# Bootstrapping PostHog SDKs - Docs

Bootstrapping seeds a PostHog SDK with data your app already knows when the SDK initializes. This makes identity, session, or feature flag state available before the SDK finishes its first network request.

Bootstrapping is available in the [JavaScript web](/docs/libraries/js.md), [React Native](/docs/libraries/react-native.md), [iOS](/docs/libraries/ios.md), [Android](/docs/libraries/android.md), and [Flutter](/docs/libraries/flutter.md) SDKs.

## How bootstrapping works

Pass known state in the SDK's `bootstrap` configuration before initialization:

1.  Your app gets the state it needs, such as a signed-in user ID or server-evaluated Feature Flags.
2.  Your app passes that state to `bootstrap` when it initializes PostHog.
3.  The SDK applies the state immediately.
4.  The SDK persists or replaces each value according to its lifecycle.

| Value | Purpose | What happens next |
| --- | --- | --- |
| Distinct ID | Start the SDK with a known anonymous or identified identity | The SDK applies or reconciles the ID according to the platform's persistence rules |
| Identified state | Tell the SDK whether the distinct ID belongs to an identified person | The SDK treats the ID as anonymous or identified and merges identities when required |
| Session ID | Continue the same session across PostHog initializations | The JavaScript web SDK uses it as the active session ID |
| Feature Flags and payloads | Make server-evaluated flags available immediately | The next complete /flags response replaces the bootstrapped values |

The JavaScript web SDK uses `distinctID`, `isIdentifiedID`, and `sessionID`. React Native, iOS, Android, and Flutter use `distinctId` and `isIdentifiedId`. Only the JavaScript web SDK supports bootstrapping a session ID.

## Bootstrap an identity

Use `distinctID` and `isIdentifiedID` when your app knows the person's identity before SDK initialization. Include the same distinct ID in server-side and client-side requests so events, sessions, and feature flag evaluations belong to the same person.

Set `isIdentifiedID` to `true` for a signed-in ID, such as a database ID. A previous `$identify` event isn't required. Set it to `false`, or omit it, for an anonymous ID.

PostHog AI

### Web

```javascript
posthog.init('<ph_project_token>', {
    api_host: 'https://us.i.posthog.com',
    defaults: '2026-05-30',
    bootstrap: {
        distinctID: 'distinct_id_of_your_user',
        isIdentifiedID: true,
    },
})
```

### React Native

```jsx
<PostHogProvider
    apiKey="<ph_project_token>"
    options={{
        host: 'https://us.i.posthog.com',
        bootstrap: {
            distinctId: 'distinct_id_of_your_user',
            isIdentifiedId: true,
        },
    }}
>
    <MyApp />
</PostHogProvider>
```

### Swift

```swift
let config = PostHogConfig(projectToken: "<ph_project_token>", host: "https://us.i.posthog.com")
config.bootstrap = PostHogBootstrapConfig(
    distinctId: "distinct_id_of_your_user",
    isIdentifiedId: true
)
PostHogSDK.shared.setup(config)
```

### Kotlin

```kotlin
val config = PostHogAndroidConfig(apiKey = "<ph_project_token>", host = "https://us.i.posthog.com")
config.bootstrap = PostHogBootstrapConfig(
    distinctId = "distinct_id_of_your_user",
    isIdentifiedId = true
)
PostHogAndroid.setup(this, config)
```

### Dart

```dart
final config = PostHogConfig('<ph_project_token>');
config.host = 'https://us.i.posthog.com';
config.bootstrap = PostHogBootstrapConfig(
  distinctId: 'distinct_id_of_your_user',
  isIdentifiedId: true,
);
await Posthog().setup(config);
```

When `isIdentifiedID` is `true`, the JavaScript web, iOS, Android, and Flutter SDKs reconcile the bootstrapped ID with any persisted identity:

-   **No persisted identity** – The SDK uses the bootstrapped ID and marks it as identified without emitting `$identify`.
-   **An anonymous identity exists** – If the IDs match, the SDK marks the existing identity as identified without emitting `$identify`. If they differ, the SDK calls `identify()` to link the anonymous activity to the bootstrapped ID. This emits `$identify` when capturing is enabled. While opted out, only the local identity changes.
-   **The same identified identity exists** – The SDK keeps it without emitting a redundant `$identify`.
-   **A different identified identity exists** – The SDK preserves the existing identity and emits a warning. Call `reset()` before initialization when you intend to switch users.

The automatic merge follows your person profile settings. If person profiles are set to `never`, the SDK preserves a different anonymous identity instead of calling `identify()`.

Use bootstrap when your app knows the signed-in identity before SDK initialization. If your app loads the identity asynchronously, call [`identify()`](/docs/product-analytics/identify.md) when it becomes available instead.

## Bootstrap a session ID

Use `sessionID` with the JavaScript web SDK to continue a session across PostHog initializations. This is useful when tracking a session across domains because it preserves one session count and a connected Session Replay.

Get the current session ID by calling `posthog.get_session_id()` and pass it to the next initialization. The session ID must be a valid UUID v7, unique to the person, timestamped no later than the first event in the session, and no more than 24 hours before the last event in the session.

Web

PostHog AI

```javascript
posthog.init('<ph_project_token>', {
    api_host: 'https://us.i.posthog.com',
    defaults: '2026-05-30',
    bootstrap: {
        sessionID: 'session_id_of_user_session',
    },
})
```

See the [cross-domain tracking tutorial](/tutorials/cross-domain-tracking.md) for a complete implementation.

## Bootstrap Feature Flags

Pass server-evaluated feature flag values and payloads to `bootstrap` to make them available when the SDK initializes. The SDK uses these values until it receives fresh values from PostHog.

See [bootstrapping Feature Flags](/docs/feature-flags/bootstrapping.md) for evaluation consistency, flag lifecycle, local evaluation, and implementation examples.

## Behavior on mobile SDKs

The iOS, Android, and Flutter SDKs bootstrap through `PostHogBootstrapConfig` and persist identity and flags on the device. Assign `config.bootstrap` before calling `setup()`. Bootstrapping requires iOS SDK `3.66.0`+, Android SDK `3.55.0`+, or Flutter SDK `5.31.0`+.

> **React Native** uses a `bootstrap` option like the JavaScript web SDK instead of `PostHogBootstrapConfig`. Bootstrapped identity doesn't overwrite persisted identity. When both bootstrapped and persisted flags exist, persisted values take precedence.

-   **Bootstrapped identity applies during setup.** On a fresh install, setting it before `setup()` means events captured synchronously during initialization (like `Application Installed`) carry your distinct ID instead of the SDK-generated UUID.
    -   An **anonymous** bootstrap (`isIdentifiedId: false`, the default) seeds the anonymous ID only when none is persisted yet. Once an anonymous ID exists on disk, or the person has been identified, the SDK ignores it.
    -   An **identified** bootstrap (`isIdentifiedId: true`) is for a signed-in identity available to your app (for example, from a backend session token). On a fresh install, it seeds the distinct ID, marks the person identified, and generates a separate device ID. On a returning install, a matching anonymous ID is marked identified without emitting `$identify`; a different anonymous ID is merged via `identify()` when person profiles are enabled. This emits `$identify` unless capturing is opted out. A different, already-identified person is left untouched.
-   **Bootstrapped flags are served until the first `/flags` response, then replaced.** A complete `/flags` response takes over entirely, so bootstrapped-only keys don't persist past it. Only *enabled* flags are seeded: a `true` boolean or a non-empty variant string. A `false` or empty value is dropped, matching posthog-js. Seed payloads with the separate `featureFlagPayloads` option. Flag values and payloads must be JSON-serializable, or they're dropped. Bootstrapped flags are cleared on `reset()`.

The feature-flags-loaded signal fires as soon as bootstrapped flags are applied, so startup logic can read them immediately. These SDKs don't support the `sessionID` bootstrap option. When person profiles are set to `never`, the SDK preserves a different anonymous identity instead of merging it into an identified bootstrap.

> **Flutter web:** `bootstrap` isn't applied on Flutter web because the web SDK hooks onto an already initialized `posthog-js` instance. Configure `bootstrap` in your `posthog.init({...})` call instead.

### Community questions

Ask a question

### Was this page useful?

HelpfulCould be better