A drop-in React re-render debugger with visual overlay, stack traces, and an MCP server for AI IDEs like Claude Code and Cursor.
React developers waste hours debugging unnecessary re-renders. Existing tools lack stack traces, structured output, and AI-native integration. Pulse gives you:
- Zero-config setup - one import, works with React 17-19
- Visual overlay - floating panel with sortable stats, render count badges, timeline heatmap
- Stack traces - per-render stack traces so you know why a component re-rendered
- Component highlighting - hover a row in the panel to highlight the component on the page
- Inspect mode - click the crosshair button, hover on any component on the page to identify it
- Unnecessary render detection - flags re-renders caused by parent updates with no prop changes
- MCP server - 5 tools for Claude Code and Cursor to query render data, get optimization suggestions
- CLI -
analyzeJSON exports, enforce render budgets in CI
The fastest way to get started — the CLI installs packages, injects code, and configures MCP for you:
npm install -g @pulse-org/cli
pulse initThat's it. The CLI will:
- Install
@pulse-org/reactand@pulse-org/overlayin your project - Add the init snippet to your entry file
- Optionally set up the MCP server for AI IDE integration
Use pulse init --basic to skip MCP server registration.
npm install @pulse-org/react @pulse-org/overlayImport before React in your entry file (e.g. main.tsx):
// Must be imported BEFORE React
import { init } from "@pulse-org/react";
import { createOverlay } from "@pulse-org/overlay";
const store = init({
captureStackTraces: true,
consoleLog: false,
});
createOverlay({ store });
// Now import React
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
ReactDOM.createRoot(document.getElementById("root")!).render(<App />);Open your app and you'll see the Pulse panel in the bottom-right corner.
If you prefer zero-code setup, import the auto entry:
// Must be the very first import
import "@pulse-org/react/auto";Configure via a global before the import:
<script>
window.__PULSE_CONFIG__ = {
captureStackTraces: true,
wsUrl: "ws://localhost:9855", // optional: connect to MCP server
};
</script>| Package | Description |
|---|---|
@pulse-org/react |
Zero-dep tracking engine. Hooks into React via DevTools global hook. |
@pulse-org/overlay |
Pure DOM visual UI. Shadow DOM panel, badges, timeline, highlighting. |
@pulse-org/mcp-server |
Node.js MCP server. Receives data via WebSocket, exposes 5 MCP tools. |
@pulse-org/cli |
CLI. serve, analyze, budget commands. |
init({
// Enable/disable tracking (default: true)
enabled: true,
// Capture stack traces per render (default: true)
captureStackTraces: true,
// Max stack frames to capture (default: 15)
maxStackFrames: 15,
// Max recent events per component (default: 50)
maxRecentEvents: 50,
// Only track components matching these patterns
include: [/^MyApp/, /Button/],
// Exclude components matching these patterns
exclude: [/^styled\./],
// WebSocket URL for MCP server (default: null)
wsUrl: "ws://localhost:9855",
// Log renders to console (default: false)
consoleLog: false,
// Callback per render event
onRender: (event) => {
console.log(event.componentName, event.trigger.type);
},
});createOverlay({
// Provide a RenderStore instance (uses global store if omitted)
store,
// Show the floating stats panel (default: true)
showPanel: true,
// Show render-count badges on component DOM nodes (default: false)
showBadges: false,
// Show the render timeline chart (default: true)
showTimeline: true,
// Panel position (default: "bottom-right")
panelPosition: "bottom-right", // | "bottom-left" | "top-right" | "top-left"
});claude mcp add pulse -- npx @pulse-org/mcp-serverAdd to your MCP config (.cursor/mcp.json):
{
"mcpServers": {
"pulse": {
"command": "npx",
"args": ["@pulse-org/mcp-server"]
}
}
}Add wsUrl to your init config:
init({
wsUrl: "ws://localhost:9855",
});| Tool | Description |
|---|---|
get_render_stats |
Global stats: total renders, unnecessary renders, per-component breakdown |
get_top_rerenderers |
Top N components by renders, duration, or unnecessary renders |
get_component_detail |
Deep dive: recent events with stack traces, prop changes, timing |
get_optimization_suggestions |
Rule-based suggestions: memo, context splitting, stable keys, etc. |
clear_stats |
Reset all collected data |
One command to set up everything — installs packages, injects code, and configures MCP:
npm install -g @pulse-org/cli
pulse init # full setup: packages + code + MCP
pulse init --basic # skip MCP server registration# Start WebSocket server for render event collection
pulse serve --port 9855
# Analyze render events from a JSON export
pulse analyze --input renders.json
# Enforce render budgets in CI (exits 1 on violations)
pulse budget --input renders.json --config pulse.config.jsonCreate pulse.config.json:
{
"budgets": [
{ "component": "ExpensiveList", "maxRenders": 20, "maxAvgDurationMs": 16 },
{ "component": "Sidebar", "maxRenders": 5 }
]
}Pulse includes a demo app with intentional re-render problems:
git clone <repo>
cd react-render-pulse
pnpm install
pnpm build
cd examples/demo-app
pnpm devOpen http://localhost:5173 and interact with the app to see the overlay in action.
See INTERNALS.md for a detailed technical breakdown of how Pulse works under the hood.
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Watch mode for core tests
pnpm --filter @pulse-org/react test:watch
# Dev mode for a specific package
pnpm --filter @pulse-org/react devMIT