Server-side local evaluation

Last updated:

|Edit this page

Note: Local evaluation is only available in the Node, Ruby, Go, Python, and PHP SDKs.

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.

Evaluating feature flags requires making a request to PostHog for each flag. However, you can improve performance by evaluating flags locally. Instead of making a request for each flag, PostHog will periodically request and store feature flag definitions locally, enabling you to evaluate flags without making additional requests.

It is best practice to use local evaluation flags when possible, since this enables you to resolve flags faster and with fewer API calls.

There are 3 steps to enable local evaluation:

Step 1: Obtain a personal API key

Personal API keys can enable full access to your account, like logging in with your email and password. You can create multiple, give them different scopes, and each can be invalidated individually. This improves the security of your PostHog account. Personal API keys need to be kept private and shouldn't be used in the frontend.

How to obtain a personal API key

  1. Go to the Personal API keys section in your account settings

  2. Click + Create a personal API Key.

  3. Give your key a label - this is just for you, usually to describe the key's purpose.

  4. Choose the scopes for your key. We recommended selecting only the scopes required for the API endpoints you really need. This is a security best practice. You can always modify the scopes later if you need to.

  5. At the top of the list, you should see your brand new key. Immediately copy its value, as you'll never see it again after refreshing the page.

You can create as many keys as you like.

How to create an api key

Step 2: Initialize PostHog with your personal API key

When you initialize PostHog with your personal API key, PostHog will use your the key to automatically fetch feature flag definitions. These definitions are then used to evaluate feature flags locally.

By default, PostHog fetches these definitions every 30 seconds (or 5 minutes in the Go SDK). However, you can change this frequency by specifying a different value in the polling interval argument.

Note: For billing purposes, we count the request to fetch the feature flag definitions as being equivalent to 10 decide requests.

This is because one of these requests can compute feature flags for hundreds or thousands of users. It ensures local evaluation is priced fairly while remaining the most cost-effective option (by far!).

const client = new PostHog(
'<ph_project_api_key>',
{
host: 'https://us.i.posthog.com',
personalApiKey: 'your personal API key from step 1',
featureFlagsPollingInterval: 30000 // Optional. Measured in milliseconds. Defaults to 30000 (30 seconds)
}
)

Step 3: Evaluate your feature flag

To evaluate the feature flag, call any of the flag related methods, like getFeatureFlag or getAllFlags, as you normally would. The only difference is that you must provide any person properties, groups or group properties used to evaluate the release conditions of the flag.

Then, by default, PostHog attempts to evaluate the flag locally using definitions it loads on initialization and at the poll interval. If this fails, PostHog then makes a server request fetch the flag value.

You can disable this behavior by setting onlyEvaluateLocally to true. In this case, PostHog will only attempt to evaluate the flag locally, and return undefined / None / nil if it was unable to.

await client.getFeatureFlag(
'flag-key',
'distinct_id_of_the_user',
{
// include any person properties, groups, or group properties required to evaluate the flag
personProperties: {
'property_name': 'value'
},
groups: {
"your_group_type": "your_group_id",
"another_group_type": "your_group_id",
},
groupProperties: {
'your_group_type': {
'group_property_name': 'value'
},
'another_group_type': {
'group_property_name': 'value'
}
},
onlyEvaluateLocally: false, // Optional. Defaults to false. Set to true if you don't want PostHog to make a server request if it can't evaluate locally
}
)

Reloading flags

As mentioned in step 2, PostHog periodically fetches feature flag definitions. However, you can also force a reload by calling reloadFeatureFlags():

await client.reloadFeatureFlags()

Restriction on local evaluation

General restrictions

Local evaluation is not possible for flags that:

  1. Have experience continuity enabled, which is set when you check 'persist flag across authentication steps' on your feature flag.
  2. Are linked to an early access feature
  3. Depend on static cohorts

Dynamic cohort restrictions

Note: This restriction does not apply to our Go SDK, v2.6.0 and above of our Node SDK, and to v2.4.0 and above of our Python SDK.

To enable local evaluation of feature flags that depend on dynamic cohorts, we translate the cohort definition into person properties.

However, there are a few constraints, and cohorts cannot be evaluated locally if:

  1. There is a variant override on the condition with the cohort.
  2. They have non-person properties.
  3. There's more than one cohort in the feature flag definition.
  4. The cohort in the feature flag is in the same group as another condition.
  5. The cohort has nested AND-OR filters. Only simple cohorts that have a top level OR group, and inner level ANDs will be evaluated locally.

Questions?

  • Gott
    a month ago

    Webhooks for subscribing to changes in FF

    Is there a plan to provide a webhook for feature flags activities? That way, we can get the latest feature flag changes quickly without having to poll too frequently.

  • Daniel
    3 months ago

    Should we use local evaluation with Vercel fluid compute?

    A: It is best practice to use local evaluation flags when possible, since this enables you to resolve flags faster and with fewer API calls.
    B: 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.

    Vercel has introduced "fluid" compute which blurs the line between serverless/lambda and a server environment and I'm having trouble trying to determine whether local evaluation is recommended or discouraged based on this documentation.

    Like a server, if you have traffic that's consistent but low enough for one instance to handle it Vercel's fluid compute may handle multiple requests over an indefinite period using the same process.
    Like serverless, if you have single requests with long idle periods in between, Vercel's fluid compute may start up a compute instance to handle each single request meaning a feature flag data request for a single request.
    Like serverless, if you have a simultaneous large burst of traffic Vercel's fluid compute may spin up multiple compute instances that only handle a request or two and then disappear.

    The local evaluation optimization appears to be fetching of serializable feature flag data from PostHog servers once then using that data for all requests in a 30s period after it's fetched. I think the proper way of handling that is with the Vercel Data Cache, i.e. fetching the flag data from PostHog such that in the 30s after that the data is retrieved from the Data Cache instead which is much closer than PostHog's servers. In that case if you had a burst of traffic within a 30s period handled by multiple instances the first one would fetch from PostHog's servers and every subsequent instance would quickly grab it from the Data Cache instead.

    • Emiliano
      a month ago

      Were you able to have an answer on this one? I I'm also running on Vercel fluid compute and I'd like to know.

      I can't really use client-side feature flags at the moment because a lot of users run ad/tracking blockers which break the experience. I wish one could set a proxy JUST for flags (I don't want session recording data to go through Vercel...)

    • Daniel
      Authora month ago

      No, I still don't know.

  • Bartosz
    6 months ago

    Multiple cohorts for ruby SDK

    Hey, when there will be possibility to use multiple cohorts for ruby SDK? I see that this restriction is not present for Golang and Python already.

    • Steven(he/him)
      6 months ago

      Hey Bart,

      Thanks for getting in touch about this.

      The bad news is that we don't have a timeline for that at the moment. The good news is that we can maybe work on it in the future if you create a GitHub issue which explains it in full detail. Once we have that, we can pester our engineers on your behalf and let you know when it launches!

      We can't promise that we'll build every feature request, as we have a lot on our roadmap, but we'll certainly give it serious thought!

  • Panot
    a year ago

    You also need Personal API key when setting up a client in Python

    You also need Personal API key when setting up a client in Python The example in step 2 for Python doesn't include the Personal API key even though it's needed.

    • Neil
      a year ago

      Good catch, thanks Panot, will fix :)

  • Elizabeth
    a year ago

    is there a way to programmatically generate an API key?

    i would like to be able to connect my tool with posthog data without having each user go to the console to generate an API key. is there way for my tool to programmatically generate the person's API key?

    • Juraj
      a year ago

      Hey Elizabeth,

      By console you mean the PostHog dashboard? Yes indeed, that's currently the only way to retrieve the key. We have an endpoint for generating the key, but for security reasons it's not public, and can only be called from the dashboard.

      We haven't received many requests for authenticating PostHog for 3rd party apps, so this is not on the immediate roadmap. This may change in the future though!

      Cheers, Juraj

  • Rob
    2 years ago

    reloadFeatureFlags() for python

    Is there a specific reason this isn't available for python, or perhaps that's still a to-do for that SDK?

    • Juraj
      2 years agoSolution

      Hey Rob,

      The reloadFeatureFlags() method is a part of the JavaScript Web SDK. Its purpose is to clear the cached feature flags from the browser's localStorage; this is not applicable in the context of the server-side Python library.

      Cheers, Juraj

Was this page useful?

Next article

Client-side bootstrapping

Note: Bootstrapping feature flags is only available in our JavaScript web and React Native SDKs. To bootstrap PostHog with feature flags, use the bootstrap key in the initialization config and add feature flag values to it: 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: When receiving a…

Read next article

PostHog.com doesn't use third party cookies - only a single in-house cookie.

No data is sent to a third party.

Ursula von der Leyen, President of the European Commission