fix(replay): gate event-trigger starts behind the replay checks - #758
fix(replay): gate event-trigger starts behind the replay checks#758posthog[bot] wants to merge 2 commits into
Conversation
A matching event trigger called start() directly, so it skipped the master switch, the project flag and the sampling decision that every other start path applies. An app that gates replay behind its own feature flag kept recording the users the flag excludes. start() then set startedWithAutomaticDisabled, so the recording counted as manually started and survived every later check. onEvent now reuses isRecordingPermittedForCurrentSession() before it starts, after it records the trigger activation, so the trigger only lifts the event-trigger gate. start() remembers an explicit start asked for while automatic replay is off. The trigger gate defers that start, so without this the manual intent is lost and the deferred recording is refused once the trigger matches. Generated-By: PostHog Desktop Task-Id: d4a23d7a-bccc-4e65-9061-9223a7937811
2be3a21 to
1ba2a1f
Compare
1ba2a1f to
3ad26f1
Compare
posthog-android Compliance ReportDate: 2026-09-04 16:34:17 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
|
Android device smoke testTested head All scenarios passed:
As a sensitivity check, the same runtime probe against merge base No crashes or ANRs occurred. This was a debug-build emulator smoke test against controlled server responses; it did not modify or depend on a PostHog Cloud project's configuration. |
marandaneto
left a comment
There was a problem hiding this comment.
Automated advisory code review. One reproduced event-trigger gating regression.
| if (isSessionReplayActive) stopRecording() | ||
| start(resumeCurrent = false) | ||
| // Do not call start(): session rotation is an automatic transition. | ||
| startRecording(resumeCurrent = false) |
There was a problem hiding this comment.
blocking: Recheck event triggers before queued rotation starts — If remote config introduces event triggers after onSessionIdChanged() queues its main-thread task but before that task executes, calling startRecording(false) bypasses those triggers and starts recording without a matching event. Previously, start(false) rechecked shouldWaitForEventTriggers() at execution time. Preserve that check when separating automatic transitions from manual starts. Reproduction: reproduced — ./gradlew :posthog-android:testDebugUnitTest --tests "com.posthog.android.replay.PostHogReplayIntegrationTest.queued session rotation respects newly loaded event triggers" fails on the reviewed head because replay becomes active without the required event; temporarily restoring the transition-time event-gate check makes it pass.
💡 Motivation and Context
Android's session replay event-trigger path called the recording transition directly. A matching event could therefore start replay even when the local replay switch was off, the project or linked feature flag rejected the session, or sampling excluded it. That automatic start was then classified as manual and could survive later gate checks.
This change makes event triggers satisfy only the event gate. Every other applicable replay gate must also pass before automatic recording starts.
Related report: session replay event trigger bypass
What changed
stopSessionReplay()cancel that pending request even while replay is inactive.No public API or generated API surface changes are required.
💚 How did you test it?
Ran locally on JDK 17:
PostHogTestandPostHogReplayIntegrationTestsuitesmake testmake checkFormat./gradlew apiCheckgit diff --checkCoverage includes the linked-flag/event 2×2 matrix, local enablement, sampling rejection, retained trigger activation, session rotation, deferred manual starts, explicit cancellation while inactive, and automatic/manual provenance under a configuration race.
A fresh SDK code review of the final diff found no blocking, important, or minor issues.
📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file