React Native SDK

@cohorly/react-native is a standalone React Native client. It has no hard dependency on react-native or any storage library - it works out of the box with an in-memory store and upgrades to persistent storage when you inject one.

Install

bash
pnpm add @cohorly/react-native
# recommended, for persistence across app restarts
pnpm add @react-native-async-storage/async-storage

Initialize

Call init() once near app launch. Inject AsyncStorage so the distinct id, queued events, and super properties survive restarts.

ts
import AsyncStorage from "@react-native-async-storage/async-storage";
import { init, track, identify, people } from "@cohorly/react-native";
​
init({
token: "YOUR_PROJECT_TOKEN",
storage: AsyncStorage, // omit to fall back to in-memory storage
});
​
track("Screen Viewed", { screen: "Home" });
identify("user_123");
people.set({ plan: "pro" });

Without storage, the client uses InMemoryStorage (also exported), which works but loses the distinct id, queue, and super properties on every app restart.

API

MemberSignatureNotes
init(options) => CohorlyClientAll optional: token, apiHost (defaults to the hosted API), storage, flushInterval, flushAt, fetch, disabled, loadFeatureFlags, sendExposureEvents, flagPersistence, flagCacheTtlMs.
track(event, properties?) => voidQueue an event.
identify(distinctId) => voidSwitches identity synchronously, then posts /alias (best effort) when the previous id was anonymous.
reset() => voidClears identity, super properties, and un-flushed events.
register / unregister(props) / (key)Super properties merged into every event.
people.*set / setOnce / increment / unset / deleteUserQueued and sent to /engage.
flush() => Promise<void>Manual flush.
getDistinctId() => stringCurrent distinct id.
getFeatureFlag / isFeatureEnabled(key, fallback?)Flag reads; optional fallback for unknown/unloaded flags (never an exposure).
getFeatureFlagDetails(key, fallback?) => FlagDetailsFull result with source ("network" / "persistence" / "fallback") plus ttlMs - and persistedAt when the cache carries stored_at - when served from the cache.
getFeatureFlagPayload(key) => unknown | nullVariant payload.
reloadFeatureFlags / onFeatureFlags() => Promise<void> / (cb) => unsubRe-evaluate; subscribe to updates.

Flags are persisted per identity (cohorly:flags, scoped by distinct_id) and bounded by flagCacheTtlMs (default 86400000 ms, 24 h). flagPersistence selects the policy - "persistenceUntilNetworkSuccess" (default, still serves an expired cache up to 7 days stale), "networkFirst" (strictly within the TTL), or "networkOnly" (never touches the cache). A legacy cache without stored_at is served indefinitely until a successful reload rewrites it. See Feature flags.

Batching

Events are queued and flushed automatically every 5 seconds or once 20 events have accumulated - both configurable via flushInterval and flushAt. Queued events are persisted to storage, so nothing is lost if the app closes before a flush. You can also construct new CohorlyClient(options) directly for multiple instances or dependency injection.

PreviousNext.js
NextiOS