Skip to content

phaelor/react-native-app-inspector

Repository files navigation

react-native-app-inspector

CI npm license

On-device performance & debug panel for React Native — no Metro, no USB, no computer. One wrapper component, zero dependencies.

Ship it inside your QA / staging build. When a tester hits jank on a release build three timezones away, they open the panel on the phone, see what's slow and why, and share the session as JSON.

Inspector demo

Install

npm install react-native-app-inspector
cd ios && pod install        # native FPS/CPU/RSS + network capture (optional)

react and react-native are the only peer deps. The native module autolinks; without a rebuild everything still works in JS — you just lose the native metrics.

Quick start

import { InspectorRoot } from 'react-native-app-inspector';

export default function Root() {
  return (
    <InspectorRoot enabled={__DEV__}>
      <App />
    </InspectorRoot>
  );
}

That's the whole integration. Capture starts, a draggable FPS / CPU / MB badge floats over the app, and tapping it opens the panel.

What you get

Timeline tab
Timeline — everything in one log,
with cause correlation
Network tab
Network — every request,
captured natively
Taps tab
Taps — tap→response latency,
auto-captured
Perf tab
Perf — JS/UI FPS, CPU, memory,
renders
Screens tab
Screens — every screen scored
0–100, with its problems
Storage tab
Storage — browse & edit
AsyncStorage / MMKV
Tab What it shows
Timeline Time-ordered log of actions, navigation, renders, network, FPS drops, memory and errors. Tap an FPS drop → cause correlation tells you what likely caused it.
Network Every request with method, status, duration. Captured natively (NSURLProtocol / OkHttp interceptor) when the native module is installed, XHR patch otherwise.
Taps Tap→response latency for every pressable, automatically — labels from testID / text, timing from the native touch timestamp to the next presented frame. RAIL-coded: <100 ms good, >300 ms sluggish.
Perf Live JS & UI-thread FPS, CPU, RSS memory, JS heap, jank — plus per-component render stats (count, avg, worst).
Screens Per-screen score 0–100 with the concrete problems: slow load, FPS drops, slow renders, memory growth, slow requests, slow taps.
Storage Key/value browser for AsyncStorage / MMKV / anything: search, pretty-printed JSON, edit, delete, clear.
Startup Time-to-interactive and custom marks (AppInspector.mark('cache-ready')).
Settings Pause live updates, share the session (native share sheet), clear, hide the badge.

Everything above is captured automatically — network, errors (console.error / uncaught), FPS/CPU/memory, renders, taps. You only add calls for what the library can't see: custom actions and non-React-Navigation screen changes.

Configuration

All props are optional:

<InspectorRoot
  enabled={__DEV__}            // false → children render untouched, zero overhead
  navigationRef={navRef}       // React Navigation ref → automatic screen tracking
  storage={AsyncStorage}       // persist session → survives a crash/relaunch
  storages={[mmkvAdapter(kv)]} // extra stores for the Storage tab
  badge={true}                 // floating FPS badge (drag to any corner)
  badgeCorner="bottom-left"
  initialTab="timeline"
  autoCaptureTaps={true}
  profileRoot={true}           // root render profiler (id "App")
  modules={{ network: true, errors: true, performance: true, slowScreens: true }}
  maxEntries={500}             // ring-buffer size per feed
/>

Recipes

React Navigation — automatic screen tracking
const navRef = useNavigationContainerRef();

<InspectorRoot enabled={__DEV__} navigationRef={navRef}>
  <NavigationContainer ref={navRef}>{/* … */}</NavigationContainer>
</InspectorRoot>;

Every screen change is logged, timed and profiled. Without React Navigation, call AppInspector.trackNavigation('Checkout') yourself or wrap screens in <InspectorScreen name="Checkout">.

Storage tab — AsyncStorage, MMKV, custom stores
import { asyncStorageAdapter, mmkvAdapter } from 'react-native-app-inspector';

<InspectorRoot
  storages={[asyncStorageAdapter(AsyncStorage), mmkvAdapter(new MMKV())]}>

Passing storage={AsyncStorage} alone already enables the tab for it. Any object with { name, getAllKeys, get, set, remove } works as a custom store.

Manual tracking — actions, Redux, network
AppInspector.trackAction('add_to_cart', { sku: 'A-123' });
AppInspector.trackNetwork({ method: 'POST', url: '/orders', status: 201, durationMs: 840 });

// Redux — log every dispatch:
applyMiddleware(AppInspector.getActionLogger().middleware());

// Time a custom interaction (auto tap capture handles normal presses):
const done = AppInspector.beginInteraction('Checkout');
await submitOrder();
done();
Profiling one component
<InspectorProfiler id="ProductList">
  <ProductList />
</InspectorProfiler>

Its commit count / avg / worst render times show up under Perf → Renders.

Exporting a session programmatically
import { exportLogs, shareLogs } from 'react-native-app-inspector';

const json = exportLogs(); // full snapshot as a JSON string
await shareLogs();         // native share sheet (also in the Settings tab)

AppInspector.getPreviousSession() returns the persisted previous session (set storage to enable) — including one that ended in a crash.

Custom UI instead of the badge
<InspectorRoot badge={false} /* … */>
  <App />
</InspectorRoot>

Then render <InspectorModal visible={open} onClose={…} /> from your own trigger (shake, hidden multi-tap, dev menu). useInspectorState() gives you the live state for fully custom UIs.

Prefer rendering it as a sibling of InspectorRoot — inside the profiled subtree, commits containing the open panel are excluded from the render stats.

Example app

example/ is a Todo app wired for inspection — real network, actions, renders and taps to look at:

cd example && npm install && npm run ios   # or npm run android

Development

npm run typecheck && npm run lint && npm test
Project structure
src/
  core/        controller, observable store, shared types (no react-native)
  modules/     timeline, performance, screens, render, startup, network,
               actions, errors, interactions, taps, navigation, storage,
               persistence, deviceInfo
  native/      bridge to the iOS/Android native module
  ui/          badge, modal, tabs
  export/      snapshot + serialization
ios/ android/  native metrics + network capture

License

MIT © phaelor

About

On-device performance & debug panel for React Native — no Metro, no USB, no computer.

Resources

License

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors