> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userefract.io/llms.txt
> Use this file to discover all available pages before exploring further.

# PostHog Feature Flags

> Evaluate PostHog feature flags through the shared Refract feature flag contract.

**PostHog feature flags** reuse your PostHog project for boolean flags, multivariate experiments, and user targeting — normalized into Refract's `CachedFeatureFlag` shape.

<details>
  <summary>🤖 Agent context</summary>

  Config schema: `featureFlagConfigSchema` in `apps/shared/src/featureFlags/schema.ts`. Loader: `apps/backend/src/tools/featureFlags/loader.ts` wraps the PostHog provider with request + shared caching. Implementation: `apps/tools/featureFlags/posthog/src/index.ts` — bulk via `getAllFlags`, per-flag fall-through via `isFeatureEnabled` / `getFeatureFlag`.

  Production config mirrors analytics credentials in `apps/backend/src/configuration/production.ts`.

  ❌ Do not import `posthog-node` outside `apps/tools/featureFlags/posthog/`.
  ❌ Do not skip caching — the loader always wraps non-LOCAL providers.
  ❌ Do not expose flags in GraphQL without adding them to `exposedFlags`.

  Verify with: `make test module=tooling-feature-flags-posthog` and `make test module=backend path=apps/backend/src/tools/featureFlags`
</details>

## Why

If you already run PostHog for analytics, feature flags can share the same API key and ingestion host. The backend evaluates flags server-side with user and organization context attached as person properties.

## Setup

1. Add `tooling-feature-flags-posthog` to `apps/backend/package.json` (already present in the template).
2. Run `make deps-install`.
3. Configure production:

```ts theme={null}
featureFlags: {
  client: FeatureFlagClientType.POSTHOG,
  cacheMs: 30_000,
  apiKey: process.env.POSTHOG_API_KEY,
  exposedFlags: ['new-dashboard'],
  settings: {
    host: 'https://us.i.posthog.com',
  },
},
```

4. Set `POSTHOG_API_KEY` (and optional `POSTHOG_HOST`) in the deployment environment.

## Evaluation context

`FeatureFlagContext` maps to PostHog person properties:

* `userId` → distinct id (falls back to `anonymous`)
* `organizationId`, `environment`, and `attributes` → person properties

## Gotchas

* Multivariate flag values are exposed through `getVariant()` with `enabled: true`.
* Boolean `false` flags remain in the normalized cache with `enabled: false`.
* Shared cache TTL is controlled by `cacheMs`; request caching is always on for HTTP traffic.

## What's next?

* [Feature flags overview](/tooling/feature-flags/overview)
* [Local provider](/tooling/feature-flags/local)
* [LaunchDarkly provider](/tooling/feature-flags/launch-darkly)
