AI-powered crash analysis is now available on all plans — including Free.Read the crash analysis guide

Mobile Session Replay Without Video: How Event-Based Replay Works

NFNourin Mahfuj Finick··9 min read

Video recording of mobile sessions sounds like the perfect debugging tool — watch exactly what your user did and you'll know exactly what went wrong. The problem is that "exactly what the user did" includes typing their password, entering their credit card, and reading their private messages. That's a compliance nightmare, and in 2026 it's also a regulatory risk in most of the world.


Event-based session replay gives you the same debugging power without recording a single pixel. This article explains how it works, what it captures, why it's legally safer, and how to implement it in React Native and Flutter.


The Privacy Problem with Video Session Replay


Video-based session replay tools (FullStory, Hotjar for mobile, LogRocket with screen recording) work by capturing the screen at regular intervals — either as screenshots or as a DOM/view hierarchy diff. The fundamental problem: your "screen" might contain:


  • Password fields being typed into
  • Credit card numbers (even partially masked)
  • Private messages or chat history
  • Medical or financial information
  • Government ID numbers

Even when tools claim to "automatically mask" sensitive fields, that masking can fail. A custom input component, a web view, or a third-party payment sheet won't be recognized as sensitive. One unmasked frame containing a password is a GDPR incident.


Under GDPR Article 4, a screen recording containing readable personal data qualifies as processing of personal data and requires a lawful basis. Screen recordings of health or financial data may require explicit consent, not just legitimate interest. Apple's App Store privacy labels require disclosing screen recording under "Other Data" → "Other Usage Data," which can deter privacy-conscious users.


How Event-Based Replay Works


Instead of recording pixels, the SDK instruments your app to emit structured events. Each event is a small JSON object describing something that happened:


{ "type": "tap", "target": "LoginButton", "x": 120, "y": 340, "timestamp": 1705312412000 }
{ "type": "navigation", "from": "LoginScreen", "to": "HomeScreen", "timestamp": 1705312413200 }
{ "type": "network", "url": "/api/auth/login", "method": "POST", "status": 200, "duration": 312 }
{ "type": "crash", "message": "TypeError: Cannot read property 'id' of undefined", "fatal": true }

No pixels. No screenshots. No view hierarchy snapshots. Just structured, typed events that describe behavior.


The dashboard reconstructs the user's journey from this event stream:


1. Load the event timeline for the session in sequence order

2. Render the app's navigation structure as the user moved between screens

3. Animate tap indicators at the recorded coordinates

4. Draw a timeline bar showing network requests, errors, and crashes

5. Allow scrubbing to any point in the session


The result looks similar to video replay from a usability standpoint — you can follow what the user did step by step — but no sensitive visual data was ever captured.


What Gets Captured


A complete event-based replay session includes:


Touch events: Which element was tapped (by accessibility label or component name), tap coordinates, swipe direction and velocity, long press duration.


Navigation events: Screen names and transitions in sequence. Every push, pop, replace, and modal presentation.


Network requests: URL (optionally redacted), HTTP method, status code, response time, and whether the request succeeded or failed. Request and response bodies are never captured.


App lifecycle: Background/foreground transitions, memory warnings, battery state changes.


Custom breadcrumbs: Any event you explicitly log — "user reached checkout", "payment attempted", "feature flag: new_onboarding=true".


Crashes and errors: Full stack trace, error message, whether the crash was fatal, and the sequence number of the last event before the crash.


What Never Gets Captured


By design, event-based replay does not and cannot capture:


  • Screenshots or video frames
  • Text typed into input fields
  • Clipboard contents
  • Notification content
  • Camera or microphone input
  • Request or response bodies
  • Any data you don't explicitly instrument

The SDK has no mechanism to capture pixel data. This isn't just a configuration option — it's architectural.


Privacy and Compliance Advantages


GDPR (EU)


Structured behavioral events — tap X, Y on screen Z — are generally not personal data under GDPR unless combined with a persistent user identity. BugsPulse uses randomly generated session IDs that are not linked to user accounts, email addresses, or device identifiers. This means crash and session data typically falls under legitimate interest rather than requiring consent.


CCPA (California)


The CCPA's definition of "sale" covers sharing data with third parties for consideration. BugsPulse doesn't share session data with third parties. Behavioral debug data that isn't linked to an identifiable consumer falls outside the CCPA's strictest requirements.


App Store Privacy Labels (Apple)


Apple's privacy nutrition labels ask about: contact info, health & fitness, financial info, location, sensitive info, contacts, user content, browsing history, search history, identifiers, usage data, diagnostics, and "other data."


For event-based replay without device ID or user identity, the applicable categories are limited to Usage Data (app interactions) and Diagnostics (crash data). Both can typically be declared as linked to "none" (anonymous) and used for app functionality only — a much cleaner label than screen recording tools, which often trigger multiple categories.


Google Play Data Safety


Similarly, Google Play's Data Safety section requires disclosing "app activity" (app interactions, in-app search history) and "app info and performance" (crash logs). Event-based replay maps cleanly to these categories without triggering financial, health, or personal info disclosures.


Implementing Event-Based Replay in React Native


npm install @bugspulse/react-native
npx pod-install  # iOS only

import BugsPulse from '@bugspulse/react-native';

BugsPulse.init({
  apiKey: 'bp_your_project_key',
  sessionReplay: true,       // enable event-based replay
  captureTouches: true,      // record tap/swipe events
  captureNetworkRequests: true, // record HTTP events
  captureCrashes: true,      // automatic crash capture
  environment: __DEV__ ? 'development' : 'production',
});

To track navigation with React Navigation:


import { NavigationContainer } from '@react-navigation/native';
import BugsPulse from '@bugspulse/react-native';

function App() {
  return (
    <NavigationContainer
      onStateChange={(state) => {
        const currentRoute = state?.routes[state.index];
        if (currentRoute) {
          BugsPulse.setCurrentScreen(currentRoute.name);
        }
      }}
    >
      {/* ... */}
    </NavigationContainer>
  );
}

Implementing Event-Based Replay in Flutter


import 'package:bugspulse/bugspulse.dart';

await BugsPulse.init(
  apiKey: 'bp_your_project_key',
  sessionReplay: true,
  captureTouches: true,
  captureNetworkRequests: true,
);

Add the navigator observer to capture navigation events automatically:


MaterialApp(
  navigatorObservers: [BugsPulseNavigatorObserver()],
  home: const HomeScreen(),
)

Reading a Session in Your Dashboard


When you open a session in the BugsPulse dashboard, you'll see:


The timeline — a horizontal bar showing events in time order. Network requests appear as blue markers, errors as red, crashes as a red X at the point where the session ended.


The screen flow — a list of screens the user visited, with timestamps and duration on each screen.


Network panel — every HTTP request with method, URL, status code, and duration. Slow requests and errors are highlighted.


Event log — the raw event stream in sequence order. Useful for understanding exactly what happened between the last meaningful action and the crash.


A typical debugging session looks like: find a crash in the crashes list → open the linked session → see that the user navigated to CartScreen → see that the /api/cart request returned 500 → see that the crash happened in the error handler that assumed the response would always succeed. Total time to root cause: 2 minutes instead of 2 hours of trying to reproduce.


Event-Based vs Video: A Practical Comparison


CapabilityVideo ReplayEvent-Based Replay
See exact UIYesNo (screen names + events)
Debug crashesLimitedFull context
Debug navigation flowsYesYes
Privacy-safeNoYes
App Store compliantRiskyClean
GDPR riskHighLow
SDK size impactHigh (video encoding)Minimal
Battery/CPU impactHighMinimal
Data volume1–5 MB/session2–20 KB/session

For debugging — which is what most mobile engineering teams need — event-based replay is strictly better. It gives you what matters: what the user did, what the network returned, and where the crash happened. What it doesn't give you is the pixel-perfect visual that's also what creates compliance risk.


Summary


Event-based session replay is the right approach for production mobile apps. It solves the core debugging problem — "what was the user doing before this crash?" — without creating the privacy and compliance exposure that video recording carries. The tradeoff of not seeing the exact pixel rendering is almost always acceptable: crashes are caused by logic errors and data problems, not by what the UI looked like.


Instrument once, and you'll never again be in the situation of looking at a stack trace with no idea what led to it.