Next.js App Router integration for streaming browser console logs to your dev terminal.
Since Turbopack doesn't use Vite, this package provides a tiny route handler and an early script component to patch console.* methods and forward logs to your development server.
- Next.js App Router compatible
- Early script injection for immediate log capture
- Route handler for receiving browser logs
- Automatic setup command
- Works with Turbopack
- No production impact
npm install -D @browser-echo/next
# or
pnpm add -D @browser-echo/nextRun the setup command to automatically create the route file:
npx @browser-echo/next setup
# or
pnpm dlx @browser-echo/next setupThis creates app/api/client-logs/route.ts with the necessary exports.
Configure the <BrowserEchoScript /> component with these options:
type BrowserLogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
interface BrowserEchoScriptProps {
enabled?: boolean; // default: true (dev only)
route?: `/${string}`; // default: '/api/client-logs'
include?: BrowserLogLevel[]; // default: ['log','info','warn','error','debug']
preserveConsole?: boolean; // default: true (also keep logging in the browser)
tag?: string; // default: '[browser]'
// stacks
stackMode?: 'none' | 'condensed' | 'full'; // default: 'condensed'
showSource?: boolean; // default: true (when available)
// batching
batch?: { size?: number; interval?: number }; // default: 20 / 300ms
// Opt-in network capture (fetch/XHR/WS)
networkLogs?: {
enabled?: boolean;
captureFull?: boolean;
bodies?: {
request?: boolean;
response?: boolean;
maxBytes?: number; // default 2048 bytes
allowContentTypes?: string[]; // default ['application/json','text/','application/x-www-form-urlencoded']
prettyJson?: boolean; // default true
};
};
}enabled: Toggle the entire functionality (automatically disabled in production)route: The endpoint path where logs are sent (must match your route file location)include: Which console methods to capture and forwardpreserveConsole: Whether to keep original console behavior in the browsertag: Prefix for terminal output to identify browser logsstackMode: How much stack trace information to include'none': No stack traces'condensed'(default): Essential stack info only'full': Complete stack traces
showSource: Include source file location hints (file:line:col)batch: Control log batching behaviorsize: Max logs per batch (default: 20)interval: Max time between batches in ms (default: 300)
Here's how to use <BrowserEchoScript /> with custom options:
// app/layout.tsx
import type { ReactNode } from 'react';
import BrowserEchoScript from '@browser-echo/next/BrowserEchoScript';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<head>
{process.env.NODE_ENV === 'development' && (
<BrowserEchoScript
route="/api/client-logs"
include={['warn', 'error']}
preserveConsole={true}
tag="[NextJS Browser]"
stackMode="condensed"
showSource={true}
batch={{ size: 10, interval: 500 }}
networkLogs={{
enabled: true,
bodies: { request: true, response: true, maxBytes: 2048 }
}}
/>
)}
</head>
<body>{children}</body>
</html>
);
}This configuration:
- Sends logs to
/api/client-logsendpoint - Only captures warnings and errors (filters out debug/info/log)
- Keeps original console behavior in browser
- Tags terminal output with
[NextJS Browser] - Uses condensed stack traces for cleaner output
- Shows source file locations
- Batches up to 10 logs every 500ms
Render the script in your root layout head (dev-only):
// app/layout.tsx
import type { ReactNode } from 'react';
import BrowserEchoScript from '@browser-echo/next/BrowserEchoScript';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<head>
{process.env.NODE_ENV === 'development' && <BrowserEchoScript />}
</head>
<body>{children}</body>
</html>
);
}Forward logs to your terminal via a dedicated route:
// app/api/client-logs/route.ts
export { POST, runtime, dynamic } from '@browser-echo/next/route';- Default route is
/api/client-logs(works best in Next.js 15+) - We set
runtime = 'nodejs'anddynamic = 'force-dynamic'to ensure it runs on Node and isn't cached
Complete setup example:
// app/layout.tsx
import type { ReactNode } from 'react';
import BrowserEchoScript from '@browser-echo/next/BrowserEchoScript';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<head>
{process.env.NODE_ENV === 'development' && (
<BrowserEchoScript
route="/api/client-logs"
include={['warn', 'error']}
stackMode="condensed"
/>
)}
</head>
<body>{children}</body>
</html>
);
}// app/api/client-logs/route.ts
export { POST, runtime, dynamic } from '@browser-echo/next/route';Next.js automatically discovers and forwards logs to MCP servers. No configuration needed in most cases!
📖 First, set up the MCP server for your AI assistant, then configure framework options below.
The Next.js route handler automatically detects MCP servers and forwards logs when available. When MCP is detected, terminal output is suppressed by default.
Discovery order:
BROWSER_ECHO_MCP_URL(normalized, trailing/mcpis stripped)- Dev probe:
http://127.0.0.1:5179thenhttp://localhost:5179 - Project-local discovery file:
.browser-echo-mcp.json(walks up parent directories)
BROWSER_ECHO_MCP_URL=http://127.0.0.1:5179/mcp— Set MCP server URL (base URL is derived automatically). When set, the route will forward; terminal printing is suppressed unless explicitly disabled.BROWSER_ECHO_SUPPRESS_TERMINAL=1— Force suppress terminal outputBROWSER_ECHO_SUPPRESS_TERMINAL=0— Force show terminal output even when MCP is active
// app/api/client-logs/route.ts
import { POST as BasePost } from '@browser-echo/next/route';
// Custom handler without MCP discovery
export async function POST(request: NextRequest) {
// Set environment to disable MCP
const originalMcpUrl = process.env.BROWSER_ECHO_MCP_URL;
delete process.env.BROWSER_ECHO_MCP_URL;
const result = await BasePost(request);
// Restore original env
if (originalMcpUrl) process.env.BROWSER_ECHO_MCP_URL = originalMcpUrl;
return result;
}
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';<BrowserEchoScript />injects client-side code that patches console methods- Browser logs are batched and sent to your route endpoint
- The route handler receives logs and prints them to your terminal
- Only active in development mode
If you change the route path, update both places:
// Use custom route in script
<BrowserEchoScript route="/api/my-logs" />// Create matching route file: app/api/my-logs/route.ts
export { POST, runtime, dynamic } from '@browser-echo/next/route';This package depends on @browser-echo/core for the client-side functionality.
- The provider prints to stdout—great for local dev and AI assistants
- If you need file logging in Next.js, you can wrap the exported
POSThandler and write to disk as needed - The setup works with both Pages Router and App Router, but this package is optimized for App Router
- No logs appear: Make sure
app/api/client-logs/route.tsis exported and<BrowserEchoScript />is rendered in<head> - Endpoint 404: Verify your route file path matches the script's
routeprop - Too noisy: Limit to
include: ['warn','error']and usestackMode: 'condensed'
MIT
