Session Replay React Native Standalone SDK
The Session Replay React Native standalone SDK records mobile sessions and uploads them to Amplitude without the Amplitude Analytics SDK. Use it when another analytics provider already instruments your app, or when you manage Amplitude deviceId and sessionId yourself. If your app already uses the Amplitude React Native Analytics SDK, install the Session Replay React Native SDK Plugin instead.
You need an Amplitude API key. After you install the package, rebuild the native app. Expo Go doesn't include this native module, so use a development build or a prebuild client.
For changelog details, go to the package change log on GitHub.
Install the SDK
npm install @amplitude/session-replay-react-native --save
Quickstart
init() configures the SDK and doesn't start capture. Call start() after you pass matching deviceId and sessionId values.
import { init, start } from "@amplitude/session-replay-react-native";
await init({
apiKey: "YOUR_API_KEY",
deviceId: "YOUR_DEVICE_ID",
sessionId: Date.now(),
sampleRate: 0.1,
privacyConfig: {
maskLevel: "medium",
},
});
await start();
Correlate replays with analytics events
Session Replay matches a replay to analytics events when the standalone SDK and your analytics SDK send the same deviceId and sessionId. Pass those values into init(), then call setDeviceId() and setSessionId() whenever either identifier changes.
import {
setDeviceId,
setSessionId,
} from "@amplitude/session-replay-react-native";
await setDeviceId("new-device-id");
await setSessionId(Date.now());
The standalone SDK doesn't manage sessions for you. Your app or third-party analytics integration must keep both identifiers in sync.
Configuration
Pass this configuration to init().
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey | string | Yes | - | Your Amplitude API key. |
deviceId | string | null | No | null | Device identifier that matches the device ID on your analytics events. |
sessionId | number | No | -1 | Session identifier that matches the session ID on your analytics events. Use milliseconds since epoch. |
sampleRate | number | No | 0 | Fraction of sessions to capture, as a decimal between 0 and 1. For example, 0.4 selects 40% of sessions over a large sample. |
enableRemoteConfig | boolean | No | true | Enables remote configuration. |
logLevel | LogLevel | No | LogLevel.Warn | Sets the log level for the Session Replay SDK. Import LogLevel from @amplitude/session-replay-react-native, then pass LogLevel.None, LogLevel.Error, LogLevel.Warn, LogLevel.Verbose, or LogLevel.Debug. |
privacyConfig | { maskLevel?: 'light' | 'medium' | 'conservative' } | No | { maskLevel: 'medium' } | Privacy options. Set maskLevel to 'light', 'medium', or 'conservative'. |
optOut | boolean | No | false | Set to true to skip session replay collection at initialization. |
serverZone | 'US' | 'EU' | No | 'US' | Amplitude server zone. Set to 'EU' for EU data residency. |
Methods
init
Configures the Session Replay SDK. Call this before any other Session Replay method. init() doesn't start capture.
import { init } from "@amplitude/session-replay-react-native";
await init({
apiKey: "YOUR_API_KEY",
deviceId: "YOUR_DEVICE_ID",
sessionId: Date.now(),
});
start
Starts recording session replay. Call this after init(), and after a previous stop() when you want capture to resume.
import { start } from "@amplitude/session-replay-react-native";
await start();
stop
Stops recording session replay.
import { stop } from "@amplitude/session-replay-react-native";
await stop();
setSessionId
Updates the session identifier. Call this whenever the session ID on your analytics events changes.
import { setSessionId } from "@amplitude/session-replay-react-native";
await setSessionId(Date.now());
setDeviceId
Updates the device identifier. Call this whenever the device ID on your analytics events changes. Pass null to clear the device ID.
import { setDeviceId } from "@amplitude/session-replay-react-native";
await setDeviceId("new-device-id");
await setDeviceId(null);
getSessionId
Returns the current session identifier from the Session Replay SDK, or null if you haven't initialized the SDK.
import { getSessionId } from "@amplitude/session-replay-react-native";
const sessionId = await getSessionId();
setOptOut
Updates opt-out at runtime. Pass true to disable replay collection. Pass false to allow collection again, subject to sampling and whether you already called start().
import { setOptOut } from "@amplitude/session-replay-react-native";
await setOptOut(true);
await setOptOut(false);
flush
Uploads pending session replay data immediately.
import { flush } from "@amplitude/session-replay-react-native";
await flush();
teardown
Shuts down native Session Replay and clears JavaScript lifecycle state. Call init() again before any other Session Replay method.
import { init, start, teardown } from "@amplitude/session-replay-react-native";
await teardown();
await init({
apiKey: "YOUR_API_KEY",
deviceId: "YOUR_DEVICE_ID",
sessionId: Date.now(),
});
await start();
Mask onscreen data
Session Replay masks or obfuscates views that contain sensitive data or PII. Wrap the region with AmpMaskView and set mask to amp-mask, amp-unmask, or amp-block. AmpMaskView lays out like a normal View, so apply the same layout styles you use on a View.
import { AmpMaskView } from "@amplitude/session-replay-react-native";
<AmpMaskView mask="amp-mask">
<Text>{title}</Text>
</AmpMaskView>;
AmpMaskView is a regular React Native layout node, so it takes part in layout exactly like a View and doesn't make itself transparent to layout. When you wrap existing content, apply the sizing and flex styles that the content relies on to the AmpMaskView itself, such as flex: 1, an explicit width and height, or alignItems. Without those styles, the wrapper can collapse or resize the region you wrapped.
Unmask views
To unmask a view that the global mask level otherwise masks, set mask to amp-unmask.
import { AmpMaskView } from "@amplitude/session-replay-react-native";
<AmpMaskView mask="amp-unmask">
<Text>{title}</Text>
</AmpMaskView>;
Block views
To replace a view with an empty placeholder of the same dimensions, set mask to amp-block.
import { AmpMaskView } from "@amplitude/session-replay-react-native";
<AmpMaskView mask="amp-block">
<Text>Session Replay doesn't capture this content</Text>
</AmpMaskView>;
Platform differences in masking
Android and iOS resolve AmpMaskView with different native Session Replay libraries, so identical markup can behave differently on each platform. Test your masking on both platforms before you release.
| Behavior | Android | iOS |
|---|---|---|
| Marker resolution | The nearest explicit mask marker wins. | A masked parent wins over any marker nested inside it. |
amp-unmask nested inside a masked region | The nested subtree becomes visible again in the replay. | The nested subtree stays masked. iOS doesn't support nested unmasking. |
Where amp-unmask takes effect | Anywhere, including inside a region that amp-mask covers. | Only outside masked regions, such as on content that the mask level masks. |
| Masked text in the replay | Asterisks that preserve the length of the original text. | No image and no text. The region renders as a flat gray fill. |
amp-block in the replay | Session Replay sends no bitmap for the view, and the player renders a placeholder. | The region renders as a flat gray fill, the same as amp-mask. |
Session Replay applies these representations on the device when it captures each frame, so the uploaded replay data holds the masked representation instead of the original text or pixels. The player can't restore masked content later.
To keep a region visible on both platforms, place its amp-unmask wrapper outside every amp-mask and amp-block region rather than nesting it inside one.
Choose a masking level
Set privacyConfig.maskLevel in init().
| Mask level | Description |
|---|---|
light | Masks sensitive native text inputs, such as passwords. |
medium (default) | Masks all React Native TextInput fields. |
conservative | Masks all TextInput fields and standard React Native Text content. |
React Native masking limitations
Session Replay doesn't automatically mask text that React Native renders outside standard native text views, including react-native-svg, Shopify Skia, and canvas-based renderers. Wrap those regions in AmpMaskView.
On Android, light doesn't reliably identify credit-card fields. Use medium or conservative, or wrap the field in AmpMaskView, for cross-platform coverage.
Remote configuration on the Session Replay settings page takes precedence over the SDK. This SDK forwards enableRemoteConfig to the native iOS and Android Session Replay libraries. Amplitude's Session Replay privacy settings state that if you enable remote configuration and it fails to load, Session Replay doesn't capture sessions.
Track web views (beta)
By default, Session Replay blocks web views and doesn't track them. To track a web view, wrap it in AmpMaskView and set mask to amp-unmask.
import { AmpMaskView } from "@amplitude/session-replay-react-native";
import { WebView } from "react-native-webview";
<AmpMaskView mask="amp-unmask" style={{ flex: 1 }}>
<WebView source={{ uri: "https://reactnative.dev/" }} style={{ flex: 1 }} />
</AmpMaskView>;
EU data residency
Session Replay supports Amplitude projects that use the EU data center. Set serverZone to 'EU' during initialization.
import { init, start } from "@amplitude/session-replay-react-native";
await init({
apiKey: "YOUR_API_KEY",
deviceId: "YOUR_DEVICE_ID",
sessionId: Date.now(),
serverZone: "EU",
});
await start();
Sampling rate
By default, Session Replay captures 0% of sessions. Set sampleRate to the percentage of sessions you want to record.
import { init, start } from "@amplitude/session-replay-react-native";
await init({
apiKey: "YOUR_API_KEY",
deviceId: "YOUR_DEVICE_ID",
sessionId: Date.now(),
sampleRate: 0.1,
});
await start();
When you set sampleRate, consider the monthly quota on your Session Replay plan. For example, if your monthly quota is 2,500,000 sessions and you average 3,000,000 monthly sessions, your quota is 83% of your average sessions. To make sampling last through the month, set sampleRate to .83 or lower.
Keep these quota details in mind:
- When you reach your monthly session quota, Amplitude stops capturing sessions for replay.
- Session quotas reset on the first of every month.
- Use sample rate to distribute your session quota across the month, rather than using your full quota at the beginning.
- Start with a low rate, for example
.01. If this value doesn't capture enough replays, raise the rate over a few days. To monitor captured replay volume, go to View the number of captured sessions.
Session Replay supports remote sampling rate settings. Your organization can update the sampling rate of your project after implementation, without a code change. If there's a conflict, Session Replay defaults to the remote setting. For more information, go to Account Settings.
User opt-out
To skip collection at initialization, set optOut to true. To change this later, call setOptOut(). Don't re-run init() only to change opt-out.
import { init, setOptOut, start } from "@amplitude/session-replay-react-native";
await init({
apiKey: "YOUR_API_KEY",
deviceId: "YOUR_DEVICE_ID",
sessionId: Date.now(),
optOut: true,
});
await setOptOut(false);
await start();
Troubleshooting
No replay appears
- Call
start()afterinit().init()configures the SDK and doesn't begin capture. - Use a non-zero
sampleRate, or confirm the remote sampling rate on the Session Replay settings page. - Pass the same
deviceIdandsessionIdthat your analytics events use, and update both when they change. - Rebuild the native app after you install the package. On iOS, run
pod installbefore the rebuild. - Don't run this SDK in Expo Go. Create a development build or prebuild client instead.
Was this helpful?