Install — Mobile
Install AnyReplay in React Native
Record React Native app sessions with @anyreplay/react-native: install, call init, wrap the app in AnyReplay, and understand what the recorder captures.
The React Native SDK records what your app shows as a tree of elements and text rather than as screenshots. It is pure JavaScript — no native module, no pod install, no rebuild — and a session recorded on a phone appears in the same session list as your web sessions and can be translated the same way. For an overview of what to expect before you install, see the React Native session replay SDK.
Requirements
- React Native 0.72 or later and React 18 or later (the package's peer dependencies).
- The New Architecture (Fabric), to record the screen. It is on by default from React Native 0.76 and Expo SDK 52; on React Native 0.72 to 0.75 you turn it on yourself (
newArchEnabled). The recorder measures elements through Fabric.
Install
npm install @anyreplay/react-nativepnpm add @anyreplay/react-nativeyarn add @anyreplay/react-nativeAdd it to your app
// App.tsx
import { AnyReplay, init, trackNavigation } from '@anyreplay/react-native';
init({
projectKey: 'YOUR_PROJECT_KEY',
ingestUrl: 'https://in.anyreplay.com',
// Your bundle id (iOS) or package name (Android). Required once the project lists allowed domains or apps.
// appId: 'com.example.app',
// Stop recording after this many sessions in a calendar month.
// maxSessionsPerMonth: 10000,
// Fields are masked: what people type replays as asterisks. Secure
// fields, passwords, one-time codes and card fields are masked either
// way. Uncomment the first line to record what people type, or the
// second to mask every field in a way nothing can weaken.
// maskAllInputs: false,
// maskAllTyping: true
});
export default function Root() {
return (
<AnyReplay>
<NavigationContainer ref={(ref) => { if (ref) trackNavigation(ref); }}>
<App />
</NavigationContainer>
</AnyReplay>
);
}Two pieces, and both are needed:
- `init(options)` starts the recorder. Call it once, at module level, before your root component renders. A second call is ignored, so a hot reload in development does not start a second recorder.
- `<AnyReplay>` wraps the app. It is how the recorder finds React's tree, and it sees every touch on the way to your components — then hands it straight back, so buttons still press and lists still scroll. Without it the recorder has nothing to read and, with
debug: true, says so.
The trackNavigation line is optional but recommended: it names each screen after its route. See navigation tracking.
Remember returning visitors
By default the visitor and session ids live in memory and are forgotten when the app process ends. Pass any storage with async getItem and setItem — AsyncStorage is the usual choice — and a relaunch within 30 minutes resumes the same session, while sampling stays stable for the same person across launches.
import AsyncStorage from '@react-native-async-storage/async-storage';
import { init } from '@anyreplay/react-native';
init({ projectKey: 'YOUR_PROJECT_KEY', storage: AsyncStorage });Consent
import AsyncStorage from '@react-native-async-storage/async-storage';
import { consent, init } from '@anyreplay/react-native';
init({ projectKey: 'YOUR_PROJECT_KEY', requireConsent: true, storage: AsyncStorage });
// when the person agrees — right after init is fine
consent(true);With requireConsent: true nothing is recorded and nothing is written to storage until consent(true). init is asynchronous, and consent may be called before it has finished: the decision is applied the moment it does, and a consent(false) made early keeps the recorder from ever starting. consent(false) also removes the stored ids, so a person who refuses is not recognised on the next launch. Store the choice yourself and call consent(true) on each launch for people who have already agreed. See consent.
What is recorded
- The committed element tree on each tick — element types, text, position and size, plus image URLs, icon-font glyphs, gradients, corner radius and borders — every 500 ms by default (
snapshotIntervalMs). Each tick sends only what changed; an unchanged screen sends nothing. - Touches, in screen points, and rage taps (three taps within a second, within 30 points of each other). A tap is recorded once, when the finger lifts, and a scroll or a swipe is not a tap.
- Screen changes, as page views.
- Device details on the first chunk: platform and OS version, model where available, screen size and locale.
Images that ship inside your app bundle are uploaded once per project, addressed by content hash, so the replay can draw them. Photos from the device's caches or photo library are never read. Set maskImages: true to record no image URLs at all.
Privacy defaults
What a person types into a TextInput is masked by default, the same as in the browser SDK. Set maskAllInputs: false to record field values, or maskAllTyping: true to keep every field masked in a way that cannot be weakened elsewhere in your configuration.
| Masked without configuration | How it is recognised |
|---|---|
| A secure field | secureTextEntry. |
| A password, new password or one-time code | textContentType, autoComplete, or keyboardType: "visible-password". |
| A card number, security code, expiry or cardholder name | textContentType: "creditCard…" or autoComplete: "cc-…". |
| A field named like one of those | Its placeholder, accessibilityLabel, testID or nativeID. |
| A value of 13–19 digits that passes the card-number check | The value itself. |
| A card number still being typed | Digits starting 2–6, grouped like a card, more than six of them: at most the first six are recorded. |
Elements whose testID contains ar-mask | What you marked. |
A masked element keeps its box and loses its words, on the device, before anything is sent. A <TextInput /> with no props at all says nothing about itself and is recorded — give a sensitive one a textContentType, an autoComplete or an ar-mask testID. See masking and blocking.
Known limits
- Lists record the rows that are rendered. Scrolling back in a replay shows the rows that existed at that moment, not the whole list.
- Custom native components record as a box with no text, because there is nothing readable to capture.
- The end of a session is flushed when the app goes to the background. If the operating system kills the app without that warning, the last few seconds can be lost.
For options and the full API see the React Native SDK reference. Using Expo? See Expo.