Skip to content

fix(replay): gate event-trigger starts behind the replay checks - #758

Open
posthog[bot] wants to merge 3 commits into
mainfrom
posthog-self-driving/fixreplay-gate-android-event-trigger-3831bf
Open

fix(replay): gate event-trigger starts behind the replay checks#758
posthog[bot] wants to merge 3 commits into
mainfrom
posthog-self-driving/fixreplay-gate-android-event-trigger-3831bf

Conversation

@posthog

@posthog posthog Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

💡 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

  • Record event-trigger activation before evaluating the remaining replay gates, so another gate can open later in the same session without requiring the event again.
  • Keep explicit start intent separate from automatic recording transitions.
  • Preserve an explicit manual start while it waits for an event trigger.
  • Let stopSessionReplay() cancel that pending request even while replay is inactive.
  • Re-check replay permission before a queued remote-config resume runs.

No public API or generated API surface changes are required.

💚 How did you test it?

Ran locally on JDK 17:

  • Focused PostHogTest and PostHogReplayIntegrationTest suites
  • make test
  • make checkFormat
  • ./gradlew apiCheck
  • git diff --check

Coverage 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

  • 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

@dustinbyrne dustinbyrne self-assigned this Sep 4, 2026
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
@dustinbyrne
dustinbyrne force-pushed the posthog-self-driving/fixreplay-gate-android-event-trigger-3831bf branch from 2be3a21 to 1ba2a1f Compare September 4, 2026 16:23
@dustinbyrne
dustinbyrne changed the base branch from posthog-self-driving/fixreplay-stop-android-replay-when-its-fea916 to main September 4, 2026 16:24
@dustinbyrne
dustinbyrne force-pushed the posthog-self-driving/fixreplay-gate-android-event-trigger-3831bf branch from 1ba2a1f to 3ad26f1 Compare September 4, 2026 16:27
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

posthog-android Compliance Report

Date: 2026-09-07 03:27:09 UTC
Duration: 118236ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 373ms
Format Validation.Event Has Uuid 30ms
Format Validation.Event Has Lib Properties 24ms
Format Validation.Distinct Id Is String 21ms
Format Validation.Token Is Present 20ms
Format Validation.Custom Properties Preserved 23ms
Format Validation.Event Has Timestamp 20ms
Retry Behavior.Retries On 503 7026ms
Retry Behavior.Does Not Retry On 400 4026ms
Retry Behavior.Does Not Retry On 401 4022ms
Retry Behavior.Respects Retry After Header 7025ms
Retry Behavior.Implements Backoff 17022ms
Retry Behavior.Retries On 500 7019ms
Retry Behavior.Retries On 502 7020ms
Retry Behavior.Retries On 504 7018ms
Retry Behavior.Max Retries Respected 17034ms
Deduplication.Generates Unique Uuids 38ms
Deduplication.Preserves Uuid On Retry 7014ms
Deduplication.Preserves Uuid And Timestamp On Retry 12024ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7016ms
Deduplication.No Duplicate Events In Batch 35ms
Deduplication.Different Events Have Different Uuids 20ms
Compression.Sends Gzip When Enabled 17ms
Batch Format.Uses Proper Batch Structure 17ms
Batch Format.Flush With No Events Sends Nothing 9ms
Batch Format.Multiple Events Batched Together 28ms
Error Handling.Does Not Retry On 403 4017ms
Error Handling.Does Not Retry On 413 4019ms
Error Handling.Retries On 408 5028ms

Feature_Flags Tests

17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 32ms
Request Payload.Flags Request Uses V2 Query Param 18ms
Request Payload.Flags Request Hits Flags Path Not Decide 21ms
Request Payload.Flags Request Omits Authorization Header 23ms
Request Payload.Token In Flags Body Matches Init 36ms
Request Payload.Groups Round Trip 21ms
Request Payload.Groups Default To Empty Object 23ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 18ms
Request Payload.Disable Geoip Omitted Defaults To False 19ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 19ms
Request Lifecycle.No Flags Request On Init Alone 7ms
Request Lifecycle.No Flags Request On Normal Capture 16ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 34ms
Request Lifecycle.Mock Response Value Is Returned To Caller 18ms
Retry Behavior.Retries Flags On 502 321ms
Retry Behavior.Retries Flags On 504 321ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 22ms

@dustinbyrne
dustinbyrne marked this pull request as ready for review September 4, 2026 17:17
@dustinbyrne
dustinbyrne requested a review from a team as a code owner September 4, 2026 17:17
@dustinbyrne

Copy link
Copy Markdown
Contributor

Android device smoke test

Tested head 3ad26f1b with the sample app on an Android 16 / API 36 emulator. A controlled local PostHog server exercised the SDK's real /config, /flags, /batch, and /s/ network paths and recorded whether replay payloads were emitted.

All scenarios passed:

  • replay without ingestion controls still starts automatically and emits /s/ payloads
  • a non-matching event does not start replay
  • a matching event starts replay when the local switch, project setting, linked flag, and sampling gates pass
  • linked flag false, sample rate 0.0, project disablement, and local disablement each prevent replay payloads
  • trigger activation resets after session rotation
  • manual start with the local automatic switch off remains inactive before the trigger and after a non-matching event, then starts and emits replay only after the configured event matches
  • stopping while that manual start is pending cancels it; a later matching event remains inactive and emits no replay

As a sensitivity check, the same runtime probe against merge base 0d7f5670 reproduced the original defect: with the linked flag false, a matching event activated replay and emitted /s/ payloads. The PR head correctly blocks that path.

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
marandaneto requested review from a team, TueHaulund, arnohillen, fasyy612 and ksvat and removed request for a team September 5, 2026 14:39

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated advisory code review. One reproduced event-trigger gating regression.

@marandaneto
marandaneto requested a review from a team September 5, 2026 14:52
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.

2 participants