Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/openfeature-web-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@posthog/openfeature-web-provider': minor
---

Initial release of the official PostHog provider for the OpenFeature web SDK, backed by `posthog-js`.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ module.exports = {
'packages/mcp/**',
'packages/nextjs-config/**',
'packages/nuxt/**',
'packages/openfeature-web-provider/**',
'packages/react-native/**',
'packages/node/**',
'packages/web/**',
Expand Down
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- [ ] @posthog/next
- [ ] @posthog/nextjs-config
- [ ] @posthog/nuxt
- [ ] @posthog/openfeature-web-provider
- [ ] @posthog/rollup-plugin
- [ ] @posthog/webpack-plugin
- [ ] @posthog/types
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ jobs:
- name: '@posthog/next'
- name: '@posthog/nextjs-config'
- name: '@posthog/nuxt'
- name: '@posthog/openfeature-web-provider'
- name: '@posthog/plugin-utils'
- name: '@posthog/rollup-plugin'
- name: '@posthog/types'
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The repository contains the following SDK packages in `./packages/`:
| `nuxt/` | `@posthog/nuxt` | Nuxt framework module |
| `next/` | `@posthog/next` | Next.js framework module |
| `nextjs-config/` | `@posthog/nextjs-config` | Next.js configuration helper |
| `openfeature-web-provider/` | `@posthog/openfeature-web-provider` | OpenFeature web provider (posthog-js) |
| `plugin-utils/` | `@posthog/plugin-utils` | Shared CLI and sourcemap utilities for plugins |
| `types/` | `@posthog/types` | TypeScript type definitions for the SDK |

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ PostHog JS is a mono-repo. The changelogs are in the individual packages
- [@posthog/convex](./packages/convex/CHANGELOG.md)
- [@posthog/next](./packages/next/CHANGELOG.md)
- [@posthog/nextjs-config](./packages/nextjs-config/CHANGELOG.md)
- [@posthog/openfeature-web-provider](./packages/openfeature-web-provider/CHANGELOG.md)
- [@posthog/plugin-utils](./packages/plugin-utils/CHANGELOG.md)
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Please see the main [PostHog docs](https://posthog.com/docs).
- [@posthog/convex](./packages/convex/README.md)
- [@posthog/nextjs-config](./packages/nextjs-config/README.md)
- [@posthog/nuxt](./packages/nuxt/README.md)
- [@posthog/openfeature-web-provider](./packages/openfeature-web-provider/README.md)
- [@posthog/plugin-utils](./packages/plugin-utils/README.md)
- [@posthog/rollup-plugin](./packages/rollup-plugin/README.md)
- [@posthog/types](./packages/types/README.md)
Expand Down
6 changes: 6 additions & 0 deletions examples/example-openfeature-web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/node_modules
/dist
.DS_Store
.env
.env.local
*.log
2 changes: 2 additions & 0 deletions examples/example-openfeature-web/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Minimum age (in days) before a package version can be installed
min-release-age=7
32 changes: 32 additions & 0 deletions examples/example-openfeature-web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# example-openfeature-web

Minimal browser example of the **[`@posthog/openfeature-web-provider`](../../packages/openfeature-web-provider)** — evaluating PostHog feature flags through the standard [OpenFeature](https://openfeature.dev) web SDK, backed by `posthog-js`.

The server equivalent lives in [`example-openfeature-node`](../example-openfeature-node) (see `@posthog/openfeature-node-provider`).

## What it shows

- Initializing `posthog-js` (you own the client lifecycle and user identity).
- Registering `PostHogWebProvider` with `OpenFeature.setProviderAndWait(...)`.
- Synchronous flag evaluation via the vendor-neutral OpenFeature client
(`getBooleanValue` / `getStringValue` / `getObjectValue`).

See [`src/main.ts`](./src/main.ts).

## Run it

These examples install workspace packages as tarballs (see [`../README.md`](../README.md)).

1. From the repo root, build the tarballs:
```bash
pnpm package:watch
```
2. In this folder, install and start:
```bash
pnpm install
pnpm start
```
3. Open the printed local URL. Set `VITE_POSTHOG_KEY` / `VITE_POSTHOG_HOST` in a
`.env` file (or edit `src/main.ts`) and use real flag keys from your project.

> The lockfile is generated on first `pnpm install` per the examples tarball workflow.
14 changes: 14 additions & 0 deletions examples/example-openfeature-web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PostHog OpenFeature web provider example</title>
</head>
<body>
<h1>PostHog + OpenFeature (web)</h1>
<p>Flags evaluated through the standard OpenFeature API, backed by posthog-js:</p>
<pre id="app">Evaluating flags…</pre>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
21 changes: 21 additions & 0 deletions examples/example-openfeature-web/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "example-openfeature-web",
"version": "0.1.0",
"private": true,
"packageManager": "pnpm@10.15.0",
"type": "module",
"scripts": {
"start": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@openfeature/web-sdk": "^1.9.0",
"@posthog/openfeature-web-provider": "*",
"posthog-js": "*"
},
"devDependencies": {
"typescript": "^5.8.2",
"vite": "^6.2.0"
}
}
12 changes: 12 additions & 0 deletions examples/example-openfeature-web/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
packages:
- .

overrides:
node-forge: 1.3.2

nodeLinker: hoisted
pnpmfile: ../.pnpmfile.cjs
minimumReleaseAge: 10080

blockExoticSubdeps: true
trustPolicy: no-downgrade
44 changes: 44 additions & 0 deletions examples/example-openfeature-web/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { OpenFeature } from '@openfeature/web-sdk'
import { PostHogWebProvider } from '@posthog/openfeature-web-provider'
import posthog from 'posthog-js'

// Configure via a local .env file (VITE_POSTHOG_KEY / VITE_POSTHOG_HOST) or edit inline.
const PROJECT_API_KEY = import.meta.env.VITE_POSTHOG_KEY ?? '<ph_project_api_key>'
const API_HOST = import.meta.env.VITE_POSTHOG_HOST ?? 'https://us.i.posthog.com'

async function main(): Promise<void> {
// 1. You own the posthog-js lifecycle. Manage user identity as usual
// (posthog.identify(...)); the provider never calls identify().
posthog.init(PROJECT_API_KEY, { api_host: API_HOST })

// 2. Register the PostHog provider with OpenFeature. setProviderAndWait
// resolves once the provider's initial flag load has settled.
await OpenFeature.setProviderAndWait(new PostHogWebProvider(posthog))
const client = OpenFeature.getClient()

// 3. Evaluate flags through the vendor-neutral OpenFeature API. Web evaluation
// is synchronous. Swap these keys for real flags in your project.
const result = {
'my-boolean-flag': client.getBooleanValue('my-boolean-flag', false),
'my-multivariate-flag': client.getStringValue('my-multivariate-flag', 'control'),
'my-payload-flag': client.getObjectValue('my-payload-flag', {}),
}

render(result)

// Optional: pass extra evaluation context (person/group properties). The
// provider reconciles it into posthog-js and reloads flags before returning.
// await OpenFeature.setContext({ plan: 'enterprise', groups: { organization: 'acme' } })
}

function render(result: Record<string, unknown>): void {
const el = document.getElementById('app')
if (el) {
el.textContent = JSON.stringify(result, null, 2)
}
}

main().catch((err) => {
// eslint-disable-next-line no-console
console.error('OpenFeature example failed:', err)
})
1 change: 1 addition & 0 deletions examples/example-openfeature-web/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
16 changes: 16 additions & 0 deletions examples/example-openfeature-web/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2020",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"types": ["vite/client"]
},
"include": ["src"]
}
7 changes: 7 additions & 0 deletions packages/openfeature-web-provider/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"printWidth": 120
}
13 changes: 13 additions & 0 deletions packages/openfeature-web-provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# @posthog/openfeature-web-provider

Official [PostHog](https://posthog.com) provider for the [OpenFeature](https://openfeature.dev) **web**
SDK ([`@openfeature/web-sdk`](https://openfeature.dev/docs/reference/technologies/client/web)), backed by
[`posthog-js`](https://posthog.com/docs/libraries/js).

For the server, use [`@posthog/openfeature-node-provider`](../openfeature-node-provider).

## Documentation

Installation and usage instructions live in the PostHog docs, so they stay in one place and don't drift:

**https://posthog.com/docs/feature-flags/installation/openfeature-js**
12 changes: 12 additions & 0 deletions packages/openfeature-web-provider/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createDefaultPreset } from 'ts-jest'

const tsJestTransformCfg = createDefaultPreset().transform

/** @type {import("jest").Config} **/
export default {
testEnvironment: 'node',
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
transform: {
...tsJestTransformCfg,
},
}
74 changes: 74 additions & 0 deletions packages/openfeature-web-provider/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"name": "@posthog/openfeature-web-provider",
"version": "0.0.0",
"bugs": {
"url": "https://github.com/PostHog/posthog-js/issues"
},
"description": "Official PostHog provider for the OpenFeature web SDK (browser), backed by posthog-js",
"repository": {
"type": "git",
"url": "git+https://github.com/PostHog/posthog-js.git",
"directory": "packages/openfeature-web-provider"
},
"homepage": "https://github.com/PostHog/posthog-js/tree/main/packages/openfeature-web-provider#readme",
"author": {
"name": "PostHog",
"email": "engineering@posthog.com",
"url": "https://posthog.com"
},
"license": "MIT",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
},
"scripts": {
"clean": "rimraf dist",
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"build": "rslib build",
"dev": "rslib build --watch",
"test:unit": "jest",
"prepublishOnly": "pnpm lint && pnpm test:unit && pnpm build",
"package": "pnpm pack --out $PACKAGE_DEST/%s.tgz"
},
"engines": {
"node": "^20.20.0 || >=22.22.0"
},
"files": [
"dist/"
],
"keywords": [
"posthog",
"openfeature",
"feature-flags",
"browser",
"web"
],
"peerDependencies": {
"@openfeature/core": "^1.11.0",
"@openfeature/web-sdk": "^1.7.0",
"posthog-js": ">=1.336.0"
},
"devDependencies": {
"@openfeature/core": "^1.11.0",
"@openfeature/web-sdk": "^1.9.0",
"@posthog-tooling/tsconfig-base": "workspace:*",
"@rslib/core": "catalog:",
"@types/jest": "catalog:",
"@types/node": "^22.15.23",
"jest": "catalog:",
"posthog-js": "workspace:*",
"ts-jest": "catalog:"
}
}
18 changes: 18 additions & 0 deletions packages/openfeature-web-provider/rslib.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig } from '@rslib/core'

export default defineConfig({
lib: [
{ format: 'esm', syntax: 'es2023', dts: true, bundle: false },
{ format: 'cjs', syntax: 'es2023', dts: true, bundle: false },
],
output: {
// Web provider: targets the browser runtime.
target: 'web',
},
source: {
entry: {
index: ['src/**/*', '!src/__tests__/**/*', '!src/**/*.spec.ts'],
},
tsconfigPath: './tsconfig.build.json',
},
})
Loading
Loading