Deconstructing the Hyperliquid order book, from L1 to L4.
Peel is an interactive explainer that takes one live order book and lets you "peel" it through its four levels of detail, L1 to L4, with a single slider. It is built to make a hard concept obvious: what each level of order book data actually shows you, and why L4 (every individual order, with identity) is different from the aggregated data most tools stop at.
It runs on Hyperliquid order book data served over gRPC by Quicknode, and it ships with a seeded synthetic market so you can run it with no credentials.
An order book is the live list of every buy order (bid) and sell order (ask) waiting to trade. Market data feeds expose it at different resolutions, named by "level":
| Level | What it shows | What it hides |
|---|---|---|
| L1: Top of Book | Only the single best bid and best ask. The current price. | Everything resting behind the front of the line. |
| L2: Aggregated Depth | The total size resting at each price. The "walls" of supply and demand. This is what most trading screens show. | That each wall is made of many separate orders. |
| L3: Order by Order | Every individual order at each price, with its size and place in line. But anonymous. | Who owns each order, and its history. |
| L4: Full Detail | Every individual order with its identity (id, owner) and full lifecycle (placed, modified, cancelled, filled). | Nothing. This is the whole truth. |
Peel renders the same book at all four levels and morphs between them:
- L1: only the best bid and best ask remain.
- L2: every price becomes one solid bar (the total).
- L3: each bar splits into the individual orders inside it. Now you can count them.
- L4: each order is shaded by its owner, so the bar becomes a mosaic of wallets. Hover any order to see its id, size, queue position, and the address that placed it.
That L3 to L4 jump is the point: at L3 the orders are anonymous, at L4 you can follow one specific order or trader through the whole book, spot a wallet stacking orders across levels, or catch a spoof wall that appears and vanishes before it ever trades. L4 per-order streaming is the gRPC-exclusive feed from Quicknode.
- A vertical resolution slider (the "peel") that drives a continuous level
from L1 to L4. Drag the handle or press
1to4. - Owner-shaded mosaic at L4 so distinct wallets are visible.
- Hover to inspect any order: id, side, size, queue position, and owner (the popup is level-aware, so at L3 the owner is hidden and at L4 it is shown).
- Live header ticker: current price and spread, updating in real time.
- Best bid / best ask chips, a fixed value column, and whale outlines on unusually large orders.
- Sim mode (no credentials, deterministic) and live mode (Quicknode).
Browsers cannot speak gRPC, so the app is two small pieces that run together:
server/is a Node relay that connects to Quicknode's Hyperliquid gRPC order book stream and rebroadcasts a light, near-touch slice of the book over a local WebSocket. It runs in two modes:- live, when
server/.envhas a Quicknode endpoint and token, and - sim, a seeded synthetic L4 market (no credentials, fully reproducible). Keeping gRPC server-side also keeps your token out of the browser.
- live, when
web/is a Vite + TypeScript app that renders the book on a 2D canvas and the controls in clean DOM. It consumes the relay's WebSocket and is identical whether the data is live or simulated.
The relay consumes the L4 firehose cheaply (a chunked drain so the initial snapshot never blocks the event loop) and pushes only the near-touch slice to the browser on a timer, which keeps the connection light and stable.
Every level is built from Quicknode's Hyperliquid gRPC order book streams. The app subscribes to three of them and derives the fourth:
- L1 (top of book) comes from
StreamBboBook: the best bid and best ask. It also drives the live price and spread in the header. - L2 (aggregated depth) comes from
StreamL2Book: one bar per price level with the total size (sz) and the order count (n). Those bars and counts are exactly what the L2 view shows. - L4 (per order) comes from
StreamL4BookUpdates: every individual order with its id, side, price, size, and owner. The app keeps this book in memory and fills each L2 bar with the orders inside it. - L3 (per order, anonymous) is not a separate stream. It is the same
StreamL4BookUpdatesdata with the owner hidden in the UI.
So as you peel from L1 to L4 you are moving between real Quicknode streams: BBO for L1, the L2 book for L2, and the per-order L4 book for L3 and L4. In sim mode the relay emits the same three message shapes from a synthetic book, so the app code is identical either way. (All these methods live under the Hyperliquid gRPC API docs.)
Prerequisites: Node.js 22.12 or newer (the web build uses Vite 8).
# 1. install dependencies for the relay and the web app
cd server && npm install
cd ../web && npm install
cd ..
# 2. run everything with one command (sim mode if there is no server/.env)
npm run devThen open http://localhost:5173.
- The relay listens on
ws://localhost:8788, the web app onhttp://localhost:5173. - With no
server/.env, it runs the synthetic market (seed 42, deterministic). - To force sim even if a
.envexists:HL_GRPC_ENDPOINT= npm run dev.
- In the Quicknode dashboard, create a
Hyperliquid endpoint with order book (gRPC) streaming enabled. The gRPC
service is on port
10000. - Copy the example env and fill in your endpoint host and token:
cp server/.env.example server/.env
HL_GRPC_ENDPOINT=your-endpoint.hyperliquid-mainnet.quiknode.pro:10000 HL_GRPC_TOKEN=your-token HL_COIN=BTC
- Restart:
npm run dev. The header status will readlive · BTC.
Note: the L4 per-order stream (
StreamL4BookUpdates) requires order book (L4) streaming to be enabled on your endpoint. It is possible for L2, BBO, and trades to stream while L4 does not. If the book stays empty in live mode, the relay prints a warning after a few seconds. Sim mode always works.
- Drag the rail handle (or press
1,2,3,4) to peel between L1 and L4. - Hover any order in L3 or L4 to inspect it.
hl-orderbook-peel/
├── dev.mjs # one command: boots the relay + web together
├── package.json # root scripts (npm run dev)
├── SCRIPT.md # screen-recording script for the explainer video
├── server/ # gRPC -> WebSocket relay (Node)
│ ├── relay.js # live (Quicknode gRPC) + seeded sim, same wire format
│ ├── proto/ # Hyperliquid order book + core gRPC protos
│ └── .env.example # copy to .env to go live
└── web/ # Vite + TypeScript + Canvas2D front end
└── src/
├── peel.ts # the renderer + slider control
├── feed.ts # WebSocket client + order-book state
└── main.ts # bootstrap + header ticker
Node, ws, @grpc/grpc-js, @grpc/proto-loader, Vite, TypeScript, Canvas2D.
Type uses open-licensed fonts: Cormorant Garamond for the heading, Inter for
body text, and Geist Mono for figures.
- Unofficial. Built on Quicknode's Hyperliquid gRPC streams.
- In sim mode the owner addresses are synthetic. Live mode shows real addresses.
MIT.