Skip to content
v0.12.0
v0.12.0What's new

Your app's traffic, inside your app.

Blix is an open-source devtools panel that renders inside your React app. Network requests from axios or fetch, Redux actions, TanStack Query and realtime messages, in one style-isolated overlay that links them together.

pnpm add -D @hakam-aldeen-kh/blix
localhost:3000blixcapturing

This is Blix itself, running on a demo app. Click rows, switch tabs, press Ctrl K.

Works with
  • React 18 & 19
  • Next.js App Router
  • axios
  • fetch
  • Redux Toolkit
  • TanStack Query
  • Realtime adapters

The problem

One click, spread across three devtools.

The request is in the browser's Network tab. The action is in the Redux extension. The cache entry is in Query Devtools. None of them know about each other, and none of them sit where you click.

ToolWhere it runsWhat it can't see
Browser DevTools, Network tabA separate windowYour Redux state and query cache
Redux DevToolsA browser extensionThe requests behind each action
TanStack Query DevtoolsIts own in-page widgetThe request that fed each query
blixInside your appNetwork, Realtime, Redux and Query, linked

01 / 04 · Network

Every request, from axios or fetch.

Filter with a query syntax, then act on a request without leaving the row. Encrypted payloads sit next to their decrypted form.

method:postis:errorurl:orders-status:2xx
Replay
Send the request again through your own client.
cURL
Copy it as cURL, or as fetch from the context menu.
JWT
Bearer tokens decoded in place: subject, issuer, time to expiry.
Encrypted
The ciphertext your interceptors produced, next to the plaintext.

02 / 04 · Realtime

Sockets, frame by frame.

Each connection is one row. Its Messages tab lists every frame with its direction, event and size, from connect to disconnect.

↓ in
Frames the server pushed.
↑ out
Subscriptions your app sent.
system
Connect, presence and disconnect.

03 / 04 · Redux

Every action, and what it changed.

The Diff tab is a unified diff: each changed path with its before and after. State shows the live store, scoped by slice.

Diff
Changed paths, line by line, with +n −n counts.
State
The live store, with the slices this action touched marked.
Re-dispatch
Run the action again against the current store.

04 / 04 · Query

The cache, with its history.

One row per query key, for the whole session. The Timeline shows every fetch, success, error and invalidation, and the header counts its observers.

Invalidate
Mark a query stale and refetch it.
Timeline
Every state change for one query key.
Linked
Jump to the request its queryFn made.
localhost:3000blixcapturing

Linked

A query knows which request fed it.

When Blix sees the request behind a TanStack Query fetch, it records the link. Follow it and the panel jumps to that request, selected, with its payload and response. Separate devtools can't do this because they never see both sides.

localhost:3000blixcapturing

Click something. Watch it land.

A small demo app on the left, the real Blix on the right. Each button makes a real axios, fetch, Redux, Query or socket call, and the row appears in its source as it happens.

localhost:3000blixcapturing
localhost:3000/demo

Demo store

A fake app. Responses are simulated.

0 events captured
localhost:3000blixcapturing

Keyboard

Built for the keyboard.

Every action in the panel is a command, and the palette shows each one's shortcut where it has one. The panel on the left is live: open the palette, type to filter, arrow to select, enter to run.

CtrlK
Open the command palette
↑↓
Move through rows
14
Jump between sources
?
Every shortcut, on one sheet
Ctrl`
Show or hide the panel

Install

Four steps in the Next.js App Router.

Install the package, attach capture where your client is built, wrap the panel in a client component, then render that wrapper in your root layout. Using fetch instead of axios? Call attachFetchMonitor() once on the client.

Paste into Claude Code, Cursor or Copilot and let it run all four steps.
  1. Step 1: Install

    As a dev dependency. It has to be present at build time; nothing from it reaches production output.

    terminalsh
    pnpm add -D @hakam-aldeen-kh/blix
  2. Step 2: Attach capture at module scope

    Where the client is constructed, after your own interceptors. Import capture from /capture, which carries no client boundary.

    src/network/axios.tsts
    import axios from "axios";
    import { attachHttpMonitor } from "@hakam-aldeen-kh/blix/capture";
    export const apiClient = axios.create({ baseURL: "/api" });
    apiClient.interceptors.request.use(addAuthHeader);
    // After your own interceptors, at module scope.
    if (process.env.NODE_ENV === "development" && typeof window !== "undefined") {
    attachHttpMonitor(apiClient);
    }
  3. Step 3: Create a client wrapper

    BlixMount.tsx starts with "use client". The panel runs in the browser, so this boundary is required.

    app/BlixMount.tsxtsx
    "use client";
    import { Blix } from "@hakam-aldeen-kh/blix";
    import { apiClient } from "@/src/network/axios";
    import { store } from "@/src/store";
    export default function BlixMount() {
    if (
    process.env.NODE_ENV !== "development" &&
    process.env.NEXT_PUBLIC_BLIX !== "true"
    )
    return null;
    return <Blix store={store} apiClient={apiClient} dbName="my-app" />;
    }
  4. Step 4: Render it in the root layout

    layout.tsx is a server component. It renders the wrapper and never imports Blix directly.

    app/layout.tsxtsx
    import BlixMount from "./BlixMount";
    export default function RootLayout({ children }) {
    return (
    <html lang="en">
    <body>
    {children}
    <BlixMount />
    </body>
    </html>
    );
    }

Production

Zero cost in production.

The NODE_ENV guards in Blix survive the build into dist/, so your bundler sees them and drops the panel from production output. Nothing to configure, nothing to strip. Need it on a staging server? Build that one with NEXT_PUBLIC_BLIX=true.

dist/index.jsjs
// excerpt
if (
mounted &&
(process.env.NODE_ENV === "development" ||
(typeof process !== "undefined" &&
!!process.env &&
process.env.NEXT_PUBLIC_BLIX === "true"))
) {
panelRef.current ??= lazy(() => import("./DevToolsPanel-JUWNT5QO.js"));
}

Blix, per build

BuildEnvBlixNote
next devNODE_ENV=developmentmounted
next buildNODE_ENV=productionremoved
next buildNEXT_PUBLIC_BLIX=truemountedstaging
Production cost
Guards are kept in the published build and tree-shaken by your bundler. Production users download none of it.
Style isolation
The panel portals outside your stacking contexts and paints only from its own themes. Your app's CSS never reaches it.
Footprint
No UI libraries, and one wrapper component to remove if you ever want to.

FAQ

Before you install.

Something missing? Open an issue on GitHub.

Does Blix ship to my users?
No. The panel sits behind a literal process.env.NODE_ENV check that survives into the published build, so your bundler folds it to false and drops the panel, its chunk and its styles. Guard your capture call sites the same way and nothing reaches production. The one way to keep it is opt-in: a staging build made with NEXT_PUBLIC_BLIX=true ships the panel, so set it to false for the build your users get.
Which React version do I need?
React and react-dom 18 or 19. axios, Redux Toolkit and TanStack Query are optional peers: install only the ones you capture. A fetch-only app needs none of them.
What does it capture?
HTTP from axios interceptors or from fetch, Redux actions with a diff of what they changed, TanStack Query cache events, and realtime traffic from any adapter with connect, disconnect, subscribe, onMessage and onPresenceUpdate.
Is anything written to disk?
Not by default. Preserve log is off, so the log lives in memory and a reload starts clean. Switch it on and the log goes to IndexedDB, in blix:<dbName>, including what was already captured. Four headers are masked: authorization, cookie, set-cookie and x-api-key. Any other header is captured as sent.
Will its styles clash with my app?
No. The panel portals outside your app's stacking contexts and ships its own fourteen themes. By default it follows your app's light or dark class, with Blix or Blix Light.
Is it free?
Yes. MIT licensed and published on the public npm registry.

Put it in the app you're debugging.

pnpm add -D @hakam-aldeen-kh/blix