Client-side bootstrapping

Last updated:

|Edit this page

Note: Bootstrapping feature flags is only available in our JavaScript web and React Native SDKs.

Since there is a delay between initializing PostHog and fetching feature flags, feature flags are not always available immediately. This makes them unusable if you want to do something like redirecting a user to a different page based on a feature flag.

To have your feature flags available immediately, you can initialize PostHog with precomputed values until it has had a chance to fetch them. This is called bootstrapping.

To bootstrap PostHog with feature flags, use the bootstrap key in the initialization config and add feature flag values to it:

posthog.init('<ph_project_api_key>', {
api_host: 'https://us.i.posthog.com',
bootstrap: {
featureFlags: {
'flag-1': true,
'variant-flag': 'control',
'other-flag': false,
},
},
})

Setting the correct flag values

To ensure you are bootstrapping PostHog with the correct flag values, we recommend fetching the flags values from your server alongside the page load request, and then passing them to your frontend.

You can do this by:

  1. When receiving a frontend request, fetch all the feature flags for the user on the backend by calling getAllFlags().
  2. Return the frontend request with the flags values in the response.
  3. On the frontend, get the flag values from the response and add them to the bootstrap key in the PostHog initialization.

Tip: to ensure your request is as quick as possible, use local evaluation on your server.

Bootstrapping with a distinct ID

The bootstrap object has two optional arguments: distinctID and isIdentifiedID.

  • distinctID enables you to set distinct ID of the user during PostHog's initialization. This is useful when you want to ensure the distinct ID on your frontend is the same as the distinct ID that you called getAllFlags() with on your server. It is strongly recommended to include it.

Note: The only case where you don't want to include distinctID is when your user has an existing PostHog session and you have not yet called identify() at any point in time to link the anonymous session ID with their identified ID. In this case, bootstrapping distinctID will cause PostHog to drop the anonymous session ID and the two sessions will not be linked.

  • isIdentifiedID ensures that the distinctID is treated as an identified ID in the library. This is helpful as it warns you when you try to do something wrong with this ID, like calling identify again with a different ID. Set this to true if you're using a unique ID such as email or a database ID. Set this to false if you're generating a random anonymous ID.
posthog.init('<ph_project_api_key>', {
api_host: 'https://us.i.posthog.com',
bootstrap: {
distinctID: 'distinct_id_of_your_user',
isIdentifiedID: true,
featureFlags: {
'flag-1': true,
'variant-flag': 'control',
'other-flag': false,
},
},
})

Examples

Questions?

  • Dmitry
    4 months ago

    identify call breaks feature flags based on $initial_current_url

    A feature flag tied to a special keyword in $initial_current_url works correctly until the identify call. The implementation uses this._posthog.identify(id, { email }). While the request successfully reaches PostHog's servers and returns feature flag data, the URL-conditional flag disappears from the response. The flag reappears after either waiting a few seconds and making a feature flags refresh call, or refreshing the page entirely. Right now I'm compelled to skip the onFeatureFlags event that fires after identify, but that doesn't seem correct. I suspect either there's an error in my implementation or this could be a PostHog bug.

  • Nicholas
    10 months ago

    available for other SDKs, e.g. iOS?

    When will bootstrapping be available for the iOS SDK? I could really use this feature to direct users on initial app open.

    • Manoel(he/him)
      10 months ago

      Hello Nicholas,

      So far not been planned yet but we will eventually do it, I've created an issue to track the interest, happy to guide a PR if you are interested in contributing.

      As a workaround, you can always fall back to your own value as you'd be using the bootstrapping such as:

      let test = PostHogSDK.shared.getFeatureFlag("test") as? Bool ?? bootstrappValue
  • Georgii
    10 months ago

    Bootstrapping works once and then doesn't

    I did server-side flag bootstrapping as described in the tutorial. After that I bootstrap flags on client and then first time flag value is returned correctly – my page /first does redirect to another page /second in React useEffect().

    But when I am on /second page and click "to previous page" in browser (Chrome) to get back to /first, useEffect() is again called but flag value "false" is returned as if it wasn't bootstrapped.

    I expected once flag bootstrapping on client is done, the values of flags is stored in browser's memory till page reload. What can possibly go wrong here?

    • Georgii
      Author10 months ago

      It is a React NextJs application

  • Bob
    a year ago

    Local evaluation vs not for Next.js?

    I'm hoping to bootstrap flags in my app router nextjs project. I want to make it as fast as possible to get the flags and am considering seeing if this makes sense to do in the root layout to pass to the PostHog init to get flag values immediately. A couple of questions

    1. If I have a flag that's evaluating based on some UserAgent data, and I init the posthog-node client, is there any way for me to have the app router pass that up using something like nextjs's headers() function?

    2. Do identify calls work in the server and persist to the client? And similarly, if a client does posthog.identify does it persist to RSC calls in any automatic way?

    • Bob
      Authora year ago

      Oh also forgot to ask my main question... saw this

      Note: Do not use local evaluation in an edge / lambda environment, as this can slow down performance, and also raise your bill drastically. It's best to use regular flag evaluation instead.

      In this doc https://posthog.com/docs/feature-flags/local-evaluation

      But I am running in nextjs on Vercel, and am taking this as conflicting advice here. What would the extra cost be of doing the computation locally? Is it really that computationally expensive? Or does it require more data being passed to/from the posthog client meaning the data transfer rate is going to be much higher?

Was this page useful?

Next article

Early access feature management

Note: Early access management is only available in the JavaScript web SDK . Early access feature management enables your users to opt in (and out) of betas and other in-progress features. This is useful if you want to: Run a beta program without building a custom solution Provide access to features that are not yet ready for general release Allow users to control their own product experience How it works Early access features can be created and edited from the Early Access Management tab in…

Read next article