Skip to content

chore!: pass the loaded flags to onFeatureFlags and reloadFeatureFlags - #664

Open
turnipdabeets wants to merge 7 commits into
chore/v6-adopt-posthog-android-4from
chore/v6-flags-loaded-result
Open

turnipdabeets wants to merge 7 commits into
chore/v6-adopt-posthog-android-4from
chore/v6-flags-loaded-result

Conversation

@turnipdabeets

@turnipdabeets turnipdabeets commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

This assumed we’ve pulled in Android 4.0

PostHogConfig.onFeatureFlags was a void Function() and reloadFeatureFlags() returned Future<void>, so Flutter apps couldn't tell what loaded or whether loading failed. posthog-ios 4.0 passes this to its listener and reload callback (PostHog/posthog-ios#897, #913), posthog-android 4.0 gets the same (PostHog/posthog-android#877), and posthog-js already passes it to onFeatureFlags.

Closes #231

Both now carry a new PostHogFeatureFlagsLoaded:

Field Meaning
flags keys of the enabled flags
variants enabled flag → true or the variant string; disabled flags left out
errorsLoading true when the latest load failed; the values are then the last known ones

Per platform:

Platform onFeatureFlags reloadFeatureFlags()
iOS/macOS from posthog-ios onFeatureFlags from posthog-ios reloadFeatureFlags(_:)
Android from posthog-android PostHogFeatureFlagsCallback from posthog-android reloadFeatureFlags
Web from posthog-js onFeatureFlags posthog-js 1.438.2+: awaits featureFlags.reloadFeatureFlagsAsync(), which settles after this reload's own request (not one already in flight); errorsLoading unless it loaded. Older posthog-js: the next onFeatureFlags call, with a timeout of twice feature_flag_request_timeout_ms
Windows/Linux from the Dart core awaits the Dart core's reload

fromMap stays internal (channel_serialization.dart), in line with #646.

Breaking: onFeatureFlags = () { … } becomes (loaded) { … } or (_) { … }. Callers of reloadFeatureFlags() are unaffected; custom platform interface implementations must return the new type.

Depends on #663 (posthog-android 4.0). The Android code is written against the PostHogFeatureFlagsLoaded posthog-android 4.0 adds, which is still in review, so this stays a draft until that API is final.

💚 How did you test it?

  • flutter analyze, flutter test (1258 pass), dart format, scripts/check-api-dart.sh (snapshot updated).
  • New tests: the method channel passes native flags to the callback and drops disabled ones; malformed native args give empty flags; on desktop, reloadFeatureFlags() returns the loaded flags, and after a failed request returns the last known flags with errorsLoading: true, as does onFeatureFlags. The desktop test fails when errorsLoading is hardcoded to false.
  • flutter build ios --simulator against a local posthog-ios 4.0 checkout (temporary .package(path:), reverted), and flutter build web.
  • Web (Chrome): reloadFeatureFlags awaits reloadFeatureFlagsAsync() when present and reports errorsLoading when posthog-js skips the request; the first test fails without that path.
  • Not yet built: Android, until posthog-android 4.0 exists locally.

📝 Checklist

  • All commits are signed (see Commit signing)
  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Claude Code (Claude Opus 5.5) made this as part of the feature flag parity work across the iOS, Android and Flutter majors. The field names mirror posthog-ios's PostHogFeatureFlagsLoaded. For web reloadFeatureFlags(), waiting only for the next posthog-js onFeatureFlags call could return a response from a request already in flight, and never fires when posthog-js skips the request, so newer posthog-js uses reloadFeatureFlagsAsync() and older versions keep that path behind a timeout.

🤖 Generated with Claude Code

@turnipdabeets turnipdabeets self-assigned this Oct 23, 2026

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 93f0034: 1 Should fix.

This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

Comment thread posthog_flutter/lib/src/posthog_flutter_web_handler.dart Outdated
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

posthog-flutter Compliance Report

Date: 2026-10-26 18:44:26 UTC
Duration: 96921ms

✅ All Tests Passed!

45/45 tests passed


Capture Tests

✅ 29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 145ms
Format Validation.Event Has Uuid ✅ 121ms
Format Validation.Event Has Lib Properties ✅ 118ms
Format Validation.Distinct Id Is String ✅ 116ms
Format Validation.Token Is Present ✅ 117ms
Format Validation.Custom Properties Preserved ✅ 119ms
Format Validation.Event Has Timestamp ✅ 118ms
Retry Behavior.Retries On 503 ✅ 5332ms
Retry Behavior.Does Not Retry On 400 ✅ 2120ms
Retry Behavior.Does Not Retry On 401 ✅ 2119ms
Retry Behavior.Respects Retry After Header ✅ 8124ms
Retry Behavior.Implements Backoff ✅ 15442ms
Retry Behavior.Retries On 500 ✅ 5229ms
Retry Behavior.Retries On 502 ✅ 5227ms
Retry Behavior.Retries On 504 ✅ 5226ms
Retry Behavior.Max Retries Respected ✅ 15447ms
Deduplication.Generates Unique Uuids ✅ 126ms
Deduplication.Preserves Uuid On Retry ✅ 5225ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10337ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5234ms
Deduplication.No Duplicate Events In Batch ✅ 126ms
Deduplication.Different Events Have Different Uuids ✅ 119ms
Compression.Sends Gzip When Enabled ✅ 118ms
Batch Format.Uses Proper Batch Structure ✅ 115ms
Batch Format.Flush With No Events Sends Nothing ✅ 109ms
Batch Format.Multiple Events Batched Together ✅ 125ms
Error Handling.Does Not Retry On 403 ✅ 2118ms
Error Handling.Does Not Retry On 413 ✅ 2117ms
Error Handling.Retries On 408 ✅ 5226ms

Feature_Flags Tests

✅ 16/16 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 14ms
Request Payload.Flags Request Uses V2 Query Param ✅ 11ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 12ms
Request Payload.Flags Request Omits Authorization Header ✅ 11ms
Request Payload.Token In Flags Body Matches Init ✅ 10ms
Request Payload.Groups Round Trip ✅ 12ms
Request Payload.Groups Default To Empty Object ✅ 11ms
Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It ✅ 11ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 12ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 11ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 11ms
Request Lifecycle.No Flags Request On Init Alone ✅ 4ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 115ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 19ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 11ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 119ms

@turnipdabeets
turnipdabeets marked this pull request as ready for review October 23, 2026 17:11
@turnipdabeets
turnipdabeets requested a review from a team as a code owner October 23, 2026 17:11

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 80ac673: 1 Should fix.

Comment on lines +249 to +251
return await reloaded.future.timeout(
Duration(milliseconds: 2 * (requestTimeoutMs ?? 3000)),
onTimeout: currentFlags,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Allow supported retries to finish before reporting failure

When posthog-js retries a timed-out request, two request timeouts plus its retry backoff exceed this deadline. A successful retry then arrives after Flutter has returned cached flags with errorsLoading: true, violating the completion contract required by AGENTS.md. Account for configured retries and backoff before applying the fallback.

onFeatureFlags and reloadFeatureFlags now carry a PostHogFeatureFlagsLoaded with the enabled flags, their values and whether loading failed, matching posthog-ios 4.0 and posthog-android 4.0. On web, reloadFeatureFlags completes right away with the flags loaded so far, because posthog-js doesn't report when a reload finishes.
Wait for the next posthog-js onFeatureFlags call instead of returning the flags already loaded, so a failed reload reports errorsLoading. Complete right away when flags are disabled, and after twice the flags request timeout when posthog-js skips the request without calling back.
The next onFeatureFlags callback can carry a response from a request already in flight, so reloadFeatureFlags() could complete with flags from before the reload. posthog-js 1.438.2+ settles reloadFeatureFlagsAsync() after this reload's own request; use it when present and keep the callback path for older posthog-js.
@turnipdabeets
turnipdabeets force-pushed the chore/v6-flags-loaded-result branch from de3a190 to 0a7ab2a Compare October 26, 2026 18:38

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant