> AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt
# OpenFeature (Java)
Canonical URL: https://posthog.com/docs/feature-flags/installation/openfeature-java
> **Cloud region:** This page uses US Cloud hosts. For an EU Cloud project, use `https://eu.i.posthog.com` instead of `https://us.i.posthog.com` (ingestion host).
## On this page
- [Installation](#installation)
- [Usage](#usage)
- [Evaluation context](#evaluation-context)
- [Supported flag types](#supported-flag-types)
- [Options](#options)
PostHog provides an official [OpenFeature](https://openfeature.dev) provider for server-side JVM applications, so you can evaluate PostHog flags through the standard OpenFeature API. It is backed by the [Java SDK](https://posthog.com/docs/libraries/java.md) (`posthog-server`) and the [OpenFeature Java SDK](https://openfeature.dev/docs/reference/technologies/server/java).
- **Package:** `com.posthog:posthog-server-openfeature`
- **Provider class:** `com.posthog.server.openfeature.PostHogProvider`
The provider requires Java 11 or later, because the OpenFeature Java SDK requires it.
## Installation
Look up the latest version of [`com.posthog.posthog-server-openfeature`](https://central.sonatype.com/artifact/com.posthog/posthog-server-openfeature).
### Gradle
build.gradle
```kotlin
dependencies {
implementation 'com.posthog:posthog-server-openfeature:0.+'
}
```
### Maven
pom.xml
```xml
com.posthog
posthog-server-openfeature
LATEST
```
This adds `posthog-server` and `dev.openfeature:sdk` as dependencies.
## Usage
Create and configure a PostHog client, then register the provider with the OpenFeature SDK:
```java
import com.posthog.server.PostHog;
import com.posthog.server.PostHogConfig;
import com.posthog.server.PostHogInterface;
import com.posthog.server.openfeature.PostHogProvider;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.EvaluationContext;
import dev.openfeature.sdk.ImmutableContext;
import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Value;
import java.util.Map;
PostHogInterface posthog = PostHog.with(
PostHogConfig.builder("")
.host("https://us.i.posthog.com")
// .personalApiKey("") enables local evaluation
.build()
);
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(new PostHogProvider(posthog));
Client client = api.getClient();
EvaluationContext context = new ImmutableContext(
"user_distinct_id",
Map.of("plan", new Value("pro"))
);
boolean isEnabled = client.getBooleanValue("my-flag", false, context);
```
You own the PostHog client lifecycle. Call `posthog.close()` when your app exits. The provider's `shutdown()` does not close the client.
## Evaluation context
The OpenFeature evaluation context maps to PostHog's flag evaluation inputs:
| OpenFeature context | PostHog |
| --- | --- |
| `targetingKey` | distinct ID (required unless `defaultDistinctId` is set) |
| `groups` attribute (structure of group type to group key) | groups |
| `groupProperties` attribute (structure of group type to properties) | group properties |
| any other attribute | person properties |
The `PostHogProvider.GROUPS_KEY` and `PostHogProvider.GROUP_PROPERTIES_KEY` constants hold the reserved attribute names:
```java
import dev.openfeature.sdk.ImmutableStructure;
EvaluationContext context = new ImmutableContext("user_distinct_id", Map.of(
PostHogProvider.GROUPS_KEY, new Value(new ImmutableStructure(Map.of("company", new Value("acme"))))
));
```
If the context has no `targetingKey` and no `defaultDistinctId` is set, the provider returns your default value with `error_code = TARGETING_KEY_MISSING`.
## Supported flag types
| OpenFeature method | Resolves to |
| --- | --- |
| `getBooleanValue` | whether the flag is enabled |
| `getStringValue` | the multivariate variant key |
| `getIntegerValue` / `getLongValue` / `getDoubleValue` | the variant parsed as a number (decimal, or hexadecimal like `0x10`) |
| `getObjectValue` | the flag's JSON payload, which must be a JSON object or array |
When the flag is off, the string, number, and object methods return your default value with the `DEFAULT` reason. One exception: if the flag has a JSON object or array payload set for its `false` value, `getObjectValue` returns that payload with the `DEFAULT` reason. Check the reason, not the returned object, to tell whether the flag is enabled. 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.
The reason is `TARGETING_MATCH` when the flag is enabled and `DEFAULT` otherwise. The Java provider does not return the `DISABLED` reason or the `posthog_reason` metadata yet.
## Options
`new PostHogProvider(client, options)`
Pass options with `PostHogProviderOptions.builder()`:
```java
import com.posthog.server.openfeature.PostHogProviderOptions;
new PostHogProvider(
posthog,
PostHogProviderOptions.builder()
.defaultDistinctId("anonymous")
.build()
);
```
- `defaultDistinctId`: distinct ID used when the context has no `targetingKey`. Defaults to `null`, in which case an evaluation without a `targetingKey` returns your default value with `error_code = TARGETING_KEY_MISSING`.
Each evaluation captures a `$feature_flag_called` event. To turn these events off, set `sendFeatureFlagEvent(false)` on the `PostHogConfig`. This setting applies to the whole client.