feat(session-replay-react-native): add teardown and runtime setOptOut - #1947
Draft
aliaksandr-kazarez wants to merge 1 commit into
Draft
feat(session-replay-react-native): add teardown and runtime setOptOut#1947aliaksandr-kazarez wants to merge 1 commit into
aliaksandr-kazarez wants to merge 1 commit into
Conversation
Consumers need to release the native session replay SDK and to opt users in and out of capture after init, which previously required tearing down the whole plugin. Adds `teardown()` and `setOptOut()` across the JS API, the TurboModule spec, and both native bridges. iOS writes the natively mutable `SessionReplay.optOut` property. Android has no public runtime setter (SDKA-78), so the bridge mirrors Flutter: it disposes the native instance without calling `stop()`, so buffered frames are not flushed, then recreates the SDK on opt-in and only resumes `start()` if recording was already running. The previous stop/start stand-in is removed because it flushed buffered data on opt-out. `SessionReplayPlugin.teardown()` now calls native teardown rather than stop, so plugin teardown actually releases native resources.
Contributor
size-limit report 📦
|
Contributor
There was a problem hiding this comment.
Pull request overview
Adds runtime lifecycle controls to the React Native Session Replay SDK so apps can (1) release native resources and re-init() and (2) toggle opt-out at runtime without tearing down the whole analytics plugin.
Changes:
- Adds JS APIs
teardown()andsetOptOut(optOut)(withstart()becoming a no-op while opted out) and exports them publicly. - Implements native support on iOS (teardown + runtime opt-out flag) and Android (recreate-on-opt-in workaround while avoiding stop/flush on opt-out).
- Updates unit/integration tests, mocks, and the example app to cover and demonstrate the new APIs.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/session-replay-react-native/test/session-replay.test.ts | Extends integration test coverage to include setOptOut() and teardown() calls. |
| packages/session-replay-react-native/test/plugin-session-replay.test.ts | Updates plugin teardown expectations to call native teardown() (not stop() twice). |
| packages/session-replay-react-native/test/index.test.ts | Adds export coverage for setOptOut and teardown/re-init behavior. |
| packages/session-replay-react-native/test/mocks/react-native.ts | Extends the RN native module mock with teardown and setOptOut. |
| packages/session-replay-react-native/src/specs/NativeAmpSessionReplay.ts | Updates TurboModule spec to include teardown() and setOptOut(). |
| packages/session-replay-react-native/src/session-replay.ts | Adds JS runtime APIs, opt-out gating for start(), and state management for teardown/opt-out. |
| packages/session-replay-react-native/src/plugin-session-replay.ts | Routes plugin teardown through the new session replay teardown API. |
| packages/session-replay-react-native/src/native-module.ts | Extends the native bridge interface docs/types for teardown and opt-out. |
| packages/session-replay-react-native/src/index.tsx | Re-exports teardown and setOptOut from the public entrypoint. |
| packages/session-replay-react-native/ios/NativeSessionReplay.swift | Adds native iOS implementations for teardown and runtime setOptOut. |
| packages/session-replay-react-native/ios/AMPNativeSessionReplay.mm | Exposes the new native iOS methods to React Native. |
| packages/session-replay-react-native/example/App.tsx | Adds UI controls to exercise setOptOut and teardown/re-init in the example app. |
| packages/session-replay-react-native/android/src/oldarch/java/com/amplitude/sessionreplayreactnative/SessionReplayReactNativeSpec.kt | Extends old-arch RN spec with teardown and setOptOut. |
| packages/session-replay-react-native/android/src/main/java/com/amplitude/sessionreplayreactnative/SessionReplayReactNativeModule.kt | Implements Android teardown and recreate-on-opt-in opt-out behavior; caches resolved config. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+251
to
+259
| export async function teardown(): Promise<void> { | ||
| if (!isInitialized) { | ||
| logger.warn('SessionReplay is not initialized'); | ||
| return; | ||
| } | ||
| await NativeSessionReplay.teardown(); | ||
| isInitialized = false; | ||
| fullConfig = null; | ||
| } |
Comment on lines
+255
to
+258
| override fun invalidate() { | ||
| sessionReplay?.shutdown() | ||
| sessionReplay = null | ||
| } |
Comment on lines
+278
to
+287
| export async function setOptOut(optOut: boolean): Promise<void> { | ||
| if (!isInitialized) { | ||
| logger.warn('SessionReplay is not initialized'); | ||
| return; | ||
| } | ||
| if (fullConfig) { | ||
| fullConfig = { ...fullConfig, optOut }; | ||
| } | ||
| await NativeSessionReplay.setOptOut(optOut); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two runtime lifecycle APIs to the React Native session replay SDK:
teardown()andsetOptOut(). Previously the only way to release the native SDK or stop capture afterinitwas to tear down the whole plugin.Linear: SDKRN-62
JS API
teardown()releases the native SDK and clears JS state, soinit()can be called again.setOptOut(optOut)toggles capture at runtime and keeps the resolved config in sync.start()is now a no-op while opted out, so an opt-out cannot be defeated by a laterstart()call.SessionReplayPlugin.teardown()now calls native teardown instead ofstop(), so plugin teardown actually releases native resources.iOS writes the natively mutable
SessionReplay.optOutproperty, which gates capture directly.teardown()nils the instance, which triggers the SDK's owndeinitcleanup.Android has no public runtime opt-out setter —
SessionReplayInternalkeepsoptOutas a private constructor-only property (tracked in SDKA-78). Until that setter ships, the bridge mirrors what the Flutter SDK does: dispose the native instance without callingstop()so buffered frames are not flushed, then recreate the SDK on opt-in and only resumestart()if recording was already running. This replaces the previous stop/start stand-in, which flushed buffered data on opt-out and was therefore a privacy bug.To support recreate-on-opt-in, the Android bridge now retains the resolved init config and keeps
sessionReplaynullable rather thanlateinit, so every call site degrades gracefully before setup and after teardown.Checklist
SessionReplayPlugin.teardown()releasing native resources instead of only stopping capture, which is the documented intent of teardown.Test plan
jest— 57/57 pass, including new coverage forsetOptOut,teardown, and teardown-then-re-inittsc --noEmitcleanprettier --checkandeslintcleanPosted automatically with Cursor. LLMs make mistakes — please verify before acting.