Raw book diffs
Every order-book delta (new, update, modified, remove) for full reconstruction.
The lowest-level book surface: every change to every order book, as it happened. Pair with a snapshot to reconstruct the exact book state at any block; the basis of queue-position and microstructure research. Over 1B book updates archived so far.
- Method
- hyperliquid.Streaming/StreamData (stream_type: BOOK_UPDATES)
- Endpoint
- stream.hyperliquidrpc.com:443 · gRPC over TLS (HTTP/2)
- Auth
- API key in x-api-key metadata
- Volume
- The highest-volume stream: every book change on every market. Filter by coin unless you genuinely need the firehose.
When to use it
This is the research-grade surface: every change to every order book, as it happened, in strict block order. Use it when the L4 book's per-coin subscriptions are the wrong shape: cross-market microstructure studies, building your own book-keeping engine with custom data structures, or recording the raw delta tape for later replay against strategies.
If you just want a correct live book for a handful of coins, the L4 stream does the snapshot bookkeeping for you and is the easier choice. Diffs alone are not a book; you must pair them with a snapshot to have state to apply them to.
Method
// stream.hyperliquidrpc.com:443 — gRPC over TLS (HTTP/2)// auth: API key in x-api-key metadata · server reflection enabledpackage hyperliquid; service Streaming { // Bidirectional: send one subscription, then read updates. // Subscribe with stream_type: BOOK_UPDATES. rpc StreamData (stream SubscribeRequest) returns (stream SubscribeUpdate);}QuickNode-compatible StreamData with stream_type: BOOK_UPDATES. Each update carries the block number and the delta payload as JSON.
Subscribe
# StreamData is bidirectional; grpcurl sends the subscription for you.grpcurl -H 'x-api-key: YOUR_KEY' \ -d '{"subscribe":{"stream_type":"BOOK_UPDATES","filters":{"coin":{"values":["BTC"]}}}}' \ stream.hyperliquidrpc.com:443 \ hyperliquid.Streaming/StreamDataUnfiltered, this is the highest-volume stream we serve, with over 1B book updates archived so far. Subscribe with a coin filter unless you genuinely need every market.
Message fields
Fields typed string that carry numbers are byte-exact decimal strings, verbatim from the node. Compare and store them as strings or arbitrary-precision decimals. Never parseFloat a price you intend to reconcile.
Server-side filters
- coins[]
- replay from a block height
Filters are applied on the server, so filtered-out messages never leave our edge. You only pay for what you subscribe to. Request shapes for every stream family are on Filtering; backfill semantics on Replay & backfill.
Semantics & gotchas
Pure delta stream in strict block order. Apply deltas to a snapshot (from StreamL4Book or the historical archive) for exact reconstruction.
- Deltas without a snapshot are not a book. Take an initial state from the L4 stream's snapshot (or the historical archive at a chosen block), then apply deltas with
block_heightgreater than the snapshot's. - Apply strictly in block order. Deltas are emitted in order; if your pipeline buffers or shards, re-serialize by
block_heightbefore applying or the book silently diverges. - sz is the size after the change.
MODIFIED/UPDATEcarry the new remaining size, and removals leaveszat 0. Keep your apply logic to “set, don't add.” - Every delta is wallet-attributed.
useron each change means placement and cancellation behavior is analyzable per firm, not just per price level.
Sample message
{ "block_height": 612408136, "coin": "BTC", "update_type": "MODIFIED", "oid": 91834220771, "user": "0x5d20af913cc01b76e4a8f20de33c197a40b8e641", "side": "B", "px": "67009.0", "sz": "0.40000"}The highest-volume stream: every book change on every market. Filter by coin unless you genuinely need the firehose.
Recipes
Reconstruct the exact book at any block
Snapshot once, then fold deltas forward to your target height. The result is byte-exact: the same px and sz strings the node emitted.
book = load_l4_snapshot("BTC") # from StreamL4Book or the archive for update in stub.StreamData(iter([subscribe]), metadata=meta): d = json.loads(update.data.data) if d["block_height"] <= book.height: continue # already inside the snapshot apply_delta(book, d) # set by oid; remove when update_type == "REMOVE"Record the delta tape for offline replay
Append each JSON delta to date-partitioned files keyed by block_height. Strategies can then be replayed against the exact sequence of book states they would have observed, with no resampling artifacts.
Order-flow imbalance per block
Group deltas by block_height and net the added versus removed size per side. Spikes in one-sided cancellation ahead of price moves are visible only at this granularity.