Skip to content

docs(opt-in): restart session replay in a new session on opt-in - #138

Open
posthog[bot] wants to merge 5 commits into
mainfrom
posthog/opt-in-replay-new-session
Open

posthog[bot] wants to merge 5 commits into
mainfrom
posthog/opt-in-replay-new-session

Conversation

@posthog

@posthog posthog Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Why

Four client SDKs converged on what optIn() does to session replay, and the opt-in spec recorded none of it — it said only that "some SDKs stop or restart them when opt state changes". Both the iOS and React Native PRs noted the gap explicitly while making the change. Without a requirement, a new SDK or a port can keep recording into the opted-out session after consent, drop a replay the app wanted, or silently undo an app's stopSessionRecording() call.

Source changes:

  • posthog-android #839 — opt-out uninstalls integrations, opt-in restarts the replay the app wanted in a new session
  • posthog-ios #942, then #959 — rotates the session in optIn(); #959 moved from "was recording" to "was wanted"
  • posthog-js (React Native) #5336, then #5363 — #5363 adopted the same one-flag "wanted" rule
  • posthog-flutter #606 — stops replay on opt-out and restarts it on opt-in

What changed

Two requirements added to openspec/specs/opt-in/spec.md, with the change archived under openspec/changes/archive/2026-10-22-restart-replay-on-opt-in/:

  • Opt-in restarts session replay in a new session. After opt-in restarts replay, the current session id differs from the one in use at opt-out. Where a wrapper owns the session id, the wrapper rotates. When the app wanted replay, the new session starts even if a linked flag or remote config that hasn't loaded keeps replay from starting, so a later start can't resume the opted-out session.
  • Opt-in restarts the session replay the app wanted at opt-out. "Wanted" means enabled in config or started with startSessionRecording(), and not stopped since. Replay held off at opt-out by sampling, a linked flag or an event trigger restarts in the new session, where those gates are evaluated again. A recording the app stopped stays stopped; start/stop calls while opted out don't count. The decision is seeded from config at launch, so an app that launches opted out with replay enabled records on first opt-in; no SDK's reset() changes it.

Scenarios cover: recording → opt-out → opt-in, a linked flag holding replay off at opt-in, a manual start with replay off in config, a trigger-held replay, a stop before opt-out, a stop while opted out, and launching opted out.

SDK alignment

Verified against main of each SDK on 2026-10-29, and on device (iOS simulator, Android emulator, against a local mock server). Everything above matches all four SDKs except:

  • New session when a gate holds replay off. posthog-ios and posthog-react-native already do this. posthog-android rotated only once the linked flag and remote config let replay start, so a start after flags loaded resumed the opted-out session. Fixed in fix(replay): start a new session on opt-in whenever replay was wanted posthog-android#915. posthog-flutter made native forget that replay was wanted and restarted replay itself, through a start that checks the linked flag before rotating. Fixed in fix(replay): let native opt-out and opt-in own the replay stop and restart posthog-flutter#687, which lets native own the stop and restart (on Android it also needs posthog-android#915).
  • A recording the app stopped stays stopped. On posthog-android, with sessionReplay = true, a remote-config re-evaluation restarts replay after stopSessionReplay(). optIn() triggers one, and so does any flags reload. This is an existing bug, separate from the PRs above; it is described in posthog-android#915 and will be fixed separately.

Merge this after posthog-android#915 lands.

Out of scope

  • Browser opt_in_capturing has its own consent semantics.

Validation

openspec validate opt-in --type spec --strict passes, and openspec validate --specs --strict passes 68/68. These are specification checks, not executed SDK conformance tests.


Created with PostHog Desktop

🤖 Generated with Claude Code

@turnipdabeets
turnipdabeets changed the base branch from docs/acceptance-step-catalogue to main October 27, 2026 22:00
@turnipdabeets turnipdabeets self-assigned this Oct 29, 2026
posthog Bot and others added 2 commits October 29, 2026 16:54
Four client SDKs now agree on what optIn() does to session replay: rotate
the session before replay restarts, and leave a recording the app stopped
before opting out stopped. The opt-in spec said only that "some SDKs stop
or restart" replay.

Add the session-rotation and restart-decision requirements, and record
that the SDKs still diverge when replay is enabled but held off at
opt-out by sampling, a linked flag, an event trigger, or unloaded remote
config.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 792f97c9-4fe2-4ada-920a-c3a85d2d132e
posthog-ios#959 and posthog-js#5363 replaced the "was recording at
opt-out" rule with the one posthog-android#839 and posthog-flutter
already ship: opt-in restarts replay the app wanted (enabled in config
or started manually, not stopped since) in a new session, and sampling,
linked flags and event triggers are evaluated again there.

Specify that rule, add scenarios for a manual start and a trigger-held
replay, and drop the divergence note it resolved. Record the remaining
difference: iOS and React Native rotate whenever replay was wanted,
Android only when replay starts.
@turnipdabeets
turnipdabeets force-pushed the posthog/opt-in-replay-new-session branch from a1fb25c to 6f6c423 Compare October 29, 2026 20:56
@turnipdabeets
turnipdabeets marked this pull request as ready for review October 29, 2026 20:56
@turnipdabeets
turnipdabeets requested a review from a team as a code owner October 29, 2026 20:57
No SDK's reset() changes the remembered replay decision: iOS, Android
and React Native seed it from the session replay option at setup, and
only close() clears it on iOS. Say that instead, and note that React
Native's reset() after optOut() restores replay because it clears the
opt-out. Also record that iOS now ignores start/stop while opted out
explicitly.

@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.

Comment thread openspec/specs/opt-in/spec.md Resolved
@marandaneto
marandaneto requested a review from a team October 30, 2026 13:15
Browser opt-in has its own consent semantics, and a browser stop stays in effect through opt-out and opt-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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