Repository navigation
fix(surveys): don't restart the popup delay on repeat trigger events - #849
Conversation
Android marked a survey active only once it was shown, so a repeat trigger event during surveyPopupDelaySeconds re-rendered it and the delegate restarted its delay. Reserve the survey before rendering, as iOS and the browser do, and release it when it is shown, closed, skipped or reset. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The integration now holds a survey until the delegate reports it shown or closed, so a delegate that drops one silently would block every later survey. The Compose host now reports a failed present as a close, and the delegate KDoc documents the contract. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
A delegate that drops a survey without calling onSurveyClosed now blocks later surveys, so call it out for custom delegates. Closing is enough to release the survey; it doesn't need to be shown first. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
posthog-android Compliance ReportDate: 2026-10-08 16:01:49 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
|
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
dustinbyrne
left a comment
There was a problem hiding this comment.
One startup compatibility edge: the SDK can attempt an eligible cached survey during setup, before Flutter’s navigation context exists. Flutter 5.50.12 drops that request without a callback, so the new native reservation can block later surveys even after the UI is ready.
Flutter 5.50.13 already fixes this, but applications retaining 5.50.12 can still resolve the newer Android SDK. Worth making the Flutter upgrade requirement explicit.
AI-assisted review.
…angeset Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Good call. Added a note to the changeset that Flutter apps need posthog_flutter 5.50.13 or later (PostHog/posthog-flutter#631), so it lands in the CHANGELOG. |
dustinbyrne
left a comment
There was a problem hiding this comment.
to expand on my earlier comment, the finding was that if remote config returns an eligible survey before runApp is called, this will prevent surveys from displaying in older versions of posthog-flutter (v5.50.12 and below, so pretty recent).
i'd assume this is relatively unlikely, given you'd need to defer runApp longer than it takes for the remote config round trip, however worth raising nonetheless because this version of posthog-android will be resolvable by older versions of posthog-flutter. i'd reproduced it locally by adding a timeout between Posthog().setup() and runApp(). it didn't occur without the added delay.
i didn't expect to submit this as a pure documentation recommendation originally (sorry for the confusion). given this seems unlikely to occur in practice, i’m comfortable approving with that compatibility caveat 👍👍
💡 Motivation and Context
With
surveyPopupDelaySecondsset, a repeat trigger event during the delay restarts it on Android. Events that keep firing faster than the delay can keep the survey from showing at all.Android marked a survey active only once it was shown. While the delay ran nothing was active, so each matching event re-rendered the survey and the delegate (the Compose host, or Flutter in PostHog/posthog-flutter#627) restarted its timer.
iOS and the browser already reserve the survey before the delay starts, so repeat events are ignored and the delay runs from the first trigger. This brings Android in line.
Changes
pendingPresentation) just before callingrenderSurvey.canShowNextSurvey()returns false while one is pending.survey dismissed.Because the integration now waits to hear back, a delegate that drops a survey silently would block every later one until reset or restart (iOS works the same way). So:
PostHogSurveysDelegate.renderSurveyKDoc now says a delegate that can't show a survey must callonSurveyClosed. Closing before shown doesn't mark the survey seen.Flutter compatibility: posthog_flutter declares
posthog-android:[3.71.0,4.0.0), so existing apps pick this up without a plugin update. Up to 5.50.12, Flutter drops a survey that arrives beforePosthogObserverhas a context and never reports back, so on Android surveys stop until restart. iOS already behaves this way. posthog_flutter 5.50.13 (PostHog/posthog-flutter#631) waits for a context instead.💚 How did you test it?
stale shown callback does not clean up a newer survey: it relied on a second survey replacing a pending one. It now closes the stale survey first and still checks that its late shown callback doesn't affect the newer one.spotlessCheckpasses, and theposthog-android(751) andposthog-android-surveys-compose(49) unit tests pass.surveyPopupDelaySeconds: 3, and trigger events at 0, 1.2 and 2.4 s. Withmainthe survey showed at 5.57 s (3 s after the last event). With this branch it showed at 3.24 s (3 s after the first). Both runs sent exactly onesurvey shown.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Claude Code (Opus 5.5). This came out of a review comment on PostHog/posthog-flutter#627. We compared repeat-event handling across platforms: iOS sets
activeSurveybeforerenderSurvey, and the browser sets_surveyInFocusbefore the delay and keeps the first activation timestamp. The fix matches that here rather than adding first-deadline logic to every delegate.🤖 Generated with Claude Code