| name | session-replay-mobile |
| description | How mobile session replay works (view-hierarchy reconstruction, not screen recording), how to configure privacy masking, and the cost / privacy tradeoffs. Use when evaluating or enabling Sentry, Datadog, or LogRocket session replay on mobile. |
Session Replay on Mobile
Instructions
Mobile session replay is powerful and expensive. It is also the single highest privacy risk in the observability stack. Enable it with eyes open.
1. How It Works (Not What You Think)
Mobile replay does not record the screen. Vendors reconstruct the UI from:
- The view hierarchy (periodic snapshots of view bounds, text, images).
- Interaction events (taps, scrolls, text input focus -- usually not content).
- Lifecycle events (screen transitions, foreground/background).
- Network summary (URL, status, duration -- usually redacted from body).
This reconstruction is replayed frame-by-frame in the vendor UI. Because it is structural, masking can be enforced per view rather than by pixel detection.
2. Vendor Support (2024+)
- Sentry: iOS (Swift/UIKit, SwiftUI), Android (Views + Jetpack Compose), Flutter, React Native. Mask-by-default.
- Datadog RUM: iOS and Android; privacy rules via
dd-privacy attributes. Mask-by-default opt-in.
- LogRocket / FullStory Mobile: iOS + Android; require deeper instrumentation for masking.
- Embrace: session timeline is the native model; partial reconstruction.
Always read the current docs -- replay is still evolving, and defaults change release-over-release.
3. Privacy: Mask By Default
Every text view, image view, web view, and input must start masked. Opt specific views in to unmasking, not out of masking.
Sentry iOS (UIKit / SwiftUI)
options.sessionReplay.maskAllText = true
options.sessionReplay.maskAllImages = true
options.sessionReplay.maskedViewClasses = [UITextField.self, UITextView.self, UILabel.self]
Explicit opt-in to show content:
label.sentryReplayUnmask()
image.sentryReplayUnmask()
Sentry Android
options.sessionReplay.isMaskAllText = true
options.sessionReplay.isMaskAllImages = true
SentryReplay.unmask(view)
Modifier.sentryUnmask()
Datadog
view.dd.privacyLevel = .maskAll
val config = RumMobileSessionReplayConfiguration.Builder()
.setImagePrivacy(ImagePrivacy.MASK_ALL)
.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_ALL)
.build()
4. WebViews and Hybrid Content
- Treat webview contents as a black box by default. Most SDKs cannot introspect webview DOM.
- For PWAs inside webviews, use the browser SDK in the web content with its own masking config.
- Redact webview URLs that embed tokens (
?auth=...).
5. Consent Gating
- Do not start replay before explicit consent for
session_replay (see analytics-privacy).
- Provide an in-app toggle to revoke; on revoke, stop the recorder and drop the buffered segment.
- In kids-directed apps, replay must be disabled outright.
6. Sampling Strategy
Two independent sample rates:
sessionSampleRate: fraction of all sessions recorded. Keep 0.01 - 0.05 in production.
replaysOnErrorSampleRate: fraction of error-bearing sessions recorded retroactively. Keep 0.5 - 1.0.
The on-error sampler uses a ring buffer so the pre-error segment is captured when an error fires. Total paid replays = (DAU * session_sample_rate) + (error_sessions * on_error_rate).
7. Cost Modelling
Replay is usually billed per captured replay and per minute stored. Rough unit economics for Sentry as an example:
- Replay quota is separate from errors and transactions.
- A typical mobile session is 2-5 minutes; a 1% sample rate on 1M DAU yields ~10k replays/day.
- Budget 10-20% of your total observability spend for replay. If replay is eating more, reduce
sessionSampleRate or disable on low-value screens.
8. Battery and Performance
- Replay SDKs snapshot the view hierarchy on a timer (default 1 Hz) plus on interaction. This is CPU work on the main thread.
- Benchmark the cold-start and scroll-frame impact; reject if cold start increases more than 120 ms on mid-tier devices.
- Disable replay on older OS versions (
N-3 and below) where CPU headroom is already scarce.
9. Data Retention and Deletion
- Replay recordings must honor the right-to-erasure flow: tie replay
session_id to user_id_hash so backend deletion removes associated replays.
- Default retention: 30-90 days. Mobile replay retention should be shorter than standard log retention because of its richness.
- Exclude replay from long-term data warehousing; it is a debugging artifact, not an analytics source.
10. What Replay Is and Isn't Good For
Good for:
- Reproducing the exact sequence of screens leading into a crash.
- Diagnosing UX dead-ends and confusing flows.
- Spotting where users tap but nothing happens.
Not good for:
- Training data for ML models.
- Measuring quantitative funnels (use product analytics).
- Any regulated content (health diagnoses, financial transactions without extra masking).
Checklist