feat(flags): minimize $feature_flag_called events for non-experiment flags#627
Open
haacked wants to merge 2 commits into
Open
feat(flags): minimize $feature_flag_called events for non-experiment flags#627haacked wants to merge 2 commits into
haacked wants to merge 2 commits into
Conversation
When the v2 /flags response carries top-level minimalFlagCalledEvents: true and the evaluated flag's has_experiment metadata is false, reduce the $feature_flag_called event properties to the cross-SDK strict allowlist, stripping registered super properties, the static/dynamic context envelope, the $feature/<key> enumeration, and $active_feature_flags. Any missing signal (field absent, legacy response shape, cached state without it, has_experiment unknown) keeps the full legacy shape, and experiment-linked flags always send the full envelope. The gate is persisted alongside the cached flags so it survives app restarts. Generated-By: PostHog Code Task-Id: ffe402fd-d75c-4043-8e5d-d2fe513cac6f
Contributor
posthog-android Compliance ReportDate: 2026-07-18 04:29:31 UTC ✅ All Tests Passed!46/46 tests passed Capture Tests✅ 29/29 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
Correct a comment in PostHogStateless.kt that claimed the minimal-events allowlist lists only properties this SDK sets today. Add a test for the untested has_experiment-absent branch under the gate, and a test locking in that bootstrap-provenance properties are stripped from minimized events. Simplify the allowlist filter loop to filterKeys.
haacked
marked this pull request as ready for review
July 18, 2026 04:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
💡 Motivation and Context
$feature_flag_calledevents carry the full enriched properties (context envelope, super properties,$active_feature_flags, the$feature/<key>enumeration) on every flag call, even for flags not linked to an experiment. This PR trims those events to a strict allowlist iff the server-controlled gate is on (top-levelminimalFlagCalledEventsin the v2/flagsresponse) AND the flag'shas_experimentis exactlyfalse. Any missing signal (field absent, legacy response shape, cached state without it,has_experimentunknown) sends the full legacy shape unchanged, and experiment-linked flags always send the full envelope. Server-gated because rolling this out unconditionally could break existing insights; announcement/comms come before enablement.Implementation notes:
posthogcore module.ALL_INTERNAL_KEYS, so it cannot leak into events via registered super properties.reset()/identity change.captureStateless) after property assembly, building the minimal property set from the allowlist rather than deleting from the full set.has_experiment, so events stay full until the first fresh/flagsresponse of the session (fail-safe, bounded staleness).Part of a cross-SDK rollout; reference implementation and fuller context: PostHog/posthog-python#748
💚 How did you test it?
Ran locally:
./gradlew :posthog:test— 805 tests including the new ones: gated + no experiment → exact allowlist key set (super props, context envelope,$feature/<key>,$active_feature_flagsstripped); gated + experiment → full; ungated / field absent → full; gate + minimal shape persist across a simulated SDK restart; gate parse/persist/flip-off/clear at thePostHogRemoteConfiglevel../gradlew :posthog-server:test./gradlew spotlessCheck./gradlew :posthog:apiCheck :posthog-server:apiCheck(afterapiDump)Could not run
:posthog-android:testDebugUnitTestor Android lint in the authoring environment (no Android SDK available) — no Android-module sources changed, but CI must confirm.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset fileCreated with PostHog Code