PostHog.FeatureFlags (posthog v2.8.1)
View SourceConvenience functions to work with Feature Flags API
Summary
Functions
Checks feature flag
Checks feature flag and returns the variant or raises on error.
Evaluates feature flags for a distinct_id and returns a snapshot.
Make request to /flags API.
Get all feature flags.
Gets the full feature flag result including value and payload.
Gets the full feature flag result or raises on error.
Copies a snapshot's $feature/<key> and $active_feature_flags properties
into the per-process PostHog context.
Functions
@spec check( PostHog.supervisor_name(), String.t(), PostHog.distinct_id() | map() | nil ) :: {:ok, boolean()} | {:ok, String.t()} | {:error, Exception.t()}
Checks feature flag
Deprecated
Use PostHog.FeatureFlags.evaluate_flags/2 plus
PostHog.FeatureFlags.Evaluations.enabled?/2 or
PostHog.FeatureFlags.Evaluations.get_flag/2 instead. The snapshot lets
one /flags call serve multiple flag checks plus event enrichment.
If there is a variant assigned, returns {:ok, variant}. Otherwise, {:ok, true} or {:ok, false}.
Accepts an optional distinct_id or a map with request body. If neither is
passed, attempts to read distinct_id from the context.
This function will also
send
$feature_flag_called event and
set
$feature/feature-flag-name property in context.
Examples
Check boolean feature flag for distinct_id:
iex> PostHog.FeatureFlags.check("example-feature-flag-1", "user123")
{:ok, true}Check multivariant feature flag for distinct_id in the current context:
iex> PostHog.set_context(%{distinct_id: "user123"})
iex> PostHog.FeatureFlags.check("example-feature-flag-1")
{:ok, "variant1"}Check boolean feature flag through a named PostHog instance:
PostHog.check(MyPostHog, "example-feature-flag-1", "user123")
@spec check!( PostHog.supervisor_name(), String.t(), PostHog.distinct_id() | map() | nil ) :: boolean() | String.t() | no_return()
Checks feature flag and returns the variant or raises on error.
Deprecated
Use PostHog.FeatureFlags.evaluate_flags/2 and
PostHog.FeatureFlags.Evaluations.enabled?/2 /
PostHog.FeatureFlags.Evaluations.get_flag/2 instead.
This is a wrapper around check/3 that returns the variant directly
or raises an exception on error. This follows the Elixir convention where
functions ending with ! raise exceptions instead of returning error tuples.
Warning: Use this function with care as it will raise an error if the feature flag is not found or if there are any API errors. For more resilient code, use
check/3which returns{:error, reason}instead of raising.
Examples
Check feature flag and get the variant:
iex> PostHog.FeatureFlags.check!("example-feature-flag-1", "user123")
trueCheck multivariant feature flag for distinct_id in current context:
iex> PostHog.set_context(%{distinct_id: "user123"})
iex> PostHog.FeatureFlags.check!("example-feature-flag-1")
"variant1"Check feature flag through a named PostHog instance:
iex> PostHog.FeatureFlags.check!(MyPostHog, "example-feature-flag-1", "user123")
falseRaises an error when feature flag is not found:
iex> PostHog.FeatureFlags.check!("example-feature-flag-3", "user123")
** (PostHog.UnexpectedResponseError) Feature flag example-feature-flag-3 was not found in the response
@spec evaluate_flags(PostHog.supervisor_name(), PostHog.distinct_id() | map() | nil) :: {:ok, PostHog.FeatureFlags.Evaluations.t()} | {:error, Exception.t()}
Evaluates feature flags for a distinct_id and returns a snapshot.
Returns {:ok, %PostHog.FeatureFlags.Evaluations{}} on success. The snapshot
represents a single /flags call and lets you branch on multiple flags and
enrich captured events from the same fetch — see
PostHog.FeatureFlags.Evaluations for the full snapshot API and
set_in_context/2 for the recommended capture-enrichment flow.
Accepts an optional distinct_id or a request body map. If neither is
passed, attempts to read distinct_id from the context.
Body options
When passing a map, the following keys are forwarded to the /flags request
body unchanged:
:distinct_id(required, unless found in context):groups:person_properties:group_properties:disable_geoip
Plus one snapshot-specific option:
:flag_keys- list of flag keys. Forwarded to the request asflag_keys_to_evaluateso the server returns only those flags. This scopes the network response, distinct fromPostHog.FeatureFlags.Evaluations.only/2which filters an already-fetched snapshot in memory.
Examples
Evaluate flags for a distinct_id:
{:ok, snapshot} = PostHog.FeatureFlags.evaluate_flags("user123")
PostHog.FeatureFlags.Evaluations.enabled?(snapshot, "new-dashboard")Evaluate a scoped set of flags with person properties:
PostHog.FeatureFlags.evaluate_flags(%{
distinct_id: "user123",
person_properties: %{plan: "enterprise"},
flag_keys: ["new-dashboard", "beta-checkout"]
})Evaluate through a named PostHog instance:
PostHog.FeatureFlags.evaluate_flags(MyPostHog, "user123")
@spec flags(PostHog.supervisor_name(), map()) :: PostHog.API.Client.response() | {:error, PostHog.Error.t()}
Make request to /flags API.
This function is a thin wrapper over a client call and is useful as a building
block to build your own check/3. For example, this is a preferred
way to access remote config payload.
Examples
Make request to /flags API:
PostHog.FeatureFlags.flags(%{distinct_id: "user123"})Make request to /flags API with additional body params:
PostHog.FeatureFlags.flags(%{distinct_id: "my_distinct_id", groups: %{group_type: "group_id"}})Make request to /flags API through a named PostHog instance:
PostHog.FeatureFlags.flags(MyPostHog, %{distinct_id: "user123"})
@spec flags_for(PostHog.supervisor_name(), PostHog.distinct_id() | map() | nil) :: {:ok, map()} | {:error, Exception.t()}
Get all feature flags.
Accepts an optional distinct_id or a map with request body. If neither is
passed, attempts to read distinct_id from the context.
Examples
Get all feature flags:
PostHog.FeatureFlags.flags_for("user123")Get all feature flags with full request body:
PostHog.FeatureFlags.flags_for(%{distinct_id: "user123", group: %{group_type: "group_id"}})Get all feature flags for distinct_id from the context:
PostHog.set_context(%{distinct_id: "user123"})
PostHog.FeatureFlags.flags_for()Get all feature flags through a named PostHog instance:
PostHog.FeatureFlags.flags_for(MyPostHog, "foo")
@spec get_feature_flag_result( PostHog.supervisor_name(), String.t(), PostHog.distinct_id() | map() | nil, keyword() ) :: {:ok, PostHog.FeatureFlags.Result.t() | nil} | {:error, Exception.t()}
Gets the full feature flag result including value and payload.
Deprecated
Use PostHog.FeatureFlags.evaluate_flags/2 and access flags from the
returned PostHog.FeatureFlags.Evaluations snapshot. The snapshot
exposes the same metadata (id, version, reason, payload) plus filter
helpers and capture enrichment via set_in_context/2.
Returns {:ok, %PostHog.FeatureFlags.Result{}} on success, {:ok, nil} if the flag
is not found, or {:error, reason} on failure.
The PostHog.FeatureFlags.Result struct contains:
key- The flag nameenabled- Whether the flag is enabledvariant- The variant string (nil for boolean flags)payload- The JSON payload configured for the flag (nil if not set)
By default, this function will
send
a $feature_flag_called event and
set
the $feature/feature-flag-name property in context.
Options
:send_event- Whether to send the$feature_flag_calledevent. Defaults totrue.
Examples
Get feature flag result for distinct_id:
iex> PostHog.FeatureFlags.get_feature_flag_result("example-feature-flag-1", "user123")
{:ok, %PostHog.FeatureFlags.Result{key: "example-feature-flag-1", enabled: true, variant: nil, payload: nil}}Get feature flag result with payload:
iex> PostHog.FeatureFlags.get_feature_flag_result("feature-with-payload", "user123")
{:ok, %PostHog.FeatureFlags.Result{key: "feature-with-payload", enabled: true, variant: "variant1", payload: %{"key" => "value"}}}Get feature flag result without sending event:
iex> PostHog.FeatureFlags.get_feature_flag_result("my-flag", "user123", send_event: false)
{:ok, %PostHog.FeatureFlags.Result{key: "my-flag", enabled: true, variant: nil, payload: nil}}Flag not found returns {:ok, nil}:
iex> PostHog.FeatureFlags.get_feature_flag_result("non-existent-flag", "user123")
{:ok, nil}Get feature flag result for distinct_id in the current context:
iex> PostHog.set_context(%{distinct_id: "user123"})
iex> PostHog.FeatureFlags.get_feature_flag_result("example-feature-flag-1")
{:ok, %PostHog.FeatureFlags.Result{key: "example-feature-flag-1", enabled: true, variant: nil, payload: nil}}Get feature flag result through a named PostHog instance:
PostHog.FeatureFlags.get_feature_flag_result(MyPostHog, "example-feature-flag-1", "user123")
@spec get_feature_flag_result!( PostHog.supervisor_name(), String.t(), PostHog.distinct_id() | map() | nil, keyword() ) :: PostHog.FeatureFlags.Result.t() | nil | no_return()
Gets the full feature flag result or raises on error.
Deprecated
Use PostHog.FeatureFlags.evaluate_flags/2 and access flags from the
returned PostHog.FeatureFlags.Evaluations snapshot.
This is a wrapper around get_feature_flag_result/4 that returns the result
directly or raises an exception on error. This follows the Elixir convention
where functions ending with ! raise exceptions instead of returning error
tuples.
Returns nil if the flag is not found (does not raise), consistent with
other PostHog SDKs.
Warning: Use this function with care as it will raise an error if there are any API errors (e.g. missing
distinct_id). For more resilient code, useget_feature_flag_result/4which returns{:error, reason}instead of raising.
Options
:send_event- Whether to send the$feature_flag_calledevent. Defaults totrue.
Examples
Get feature flag result for distinct_id:
iex> PostHog.FeatureFlags.get_feature_flag_result!("example-feature-flag-1", "user123")
%PostHog.FeatureFlags.Result{key: "example-feature-flag-1", enabled: true, variant: nil, payload: nil}Returns nil when flag is not found:
iex> PostHog.FeatureFlags.get_feature_flag_result!("non-existent-flag", "user123")
nilRaises an error when distinct_id is missing:
iex> PostHog.FeatureFlags.get_feature_flag_result!("example-feature-flag-1")
** (PostHog.Error) distinct_id is required but wasn't explicitly provided or found in the context
@spec set_in_context(PostHog.supervisor_name(), PostHog.FeatureFlags.Evaluations.t()) :: :ok
Copies a snapshot's $feature/<key> and $active_feature_flags properties
into the per-process PostHog context.
Any subsequent PostHog.capture/3 from this process automatically attaches
these properties to the captured event — no additional /flags request,
with the values guaranteed to match what the snapshot already evaluated.
This is the idiomatic Elixir way to enrich captured events from an
evaluate_flags/2 snapshot. For one-off enrichment without touching context,
merge PostHog.FeatureFlags.Evaluations.event_properties/1 into a capture's
properties directly.
Examples
{:ok, snapshot} = PostHog.FeatureFlags.evaluate_flags("user123")
PostHog.FeatureFlags.set_in_context(snapshot)
# All subsequent captures pick up $feature/* and $active_feature_flags
PostHog.capture("page_viewed", %{distinct_id: "user123"})