A local, real-time mobile app inspector for React Native — works across multiple devices simultaneously and requires zero npm dependencies in your app.
Drop one file into any React Native project. Every log, network call, Redux action, React Query update, and navigation event appears instantly in a Chrome-DevTools-style dashboard in your browser.
| Panel | What it shows |
|---|---|
| Logs | All console.log/warn/error/info/debug — expandable, filterable by level |
| Network | Every fetch and XHR call — Chrome-style table with Headers / Preview / Response / Payload tabs, cURL export |
| Redux | Every dispatched action + shallow state diff |
| React Query | Live query state per key — history timeline per query |
| Navigation | Every screen transition with route + params |
| Custom | peekr.log(tag, value) — send anything from anywhere |
| Tool | Version | Check |
|---|---|---|
| Node.js | ≥ 18 | node --version |
| pnpm | any | pnpm --version (install: npm i -g pnpm) |
| adb | any | adb version (Android only — part of Android SDK) |
# 1. Install dependencies (one-time)
cd ~/Projects/peekr
pnpm install
# 2. Approve esbuild (one-time, required for Vite)
pnpm approve-builds
# → select esbuild with spacebar, press Enter
# 3. Start server + dashboard
pnpm dev
# Server → ws://localhost:3737
# Dashboard → http://localhost:4000
# 4. Open the dashboard
open http://localhost:4000If
pnpm devfails (esbuild not built), start each part manually:pnpm server # terminal 1 pnpm dashboard # terminal 2
When you import peekr.js, it immediately (with zero config):
| What | How |
|---|---|
| Logs | Patches console.log/warn/error/info/debug globally |
| Network | Wraps global fetch and XMLHttpRequest — catches everything regardless of Axios, ky, or plain fetch |
| Connection | Opens a WebSocket to localhost:3737 (iOS) or 10.0.2.2:3737 (Android emulator) and auto-reconnects with exponential backoff |
| Queuing | Buffers events while disconnected, flushes when connected |
What requires one extra line of code (optional):
| What | Code |
|---|---|
| Redux actions | peekr.reduxMiddleware() added to store middleware |
| React Query | peekr.watchQueryClient(queryClient) |
| Navigation | peekr.navigationListener on <NavigationContainer> |
| Axios | peekr.watchAxios(axiosInstance) |
These projects already have peekr integrated:
- peekr.js:
packages/engine/peekr.js - Import: first line of
packages/engine/index.js - Stack: Redux, Axios — add
peekr.reduxMiddleware()andpeekr.watchAxios()for full coverage
- peekr.js:
example/peekr.js - Import: first line of
example/index.js - Stack: Redux, React Query — add
peekr.reduxMiddleware()andpeekr.watchQueryClient()for full coverage
Keep peekr.js out of your linter. Some formatters (Prettier, ESLint) will try to reformat or remove it. Add to
.prettierignoreand.eslintignore:**/peekr.js
cp ~/Projects/peekr/peekr.js <your-app>/src/peekr.js// index.js — very first line, before everything else
import './src/peekr';For monorepo apps (like bmb.core) where the entry point is in a sub-package:
// packages/engine/index.js import './peekr'; // peekr.js is in the same folder
adb reverse tcp:3737 tcp:3737Run this once per emulator session. For iOS simulator, no step needed — it uses localhost automatically.
Press R in Metro or shake the device → Reload. The device appears in the peekr sidebar within 1–2 seconds.
Add any of these after the base import for richer data:
import { peekr } from './src/peekr';
// Axios — captures all requests through an axios instance
peekr.watchAxios(axiosInstance);
// Redux — add as middleware
const store = configureStore({
middleware: (getDefault) => getDefault().concat(peekr.reduxMiddleware()),
});
// React Query — pass your QueryClient
peekr.watchQueryClient(queryClient);
// React Navigation — add to NavigationContainer
<NavigationContainer onStateChange={peekr.navigationListener}>
// Custom events — send anything from anywhere
peekr.log('user_tapped', { screen: 'Home', button: 'login' });
peekr.log('api_error', { code: 401, url: '/auth/token' });| Button | Keyboard | Action |
|---|---|---|
| Clear | ⌘K |
Remove all events for the selected device |
| Pause | Space |
Freeze display — events buffer, resume to flush |
| Reverse | R |
Toggle newest-first / oldest-first order |
| Auto-scroll | — | Keep scrolled to latest event |
| Key | Panel |
|---|---|
1 |
Logs |
2 |
Network |
3 |
Redux |
4 |
React Query |
5 |
Navigation |
6 |
Custom |
- Table columns: Name (path), Method, Status, Time, Size — all sortable
- Click a row to open the detail pane:
- Headers — General info + collapsible request/response headers
- Preview — Interactive JSON tree (click
▶to expand nodes, hover any value to copy it) - Response — Raw body
- Payload — Request body (POST/PUT/PATCH)
- cURL button — copies a ready-to-paste curl command
- Filter bar — filter by URL or method
- Status filters — All / 2xx / 4xx / 5xx / Failed
- Click any long log entry to expand it fully
- Filter by level: ALL / LOG / INFO / WARN / ERROR / DEBUG
- Hover any row → copy button appears
┌─────────────────────────────────────────────────────────┐
│ Your browser │
│ http://localhost:4000 (Vite + React) │
└──────────────────────┬──────────────────────────────────┘
│ ws://localhost:3737/dashboard
┌──────────────────────▼──────────────────────────────────┐
│ peekr server (Node.js) │
│ ws://:3737/client REST http://:3737/api │
└──────────────────────▲──────────────────────────────────┘
│ ws://10.0.2.2:3737/client (Android)
│ ws://localhost:3737/client (iOS)
┌──────────────────────┴──────────────────────────────────┐
│ React Native app (peekr.js) │
│ patches fetch + XHR + console · auto-reconnects │
└─────────────────────────────────────────────────────────┘
~/Projects/peekr/
├── peekr.js ← copy this into any RN app
├── packages/
│ ├── server/ ← Node.js WebSocket + HTTP (port 3737)
│ ├── dashboard/ ← Vite + React UI (port 4000)
│ └── sdk/ ← TypeScript SDK (optional, for typed projects)
└── README.md
The server may have stopped. Run pnpm server from ~/Projects/peekr to restart it.
# Check emulator is visible
adb devices
# Re-forward the port
adb reverse tcp:3737 tcp:3737
# Reload the app in MetroMake sure peekr server is running (curl http://localhost:3737/api/health). iOS uses localhost automatically — no adb needed.
kill $(lsof -ti:3737)
pnpm servermacOS Monterey+ uses port 5000 for AirPlay — port 4000 should be free. If not:
kill $(lsof -ti:4000)
pnpm dashboardMake sure import './peekr' (or import './src/peekr') is the very first import in index.js, before any other imports including react-native-reanimated.
Add to your .eslintignore / .prettierignore:
**/peekr.js
This project includes a Claude slash command. From any React Native project:
/setup
Claude will automatically check prerequisites, start the server, copy peekr.js into your project, add the import, forward adb ports, and verify the connection — all in one shot.
To use it, make sure ~/Projects/peekr/.claude/commands/ is accessible, or copy the commands folder into your project's .claude/ directory.



