Skip to content

christi10/peekr

Repository files navigation

peekr

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.


What you get

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

Prerequisites

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)

Quick start

# 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:4000

If pnpm dev fails (esbuild not built), start each part manually:

pnpm server      # terminal 1
pnpm dashboard   # terminal 2

What peekr.js does automatically

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)

Connected projects

These projects already have peekr integrated:

bmb.core

  • peekr.js: packages/engine/peekr.js
  • Import: first line of packages/engine/index.js
  • Stack: Redux, Axios — add peekr.reduxMiddleware() and peekr.watchAxios() for full coverage

Agent-WebChat-SDK

  • peekr.js: example/peekr.js
  • Import: first line of example/index.js
  • Stack: Redux, React Query — add peekr.reduxMiddleware() and peekr.watchQueryClient() for full coverage

Keep peekr.js out of your linter. Some formatters (Prettier, ESLint) will try to reformat or remove it. Add to .prettierignore and .eslintignore:

**/peekr.js

Connecting a React Native app

Step 1 — Copy peekr.js into your app

cp ~/Projects/peekr/peekr.js <your-app>/src/peekr.js

Step 2 — Add one import at the top of index.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

Step 3 — Forward the port (Android only)

adb reverse tcp:3737 tcp:3737

Run this once per emulator session. For iOS simulator, no step needed — it uses localhost automatically.

Step 4 — Reload the app

Press R in Metro or shake the device → Reload. The device appears in the peekr sidebar within 1–2 seconds.


Optional integrations

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' });

Dashboard reference

Toolbar (top of every panel)

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

Panel keyboard shortcuts

Key Panel
1 Logs
2 Network
3 Redux
4 React Query
5 Navigation
6 Custom

Network panel

  • 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

Logs panel

  • Click any long log entry to expand it fully
  • Filter by level: ALL / LOG / INFO / WARN / ERROR / DEBUG
  • Hover any row → copy button appears

Architecture

┌─────────────────────────────────────────────────────────┐
│                      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

Troubleshooting

Dashboard shows "disconnected" on refresh

The server may have stopped. Run pnpm server from ~/Projects/peekr to restart it.

Android emulator not connecting

# Check emulator is visible
adb devices

# Re-forward the port
adb reverse tcp:3737 tcp:3737

# Reload the app in Metro

iOS simulator not connecting

Make sure peekr server is running (curl http://localhost:3737/api/health). iOS uses localhost automatically — no adb needed.

Port 3737 already in use

kill $(lsof -ti:3737)
pnpm server

Port 4000 already in use (macOS AirPlay)

macOS Monterey+ uses port 5000 for AirPlay — port 4000 should be free. If not:

kill $(lsof -ti:4000)
pnpm dashboard

App connects but no events appear

Make sure import './peekr' (or import './src/peekr') is the very first import in index.js, before any other imports including react-native-reanimated.

peekr.js keeps getting removed by linter/formatter

Add to your .eslintignore / .prettierignore:

**/peekr.js

Running with Claude

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.

Releases

No releases published

Packages

 
 
 

Contributors