From 95ff69f2747426d608fa7145b7de0f3124bc89d2 Mon Sep 17 00:00:00 2001 From: "Gustavo H. Strassburger" Date: Wed, 1 Jul 2026 14:28:14 -0300 Subject: [PATCH 1/2] Add OpenFeature (JavaScript) feature flags provider docs Documents the two official PostHog OpenFeature providers for JavaScript (@posthog/openfeature-node and @posthog/openfeature-web): installation, usage, evaluation-context mapping, supported flag types, and options. Companion to the posthog-js implementation PR (PostHog/posthog-js#3994), mirroring the existing OpenFeature (Python) page. Generated-By: PostHog Code Task-Id: 46a3f8c9-fbcd-460e-9457-fca583955e5a --- .../installation/openfeature-js.mdx | 117 ++++++++++++++++++ src/navs/index.js | 1 + 2 files changed, 118 insertions(+) create mode 100644 contents/docs/feature-flags/installation/openfeature-js.mdx diff --git a/contents/docs/feature-flags/installation/openfeature-js.mdx b/contents/docs/feature-flags/installation/openfeature-js.mdx new file mode 100644 index 000000000000..ae7ea63eec5b --- /dev/null +++ b/contents/docs/feature-flags/installation/openfeature-js.mdx @@ -0,0 +1,117 @@ +--- +title: OpenFeature (JavaScript) +sidebar: Docs +showTitle: true +availability: + free: full + selfServe: full + enterprise: full +--- + +PostHog provides official [OpenFeature](https://openfeature.dev) 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`** – for server/Node.js apps, backed by [`posthog-node`](/docs/libraries/node) and the [OpenFeature server SDK](https://openfeature.dev/docs/reference/technologies/server/javascript). +- **`@posthog/openfeature-web`** – for browser apps, backed by [`posthog-js`](/docs/libraries/js) and the [OpenFeature web SDK](https://openfeature.dev/docs/reference/technologies/client/web). + +## Server (Node.js) + +### Installation + +```bash +npm install @posthog/openfeature-node @openfeature/server-sdk posthog-node +``` + +### 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: + +```ts +import { OpenFeature } from '@openfeature/server-sdk' +import { PostHogServerProvider } from '@posthog/openfeature-node' +import { PostHog } from 'posthog-node' + +// personalApiKey enables local evaluation +const posthog = new PostHog('', { host: '' }) + +await OpenFeature.setProviderAndWait(new PostHogServerProvider(posthog)) +const client = OpenFeature.getClient() + +const isEnabled = await client.getBooleanValue('my-flag', false, { targetingKey: 'user_distinct_id' }) +``` + +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 no `targetingKey`. Defaults to unset, in which case an evaluation without a `targetingKey` returns your default value with `error_code = TARGETING_KEY_MISSING`. +- `sendFeatureFlagEvents` — whether to emit `$feature_flag_called` events on each evaluation. Defaults to `true`. + +## Browser (web) + +### Installation + +```bash +npm install @posthog/openfeature-web @openfeature/web-sdk posthog-js +``` + +### 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. + +```ts +import { OpenFeature } from '@openfeature/web-sdk' +import { PostHogWebProvider } from '@posthog/openfeature-web' +import posthog from 'posthog-js' + +posthog.init('', { api_host: '' }) + +await OpenFeature.setProviderAndWait(new PostHogWebProvider(posthog)) +const client = OpenFeature.getClient() + +const isEnabled = client.getBooleanValue('my-flag', false) +``` + +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_called` events on each evaluation. Defaults to `true`. +- `reloadTimeoutMs` — the maximum time `initialize`/`onContextChange` waits for `posthog-js` to (re)load flags before becoming ready anyway, so the OpenFeature client can't get stuck in `NOT_READY` if the SDK never delivers its flags callback. Defaults to `5000`. + +## 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. diff --git a/src/navs/index.js b/src/navs/index.js index f66a6e186997..20513b2b8832 100644 --- a/src/navs/index.js +++ b/src/navs/index.js @@ -4426,6 +4426,7 @@ export const docsMenu = { { name: 'PHP', url: '/docs/feature-flags/installation/php' }, { name: 'Python', url: '/docs/feature-flags/installation/python' }, { name: 'OpenFeature (Python)', url: '/docs/feature-flags/installation/openfeature' }, + { name: 'OpenFeature (JavaScript)', url: '/docs/feature-flags/installation/openfeature-js' }, { name: 'React', url: '/docs/feature-flags/installation/react' }, { name: 'React Native', url: '/docs/feature-flags/installation/react-native' }, { name: 'React Router', url: '/docs/feature-flags/installation/react-router' }, From e3e9218482a273bf630d9b2c27c06dabc97449b3 Mon Sep 17 00:00:00 2001 From: "Gustavo H. Strassburger" Date: Wed, 1 Jul 2026 15:44:16 -0300 Subject: [PATCH 2/2] Update package names to add -provider suffix Match the renamed packages: @posthog/openfeature-node-provider and @posthog/openfeature-web-provider (install commands and import snippets). Generated-By: PostHog Code Task-Id: 46a3f8c9-fbcd-460e-9457-fca583955e5a --- .../feature-flags/installation/openfeature-js.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contents/docs/feature-flags/installation/openfeature-js.mdx b/contents/docs/feature-flags/installation/openfeature-js.mdx index ae7ea63eec5b..ca03fced1e36 100644 --- a/contents/docs/feature-flags/installation/openfeature-js.mdx +++ b/contents/docs/feature-flags/installation/openfeature-js.mdx @@ -10,15 +10,15 @@ availability: PostHog provides official [OpenFeature](https://openfeature.dev) 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`** – for server/Node.js apps, backed by [`posthog-node`](/docs/libraries/node) and the [OpenFeature server SDK](https://openfeature.dev/docs/reference/technologies/server/javascript). -- **`@posthog/openfeature-web`** – for browser apps, backed by [`posthog-js`](/docs/libraries/js) and the [OpenFeature web SDK](https://openfeature.dev/docs/reference/technologies/client/web). +- **`@posthog/openfeature-node-provider`** – for server/Node.js apps, backed by [`posthog-node`](/docs/libraries/node) and the [OpenFeature server SDK](https://openfeature.dev/docs/reference/technologies/server/javascript). +- **`@posthog/openfeature-web-provider`** – for browser apps, backed by [`posthog-js`](/docs/libraries/js) and the [OpenFeature web SDK](https://openfeature.dev/docs/reference/technologies/client/web). ## Server (Node.js) ### Installation ```bash -npm install @posthog/openfeature-node @openfeature/server-sdk posthog-node +npm install @posthog/openfeature-node-provider @openfeature/server-sdk posthog-node ``` ### Usage @@ -27,7 +27,7 @@ The server model is asynchronous and multi-user: the distinct ID arrives per eva ```ts import { OpenFeature } from '@openfeature/server-sdk' -import { PostHogServerProvider } from '@posthog/openfeature-node' +import { PostHogServerProvider } from '@posthog/openfeature-node-provider' import { PostHog } from 'posthog-node' // personalApiKey enables local evaluation @@ -53,7 +53,7 @@ You own the PostHog client lifecycle — call `posthog.shutdown()` when your app ### Installation ```bash -npm install @posthog/openfeature-web @openfeature/web-sdk posthog-js +npm install @posthog/openfeature-web-provider @openfeature/web-sdk posthog-js ``` ### Usage @@ -62,7 +62,7 @@ The browser model is single-user and synchronous: `posthog-js` owns the user ide ```ts import { OpenFeature } from '@openfeature/web-sdk' -import { PostHogWebProvider } from '@posthog/openfeature-web' +import { PostHogWebProvider } from '@posthog/openfeature-web-provider' import posthog from 'posthog-js' posthog.init('', { api_host: '' })