Monitor fetch requests AND hook intent in Next.js apps β catch mismatches other tools miss
Demo β’ Installation β’ Documentation β’ Case Studies β’ Contributing
Other tools show you network requests. HooksLens shows you the story behind them.
Chrome DevTools shows what fetched. HooksLens shows what hook registered, what it expected, and what actually happened β then flags the mismatches.
You refactor a hook to use productId instead of product. Your API returns 400. Chrome DevTools shows the failed request. HooksLens shows you registered useProduct expecting productId, but the fetch sent product β instant root cause.
Open /hookslens in development to access:
- Fetch Tracking β Monitor all HTTP requests,
useEffectfetches, and API calls - Performance Detection β Automatically flag slow (>1s) and stalled (>5s) requests
- Duplicate Detection β Find redundant API calls across your app
- Error Monitoring β Track 4xx/5xx responses and network failures
- Timeline View β Visualize request waterfalls and concurrency
- Route Filtering β Focus on specific Next.js routes
- Hook Registry β See which hooks registered (names, descriptions, expected parameters)
- Intent vs Reality β Compare what hooks expected vs what actually fetched
- Mismatch Detection β Auto-flag parameter mismatches (
productIdvsproduct) - Polling Detection β Identify hooks with
refreshIntervalconfigured - Cache Status β Monitor fresh/stale/error states per hook
- Mutation Tracking β Monitor
useSWRMutationcalls
The HooksLens dashboard/panel includes:
| Component | Description |
|---|---|
| Topbar | Theme toggle, live connection state, diagnostic indicators |
| Sidebar | Statistics grid and route navigation |
| Registry Table | Hook status, instance counts, polling intervals, fetch timing |
| Timeline Panel | Event visualization with filtering and flagged patterns |
Note: Theme preferences are automatically persisted in
localStorage.
src/
app/hookslens/
page.tsx
panel.css
components/
Topbar.tsx
Sidebar.tsx
HooksTable.tsx
TimelinePanel.tsx
hooks/
useInsightSnapshot.ts
lib/
format.ts
lib/
hookslens/
store.ts
middleware.ts
fetchObserver.ts
useHooksLens.ts
flowchart LR
A[Next.js app route] --> B[SWR hooks]
A --> C[useEffect or raw fetch]
B --> D[hooksLensMiddleware]
C --> E[installFetchObserver wrapper]
D --> F[hooksLensStore]
E --> F
F --> G[Snapshot hook useInsightSnapshot]
G --> H[hookslens panel views]
F <--> I[BroadcastChannel sync]
A standalone mock demo is included in hookslens-demo.jsx for quick UI exploration.
Demo Features:
- Static mock data for UI preview (not connected to runtime)
- Common SWR debugging scenarios: parameter mismatches, duplicate fetches, stalled polling, concurrent requests
- Works in any React sandbox or local React app
Note: The demo currently includes placeholder data. The patterns shown (duplicates, mismatches, stalling) apply to any Next.js + SWR application.
Run locally:
npm install
npm run demoThen open the printed local URL (default: http://127.0.0.1:5173/ or http://localhost:5173/).
npm i hookslens --save-devWhat's included:
installFetchObserver()β Tracks allfetch()calls (works standalone)hooksLensMiddlewareβ SWR middleware (optional, for SWR users)hookslens/panelβ Dashboard component for Next.js App Router
Choose the setup that matches your stack:
Perfect for Next.js apps using fetch, useEffect, or any HTTP library.
Step 1: Install the fetch observer
// src/app/providers.tsx
"use client";
import { useEffect } from "react";
import { installFetchObserver } from "hookslens";
export function Providers({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (
typeof window !== "undefined" &&
process.env.NODE_ENV === "development"
) {
installFetchObserver();
}
}, []);
return <>{children}</>;
}Step 2: Add the dashboard route
// src/app/hookslens/page.tsx
"use client";
import HooksLensPanel from "hookslens/panel";
export default function Page() {
if (process.env.NODE_ENV !== "development") return null;
return <HooksLensPanel />;
}Done! Navigate to /hookslens to see all your fetch calls.
Includes everything from Option A plus SWR-specific features.
Step 1: Wire both fetch observer and SWR middleware
// src/app/providers.tsx
"use client";
import { useEffect, ReactNode } from "react";
import { SWRConfig } from "swr";
import { installFetchObserver, hooksLensMiddleware } from "hookslens";
interface SWRProviderProps {
children: ReactNode;
}
export const SWRProvider = ({ children }: SWRProviderProps) => {
useEffect(() => {
if (
typeof window !== "undefined" &&
process.env.NODE_ENV === "development"
) {
installFetchObserver();
}
}, []);
const swrUse =
process.env.NODE_ENV === "development" ? [hooksLensMiddleware] : [];
return <SWRConfig value={{ use: swrUse }}>{children}</SWRConfig>;
};Optional: Label custom hooks for better tracking:
import { useHooksLens } from "hookslens";
export function useProductReviews(productId: string) {
useHooksLens({
name: "useProductReviews",
description: "Fetches paginated product reviews",
fetchKey: `/api/reviews?productId=${productId}`,
});
return useSWR(["/api/reviews", { productId }], fetcher);
}Step 2: Add the dashboard route
// src/app/hookslens/page.tsx
"use client";
import HooksLensPanel from "hookslens/panel";
export default function Page() {
if (process.env.NODE_ENV !== "development") return null;
return <HooksLensPanel />;
}Done! Navigate to /hookslens to see all your fetch calls.
Includes everything from Option A plus SWR-specific features.
Step 1: Wire both fetch observer and SWR middleware
// src/app/providers.tsx
"use client";
import { useEffect, ReactNode } from "react";
import { SWRConfig } from "swr";
import { installFetchObserver, hooksLensMiddleware } from "hookslens";
interface SWRProviderProps {
children: ReactNode;
}
export const SWRProvider = ({ children }: SWRProviderProps) => {
useEffect(() => {
if (
typeof window !== "undefined" &&
process.env.NODE_ENV === "development"
) {
installFetchObserver();
}
}, []);
const swrUse =
process.env.NODE_ENV === "development" ? [hooksLensMiddleware] : [];
return <SWRConfig value={{ use: swrUse }}>{children}</SWRConfig>;
};Optional: Label custom hooks for better tracking:
import { useHooksLens } from "hookslens";
export function useProductReviews(productId: string) {
useHooksLens({
name: "useProductReviews",
description: "Fetches paginated product reviews",
fetchKey: `/api/reviews?productId=${productId}`,
});
return useSWR(["/api/reviews", { productId }], fetcher);
}Create the HooksLens panel route in your app:
// src/app/hookslens/page.tsx
import HooksLensPanel from "hookslens/panel";
// OR do this: import HooksLensPanel from "dist/local-lib/src/app/hookslens/page"
export default function Page() {
return <HooksLensPanel />;
}Then open:
http://localhost:3000/hookslens
π‘ Best Practice: HooksLens is designed for development use only:
- Enable middleware conditionally in development
- Install fetch observer only in development
- Keep
/hookslensroutes restricted to development environments
Available commands:
npm install
npm run dev
npm run build
npm run build:local-lib
npm test
npm run test:watch
npm run pack:checkNote: The local-lib panel page is auto-generated from source files via
scripts/build-local-lib.mjs.
Test coverage includes:
useHooksLens.test.tsβ Hook registration and lifecyclefetchObserver.test.tsβ Fetch interception logicstore.test.tsβ State managementmiddleware.test.tsβ SWR middleware integration
Supported patterns:
src/**/__tests__/**/*.{test,spec}.{ts,tsx}
src/**/*.{test,spec}.{ts,tsx}
Commands:
npm test # Run once (CI/publish-safe)
npm run test:watch # Watch mode
npm run test:ui # Interactive UIHooksLens builds upon the React and network debugging ecosystem with real-time fetch monitoring for Next.js apps.
Complementary tools:
| Tool | Focus | Link |
|---|---|---|
| React DevTools | Component & hooks inspection | docs |
| Chrome DevTools | Network request debugging | docs |
| SWR | Cache & revalidation | docs |
| SWR Middleware | Extension point (used by HooksLens) | docs |
| OpenTelemetry JS | Observability patterns | docs |
What makes HooksLens unique:
- π Monitors all fetch calls, not just network panel snapshots
- π― Shows hook registration intent alongside request outcomes (with SWR)
- π£οΈ Route-level debugging context for Next.js apps
- β±οΈ Timeline visualization with duplicate/mismatch detection
| Limitation | Description |
|---|---|
| Development-only | Designed for local/staging diagnostics, not production telemetry |
| Causality depth | Shows sequence and overlap, not full dependency-cause graphs |
| Browser API dependency | Cross-tab sync uses BroadcastChannel (graceful degradation when unavailable) |
| Client-side focus | Tracks browser fetch calls; server-side patterns not fully represented |
| Manual baseline | Missing hook detection is visual/observational without custom assertions |
HooksLens may not be the right tool if you need:
- β Production-grade distributed tracing across backend services
- β Support for non-Next.js frameworks (designed for Next.js App Router)
- β Rendering performance profiling (use React Profiler instead)
- β Zero runtime instrumentation in development
- β Debugging server actions, server components, or non-fetch transports (e.g., GraphQL over custom clients)
Our focus is on closing critical debugging gaps:
-
Revalidation Cause Tracing Annotate events with trigger sources (focus, reconnect, interval, mutate, mount, key change)
-
Effect Trigger Context Capture lightweight cause hints for external fetches (route transitions, visibility changes, user actions)
-
Expected Hook Baseline Checks Define expected hook presence per route and flag missing hooks after refactors
-
CI-Safe Regression Summary Export diagnostics snapshots for PR checks to catch unexpected hook disappearance and duplicate patterns
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the terms specified in the LICENSE file.
Parts of this project were developed with assistance from generative AI tools, including Claude.
