Skip to content

feat(session-replay-react-native): add teardown and runtime setOptOut - #1947

Draft
aliaksandr-kazarez wants to merge 1 commit into
mainfrom
aliaksandrkazarez/sdkrn-62-ga1a-add-teardown-setoptout
Draft

feat(session-replay-react-native): add teardown and runtime setOptOut#1947
aliaksandr-kazarez wants to merge 1 commit into
mainfrom
aliaksandrkazarez/sdkrn-62-ga1a-add-teardown-setoptout

Conversation

@aliaksandr-kazarez

Copy link
Copy Markdown
Contributor

Summary

Adds two runtime lifecycle APIs to the React Native session replay SDK: teardown() and setOptOut(). Previously the only way to release the native SDK or stop capture after init was to tear down the whole plugin.

Linear: SDKRN-62

JS API

  • teardown() releases the native SDK and clears JS state, so init() 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 later start() call.
  • SessionReplayPlugin.teardown() now calls native teardown instead of stop(), so plugin teardown actually releases native resources.

iOS writes the natively mutable SessionReplay.optOut property, which gates capture directly. teardown() nils the instance, which triggers the SDK's own deinit cleanup.

Android has no public runtime opt-out setter — SessionReplayInternal keeps optOut as 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 calling stop() so buffered frames are not flushed, then recreate the SDK on opt-in and only resume start() 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 sessionReplay nullable rather than lateinit, so every call site degrades gracefully before setup and after teardown.

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: No — both APIs are additive. The one behavior change is 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 for setOptOut, teardown, and teardown-then-re-init
  • tsc --noEmit clean
  • prettier --check and eslint clean
  • On-device verification of the opt-out and teardown/re-init flows against native debug replay servers (harness in progress, not part of this PR)

Posted automatically with Cursor. LLMs make mistakes — please verify before acting.

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

linear-code Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

SDKRN-62

@github-actions

Copy link
Copy Markdown

size-limit report 📦

Path Size
packages/analytics-browser/lib/scripts/amplitude-min.js.gz 61.54 KB (0%)
packages/session-replay-browser/lib/scripts/session-replay-browser-min.js.gz 134.97 KB (0%)
packages/unified/lib/scripts/amplitude-min.umd.js.gz 215.58 KB (0%)
@amplitude/element-selector (gzipped esm) 2.67 KB (0%)

@aliaksandr-kazarez
aliaksandr-kazarez requested a lite review from Copilot August 20, 2026 19:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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() and setOptOut(optOut) (with start() 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);
}
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