> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getflowpilot.io/llms.txt
> Use this file to discover all available pages before exploring further.

# User identity

> Tie FlowPilot activity to your own account IDs, attach your own attributes, and see what the SDK reports about each device.

FlowPilot gives every install a stable anonymous ID and uses it to attribute flows, experiments, and revenue. Call `identify` to connect that install to your own account ID, and `setUserAttributes` to attach anything you know that FlowPilot cannot see.

Everything here shows up on the [Users page](/dashboard/users).

## identify

```ts theme={null}
FlowPilot.identify(currentUser.id);
```

Call it after `configure(...)`, as soon as you know who the person is — typically right after sign-in or when you restore a session at launch.

From that point on, events are attributed to your ID instead of the anonymous one. The anonymous ID is kept as an **alias**, so the person's history from before they signed up stays attached to them rather than appearing as a second, unrelated user.

A flow already on screen keeps the ID it started with, so a session's funnel is never split across two identities.

## reset

```ts theme={null}
await FlowPilot.reset();
```

Call it on logout. Both the account ID and the anonymous ID are cleared and a fresh anonymous identity is minted, so the next person to sign in on a shared device does not inherit the previous account's history.

## setUserAttributes

```ts theme={null}
FlowPilot.setUserAttributes({
  plan: 'trial',
  campaign: 'spring_sale',
  signupDays: 3,
});
```

Attributes appear on the person's profile in the dashboard under **Custom attributes**.

They are **merged**, not replaced — a call that sets only `plan` leaves `campaign` alone. Pass `null` as a value to clear a key:

```ts theme={null}
FlowPilot.setUserAttributes({ campaign: null });
```

Safe to call as often as you like. The SDK fingerprints the report and drops it before it reaches the network when nothing has changed, so calling this from a render costs one request per launch, not one per frame.

This is where ad attribution belongs. FlowPilot cannot see an ad network, a referrer, or a plan tier your own backend owns — your app can, and this is the channel for it.

<Note>
  Attributes are limited to 100 keys, with each value capped at 512 characters. Nested objects are stored as JSON text. Your key names are sent exactly as you write them.
</Note>

## What the SDK reports about the device

Once per app session, the SDK sends a device report. It is sent separately from analytics events rather than attached to them, so a person's event count is not inflated by a description of their phone.

| Reported           | Examples                                                                             |
| ------------------ | ------------------------------------------------------------------------------------ |
| Platform and build | `ios` / `android`, SDK version, `expo` wrapper, app version, build number, bundle ID |
| Device             | OS version, hardware model, manufacturer, device type                                |
| Identity           | Install date                                                                         |
| Region             | Device country, locale, language, time zone and offset                               |
| Store              | Storefront currency, environment (production or sandbox)                             |
| Conditions         | Simulator, debug build                                                               |

### Optional dependencies

Only `react-native` is required. These packages each add detail to the report if your app already has them, and are skipped silently if it does not:

| Package             | Adds                                                                       |
| ------------------- | -------------------------------------------------------------------------- |
| `expo-device`       | Hardware model, OS version, manufacturer, device type, simulator detection |
| `expo-application`  | Native app version, build number, bundle ID                                |
| `expo-constants`    | App version and build from your Expo config                                |
| `expo-localization` | Locale, language, region, and currency                                     |

Without any of them, the report still carries platform, OS version, time zone, and locale — most of what the Users list displays.

### What it never collects

* **No advertising identifier.** The SDK does not read the IDFA or the Android advertising ID, and never triggers an App Tracking Transparency prompt. Adding FlowPilot cannot cause your app to ask for tracking permission.
* **No location.**
* **Nothing personal.** No contacts, no email, no name. If FlowPilot knows who someone is, it is because you called `identify`.

### Absent, not guessed

Anything the SDK cannot read is left out of the report entirely. It is never sent as an empty string or `"unknown"`, and an absent value never overwrites a value the server already had — so a report from a build without `expo-device` cannot blank the model recorded by a build that had it.

## When reports are sent

| Moment                   | What happens                                                                         |
| ------------------------ | ------------------------------------------------------------------------------------ |
| `configure(...)`         | One report, in the background. Nothing on your launch path waits for it.             |
| `identify(...)`          | An immediate report, so the alias link is written at the moment the person signs up. |
| `setUserAttributes(...)` | A report, unless nothing has changed since the last one.                             |

Every report is fire-and-forget. A failed one is dropped silently and retried on the next launch; it never surfaces an error, blocks a flow, or affects analytics ingestion.
