OpenFeature (JavaScript)
Contents
PostHog provides official OpenFeature providers for JavaScript, so you can evaluate PostHog feature flags through the standard OpenFeature API. There are two packages, matching OpenFeature's split between the server and web (client) SDKs:
@posthog/openfeature-node-provider– for server/Node.js apps, backed byposthog-nodeand the OpenFeature server SDK.@posthog/openfeature-web-provider– for browser apps, backed byposthog-jsand the OpenFeature web SDK.
Server (Node.js)
Installation
Usage
The server model is asynchronous and multi-user: the distinct ID arrives per evaluation from the context's targetingKey, and resolution returns a promise. Construct and configure a PostHog client, register the provider, then evaluate flags:
You own the PostHog client lifecycle — call posthog.shutdown() when your app exits.
Options
new PostHogServerProvider(client, options?)
defaultDistinctId— distinct ID used when the context has notargetingKey. Defaults to unset, in which case an evaluation without atargetingKeyreturns your default value witherror_code = TARGETING_KEY_MISSING.sendFeatureFlagEvents— whether to emit$feature_flag_calledevents on each evaluation. Defaults totrue.
Browser (web)
Installation
Usage
The browser model is single-user and synchronous: posthog-js owns the user identity and keeps flags in memory, so evaluation is synchronous. The provider reconciles the static evaluation context into the SDK whenever it changes (the OpenFeature onContextChange contract), then reloads flags.
Manage the user identity through posthog-js as usual (posthog.identify(...)). The web provider never calls identify(), so targetingKey is not used to switch users.
Options
new PostHogWebProvider(client, options?)
sendFeatureFlagEvents— whether to emit$feature_flag_calledevents on each evaluation. Defaults totrue.reloadTimeoutMs— the maximum timeinitialize/onContextChangewaits forposthog-jsto (re)load flags before becoming ready anyway, so the OpenFeature client can't get stuck inNOT_READYif the SDK never delivers its flags callback. Defaults to5000.
Evaluation context
The OpenFeature evaluation context maps to PostHog's flag evaluation inputs.
For the server provider:
| OpenFeature context | PostHog |
|---|---|
targetingKey | distinctId (required unless defaultDistinctId is set) |
groups attribute | groups |
groupProperties attribute | group properties |
| any other attribute | person properties |
For the web provider, posthog-js owns the user identity, so there is no targetingKey mapping:
| OpenFeature context | PostHog |
|---|---|
groups attribute | posthog.group(type, key) |
groupProperties attribute | posthog.group(type, key, properties) |
| any other attribute | posthog.setPersonPropertiesForFlags(...) |
Supported flag types
Both providers resolve flag types through PostHog's getFeatureFlagResult:
| OpenFeature method | Resolves to |
|---|---|
getBooleanValue | whether the flag is enabled |
getStringValue | the multivariate variant key |
getNumberValue | the variant parsed as a number |
getObjectValue | the flag's JSON payload |
A non-existent flag returns your default value with error_code = FLAG_NOT_FOUND. Calling a typed getter on an incompatible flag (for example getStringValue on a boolean flag) returns your default value with error_code = TYPE_MISMATCH, per the OpenFeature spec.