# 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, register, people } from "@cohorly/react-native";

init({
  token: "YOUR_PROJECT_TOKEN",
  storage: AsyncStorage, // omit to fall back to in-memory storage
});

register({ app_version: "1.2.0" });
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

| Member                    | Signature                                        | Notes                                                                                                                      |
| ------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| `init`                    | `(options) => CohorlyClient`                     | All optional: `token`, `apiHost` (defaults to the hosted API), `storage`, `flushInterval`, `flushAt`, `fetch`, `disabled`. |
| `track`                   | `(event, properties?) => void`                   | Queue an event.                                                                                                            |
| `identify`                | `(distinctId) => void`                           | Switches identity synchronously, then posts `/alias` (best effort) when the previous id was anonymous.                     |
| `reset`                   | `() => void`                                     | Clears identity, super properties, and un-flushed events.                                                                  |
| `register` / `unregister` | `(props)` / `(key)`                              | Super properties merged into every event.                                                                                  |
| `people.*`                | `set / setOnce / increment / unset / deleteUser` | Queued and sent to /engage.                                                                                                |
| `flush`                   | `() => Promise<void>`                            | Manual flush.                                                                                                              |
| `getDistinctId`           | `() => string`                                   | Current distinct id.                                                                                                       |

Note the People delete method here is `people.deleteUser()` (not `delete`).
`identify()` applies the identity switch synchronously and then fires an
`/alias` post in the background: it is never awaited, and a failure is
swallowed rather than retried. That is safe because every event already
carries `$device_id` and, once identified, `$user_id`, so the server links
the anonymous and identified ids implicitly from the next `track()` call
even if the `/alias` post never lands. See
[Identity](/reference/data-model#identity). Call `reset()` on logout so a
shared device doesn't carry one person's identity into the next session.

## 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.
