Skip to content

For mobile app teams

Session Replay for Mobile App Teams

Screenshot-based mobile replay is costly, needs a native module and cannot be translated. How React Native teams record the element tree with AnyReplay instead.

Updated · 5 min read

Mobile session replay has usually meant one thing: capture the screen as an image several times a second, compress it, upload it. It works, at a cost mobile teams know well: battery, bandwidth, a native module to install, and a recording that is a video nobody can search. Session replay for mobile app teams with AnyReplay takes a different approach for React Native. It records what the app rendered as elements, not pixels.

This page covers why screenshot recording is a poor fit for React Native, how element-tree recording works, what is masked on the device, which option controls cost, and what the SDK cannot see.

The problem: screenshots are the wrong primitive for React Native

A screenshot recorder has three costs. It is expensive on the device: capturing, encoding and uploading images drains battery and data, and users notice. It needs a native module, which means a rebuild, a native install step, and no Expo Go. And the result is pixels: you cannot search for the screen where a label was wrong, and you cannot translate a picture of a Turkish interface for a reviewer who reads German.

There is a fourth cost that is easy to miss. A screenshot records the user's data as an image, and an image cannot be masked reliably after the fact. Masking has to happen before capture, which for pixels means guessing where the sensitive text will be.

How replay fits a mobile team's workflow

Mobile teams use replay the way web teams do: watching sessions after a release, jumping to the moment a user gave up, and attaching a recording to a bug report. The difference is that in a React Native app the recording is a wireframe with real text. A QA engineer sees the screen name, the components on it, their text and their layout, and can search sessions for the text of the failing screen. The QA and bug reproduction page covers that side.

Because the recording is text, session translation applies to mobile sessions the same way it applies to web: a reviewer picks a language, the labels are translated before playback, and product names stay as they are. The post on session replay for React Native goes deeper into the recording model.

What AnyReplay does for mobile app teams

Element-tree recording, no native module

The React Native SDK reads the element tree React has committed on each tick. For each host element it notes what the element is and what it says, then measures where it sits on screen. The result is a React Native element tree with text and positions: a semantic recording rather than a picture. There is no native module, no rebuild, and it works in Expo Go on SDK 52+.

Small on the wire

The first frame of a screen is a few kilobytes. Every later frame carries only what changed, and an idle screen sends nothing. Frames are captured on an interval, snapshotIntervalMs, default 500 milliseconds, and that interval is the main cost lever: raise it to reduce data and battery use, lower it for finer detail on screens that matter.

Masking on the device

Masking is applied on the device before anything leaves it, and works exactly as it does on the web. Anything with secureTextEntry, any field that a textContentType, autoComplete, keyboardType, placeholder or label marks as a credential or payment field, and any card number, whole or typed past its sixth digit, are masked whatever you configure; any element whose testID contains ar-mask is masked because you said so. A masked element keeps its box and loses its words; the server never sees the value. Other fields are masked by default too, unless you set maskAllInputs: false. With that opt-out, a bare <TextInput /> with no props says nothing about itself and is recorded, so give sensitive fields a textContentType, an autoComplete or an ar-mask testID. The privacy page has the full model.

trackNavigation(ref) accepts a react-navigation container ref and records screen changes, so a session reads as a sequence of named screens. screen(name) does the same by hand for other routers. identify({ userId, email }) ties the session to a user your support and analytics systems already know, and passing AsyncStorage as storage lets the SDK recognise a returning visitor.

requireConsent: true records nothing until consent(true) is called. sampleRate from 0 to 1 is decided once per visitor. flush() forces an upload before the app goes to the background, getSessionId() returns the ID for your bug report form, and stop() ends recording.

What the SDK cannot see

Being clear about limits saves a week of surprise later. A FlatList records only the rows that were rendered, not the whole data set. Maps and videos are labelled boxes. Custom native components the SDK does not recognise are recorded as Unknown boxes with their layout. And there is no native iOS or Android SDK yet.

Getting started

  1. Create a project. The Free plan includes one project and 500 sessions per month; see pricing for the current plans.
  2. Run npm install @anyreplay/react-native, call init({ projectKey }) at app start and wrap the app in <AnyReplay>. If the project restricts domains, list the bundle id under Allowed apps and pass it as appId.
  3. Pass your navigation container ref to trackNavigation, and call identify once the user is signed in.
  4. Ship. Watch the first sessions, then raise snapshotIntervalMs if data use is higher than you want.

Frequently asked questions

Does the SDK need a native module or a rebuild?

No. It is plain JavaScript that reads the tree React has committed, and works in Expo Go (SDK 52+) without any native code.

What does a recording look like?

A wireframe of the screen with real text and real positions. Text is searchable and translatable; maps and videos appear as labelled boxes; masked inputs keep their box and lose their text.

Does it work with native iOS or Android apps?

Not yet. There is no native iOS or Android SDK; you can ask to be notified from the setup page.

How do I reduce battery and data use?

Raise snapshotIntervalMs from its default of 500 milliseconds. Idle screens send nothing regardless, and later frames carry only what changed.

Are passwords recorded?

Not if it is a password, a one-time code or a payment field: anything with secureTextEntry, or marked by a textContentType, autoComplete, keyboardType, placeholder or label, is masked on the device before upload, so the value never leaves the phone. Other fields are masked too unless you set maskAllInputs: false.

Start free — 1 project, 500 sessions a month

Install the snippet, record a session, and watch it back in your own language.