You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In most of the SDKs, the method to retrieve a feature flag payload is a standalone method. This method does not raise the $feature_flag_called event, which is a source of confusion for folks. The reason it doesn't is because we expect a pattern like so:
ifis_feature_enabled('key'): # Raises eventpayload=get_feature_flag_payload('key') # Does not raise event
If get_feature_flag_payload raised the $feature_flag_called event, we'd double count here.
Problem
The problem is that get_feature_flag_payload(...) doesn't require that you call is_feature_enabled or get_feature_flag first. It can be called independently:
payload=get_feature_flag_payload('key')
Every SDK except Unity/.NET follows this problematic pattern:
Why customers complain: If they only call getFeatureFlagPayload(), they get zero analytics about feature flag usage. This is confusing because:
The name suggests it's checking a feature flag
They expect it to behave similarly to getFeatureFlag()
There's no documentation making it clear this is a "silent" method
This sadly does not lead customers into the pit of success.
Solution
For each SDK, we should deprecate/obsolete the standalone method to retrieve the payload in favor of a pattern that leads into the pit of success.
Ideal API Pattern
Strongly-typed languages (Unity/.NET style):
flag = client.getFeatureFlag("my-flag", distinctId) // raises event, returns wrapper
flag.isEnabled // boolean
flag.variant // string or null
flag.getPayload<T>() // deserializes payload, NO additional event
How it works: GetFeatureFlag() returns a PostHogFeatureFlag wrapper that contains both value and payload
Event: Raised once when GetFeatureFlag() is called
Payload: Accessed via .GetPayload<T>() on the returned object - no additional event. Also accessible via GetPayloadJson() which returns a dictionary style JSON object.
Dynamic languages:
result = client.get_feature_flag_result("my-flag", distinctId) // raises event
result.value // boolean or variant string
result.payload // the payload object
Note
This pattern exists today in posthog-python but I don't think its well known. I think we need to deprecate get_feature_flag_payload() with a message pointing people to use get_feature_flag_result.
Additional Context
Feature Flag Payload Catalog Across PostHog SDKs
SDK
getFeatureFlag() raises event?
getFeatureFlagPayload() raises event?
Combined method?
Design Pattern
Python
✅ Yes (default)
❌ No
get_feature_flag_result() returns both
Has the method you want
JS (Web)
✅ Yes (default)
❌ No
None
Separate calls
Node
✅ Yes (default)
❌ No
getAllFlagsAndPayloads() (no events, returns all flags)
Separate calls
React Native
✅ Yes (default)
❌ No
useFeatureFlagWithPayload() hook (raises event via getFeatureFlag())
Hook is good, imperative API is not
iOS
✅ Yes (if config enabled)
❌ No
None
Separate calls
Android
✅ Yes (default)
❌ No
None
Separate calls
PHP
✅ Yes (default)
❌ No
None
Separate calls
Ruby
✅ Yes (default)
❌ No
get_all_flags_and_payloads() (no events)
Separate calls
Go
✅ Yes (default)
❌ No
None
Separate calls
.NET
✅ Yes (default)
N/A - payload in FeatureFlag object
GetFeatureFlagAsync() returns both
Good pattern
Unity
✅ Yes (if config enabled)
N/A - accessed via GetPayload<T>()
GetFeatureFlag().GetPayload<T>()
Best pattern
Flutter
✅ Yes (delegates to native)
❌ No (delegates to native)
None
Separate calls
Elixir
✅ Yes (check/3 only)
N/A - no dedicated method
None
Manual extraction needed
Migration Path
SDK
Current State
Migration Path
Python
get_feature_flag_result() exists
Deprecate get_feature_flag_payload() with warning pointing to get_feature_flag_result()
JS (Web)
No combined method
Add getFeatureFlagResult(), then deprecate getFeatureFlagPayload()
Node
No single-flag combined method
Add getFeatureFlagResult(), then deprecate getFeatureFlagPayload()
React Native
Hook is good, imperative API is not
Keep useFeatureFlagWithPayload() hook. Add getFeatureFlagResult() for imperative usage. Deprecate getFeatureFlagPayload()
iOS
No combined method
Add method returning struct with value and payload, then deprecate getFeatureFlagPayload()
Android
No combined method
Add method returning object with value and payload, then deprecate getFeatureFlagPayload()
PHP
No combined method
Add get_feature_flag_result(), then deprecate get_feature_flag_payload()
Ruby
No combined method
Add get_feature_flag_result(), then deprecate get_feature_flag_payload()
Go
No combined method
Add GetFeatureFlagResult(), then deprecate GetFeatureFlagPayload()
Flutter
Delegates to native
Wait for iOS/Android fixes, then update bindings and deprecate getFeatureFlagPayload()
Elixir
No payload method exists
Add get_feature_flag_result/3 that wraps check/3 and includes payload
.NET
Already good
No changes needed
Unity
Already good
No changes needed
Debug info
- [ ] PostHog Cloud, Debug information: [please copy/paste from https://us.posthog.com/settings/project-details#variables or https://eu.posthog.com/settings/project-details#variables]
- [ ] PostHog Hobby self-hosted with `docker compose`, version/commit: [please provide]
- [ ] PostHog self-hosted with Kubernetes (deprecated, see [`Sunsetting Kubernetes support`](https://posthog.com/blog/sunsetting-helm-support-posthog)), version/commit: [please provide]
Bug Description
In most of the SDKs, the method to retrieve a feature flag payload is a standalone method. This method does not raise the
$feature_flag_calledevent, which is a source of confusion for folks. The reason it doesn't is because we expect a pattern like so:If
get_feature_flag_payloadraised the$feature_flag_calledevent, we'd double count here.Problem
The problem is that
get_feature_flag_payload(...)doesn't require that you callis_feature_enabledorget_feature_flagfirst. It can be called independently:Every SDK except Unity/.NET follows this problematic pattern:
getFeatureFlag()→ raises$feature_flag_calledeventgetFeatureFlagPayload()→ NO event raisedWhy customers complain: If they only call
getFeatureFlagPayload(), they get zero analytics about feature flag usage. This is confusing because:getFeatureFlag()This sadly does not lead customers into the pit of success.
Solution
For each SDK, we should deprecate/obsolete the standalone method to retrieve the payload in favor of a pattern that leads into the pit of success.
Ideal API Pattern
Strongly-typed languages (Unity/.NET style):
GetFeatureFlag()returns aPostHogFeatureFlagwrapper that contains both value and payloadGetFeatureFlag()is called.GetPayload<T>()on the returned object - no additional event. Also accessible viaGetPayloadJson()which returns a dictionary style JSON object.Dynamic languages:
Note
This pattern exists today in
posthog-pythonbut I don't think its well known. I think we need to deprecateget_feature_flag_payload()with a message pointing people to useget_feature_flag_result.Additional Context
Feature Flag Payload Catalog Across PostHog SDKs
getFeatureFlag()raises event?getFeatureFlagPayload()raises event?get_feature_flag_result()returns bothgetAllFlagsAndPayloads()(no events, returns all flags)useFeatureFlagWithPayload()hook (raises event viagetFeatureFlag())get_all_flags_and_payloads()(no events)FeatureFlagobjectGetFeatureFlagAsync()returns bothGetPayload<T>()GetFeatureFlag().GetPayload<T>()check/3only)Migration Path
get_feature_flag_result()existsget_feature_flag_payload()with warning pointing toget_feature_flag_result()getFeatureFlagResult(), then deprecategetFeatureFlagPayload()getFeatureFlagResult(), then deprecategetFeatureFlagPayload()useFeatureFlagWithPayload()hook. AddgetFeatureFlagResult()for imperative usage. DeprecategetFeatureFlagPayload()getFeatureFlagPayload()getFeatureFlagPayload()get_feature_flag_result(), then deprecateget_feature_flag_payload()get_feature_flag_result(), then deprecateget_feature_flag_payload()GetFeatureFlagResult(), then deprecateGetFeatureFlagPayload()getFeatureFlagPayload()get_feature_flag_result/3that wrapscheck/3and includes payloadDebug info