Skip to content

feat(react-native): support session replay v2 trigger groups - #5239

Open
marc-merino wants to merge 1 commit into
PostHog:mainfrom
marc-merino:knit/session-replay-v2-trigger-groups-on-mobile
Open

marc-merino wants to merge 1 commit into
PostHog:mainfrom
marc-merino:knit/session-replay-v2-trigger-groups-on-mobile

Conversation

@marc-merino

@marc-merino marc-merino commented Oct 7, 2026 •

Copy link
Copy Markdown

Knit Bundle

View bundle

This PR is part of Knit bundle session-replay-v2-trigger-groups-on-mobile.

See the other review objects in this bundle:

Bundle id: session-replay-v2-trigger-groups-on-mobile
Bundle title: Session replay v2 trigger groups on mobile

One of four PRs adding session replay v2 trigger groups to the mobile SDKs (Android, iOS, React Native, Flutter). You can see the unified description of the whole change here: Svartal bundle. The four PRs are linked above.

Problem

Closes #4595.

The server and posthog-js already support session replay v2 trigger groups (sessionRecording.version: 2 with a triggerGroups array). posthog-react-native only reads the v1 linkedFlag / eventTriggers fields, so with a v2 config it started recording without applying the per-group conditions or sampling.

Changes

On React Native, events and screens are captured in JS and never reach the native SDK, so the JS layer owns the trigger-group decision (src/session-replay/triggerGroups.ts), mirroring posthog-js V2TriggerGroupStrategy:

  • Each group has event, screen and flag conditions, combined with any / all. Screen names ($screen_name) take the place of URLs. A group with no conditions activates immediately.
  • Sampling is per group, using the same hash as posthog-js (sessionId + groupId), so web and mobile reach the same decision for a session.
  • Recording starts as soon as any activated group is sampled in, using the existing start/stop path to the native plugin. Activation resets when the session rotates.
  • Under v2, the flat remote sampleRate isn't forwarded to the native plugin, since per-group sampling replaces it.
  • $sdk_debug_replay_remote_trigger_matching_config, $sdk_debug_replay_trigger_groups_count and $sdk_debug_replay_matched_recording_trigger_groups match posthog-js.
  • Nothing changes when version is missing or 1.
  • Not covered: per-group minDurationMs. JS computes it (it's in the debug log), but the native plugin can't receive it yet. Passing it needs an addition to the plugin API, so I'd rather agree that with you first.

Companion PRs (linked in the Knit block above) teach posthog-android and posthog-ios the same groups, and make them skip the event and screen conditions under React Native, so the native layer doesn't evaluate what it can't see. I'd especially like a sanity check on that split. The sdk-specs hybrid section currently describes v2 as web-only; happy to add the mobile behaviour there in a follow-up.

node .agents/skills/replay-incident-risk/check.mjs reports no incident-pattern matches.

How did you test it?

  • Unit tests for parsing, status combining, the sampling hash (vectors computed from the posthog-js helper), property filters, the union rule, session rotation, and the recording wiring. pnpm test:unit in packages/react-native: 1284 pass; types check.
  • End to end with examples/example-expo-57 on an Android 15 emulator, pointed at a local mock PostHog server:
    • Two groups, button_clicked with sampleRate: 0 and open_replay_screen_tapped with sampleRate: 1. After button_clicked: record=false, the group reports matched: true, sampled: false. After the "Fire 'open_replay_screen_tapped'" button: record=true, the native recorder resumes and isSessionReplayActive() returns true.
    • One group on screen explore: record=false on the home tab, record=true and recording resumes after opening the Explore tab ((tabs)/explore).
    • In this emulator setup no $snapshot uploads reached the mock, for v2 and equally for the existing v1 event trigger, so I verified the JS decision and native isEnabled() rather than uploaded snapshots. The plugin still bundles posthog-android 3.71.6.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Driven by me in Ivaldi, my agent workspace. Claude Code (Opus 5.5) planned, reviewed and integrated the work; OpenCode (GLM 5.3) wrote the first implementation from a contract taken from the posthog-js browser code.
  • The feature spans four repos, so I ran it as one Knit bundle: the Android, iOS, React Native and Flutter changes were built, tested and versioned together. All four diffs side by side on Svartal.

Evaluate the v2 trigger groups from the sessionRecording remote config
in the JS layer, which owns the event and screen conditions on React
Native: per-group event, screen and flag conditions combined with
any/all, per-group sampling with the same hash as posthog-js, and
recording when any activated group is sampled in. The $sdk_debug_replay_*
properties report the matched groups. Configs without version 2 keep
the v1 behaviour.

Assisted-by: OpenCode/glm-5.3
Assisted-by: Claude Code/claude-opus-5-5

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.

Session replay (React Native): support v2 trigger groups (conditional recording)

1 participant