Server-side local evaluation

Last updated:

|Edit this page

Note: Local evaluation is only available in the Node, Ruby, Go, Python, C#/.NET, 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: Find your feature flags secure API key

The feature flags secure API key is a secret project specific token listed in the Feature Flags tab of your project settings in the "Feature Flags Secure API Key" section. It provides the SDKs with access to the feature flag definitions for your project so they can evaluate flags locally.

This key needs to be kept secret, and should not be used in the frontend or exposed to users.

Note: Existing personal API keys will continue to work for local evaluation, but we recommend switching to the feature flags secure API key for local evaluation moving forward. We will be deprecating personal API keys for local evaluation in the future.

How to obtain a feature flags secure API key

  1. Go to the Feature Flags tab of your project settings

  2. The key should be displayed in the "Feature Flags Secure API Key" section.

  3. Copy the key and use it to initialize the PostHog client.

Step 2: Initialize PostHog with your feature flags secure API key

When you initialize PostHog with your feature flags secure API key, PostHog will use 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 feature flags secure 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": "another_group_id",
},
groupProperties: {
'your_group_type': {
'group_property_name': 'value'
},
'another_group_type': {
'group_property_name': 'another 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? Ask Max AI.

It's easier than reading through 642 pages of documentation

Community questions

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