Documentation

Hyperliquid WebSocket Streams

Every Hyperliquid WebSocket stream on Supanode: the full book, incremental updates, best bid and offer, trades, the per-order book, raw book diffs, order statuses and mid prices.

// updated 2026-09-24

Eight streams, all on one connection. Almost every subscribe message uses the same envelope:

{ "method": "subscribe", "subscription": { "type": "STREAM_NAME", "coin": "BTC" } }

The two exceptions are allMids, which covers every market and takes no coin, and orderUpdates, which follows an address rather than a market.

StreamWhat it carries
l2BookThe full book by price level, up to 1000 levels per side
l2DiffThe same book as a snapshot plus incremental changes
bboBest bid and offer only
tradesExecuted trades
l4BookThe book order by order, with owner addresses
bookDiffsRaw book diffs from the node
orderUpdatesStatus changes of orders
allMidsMid price for every market

l2Book

The whole book, aggregated by price level.

{ "method": "subscribe", "subscription": { "type": "l2Book", "coin": "BTC", "nLevels": 100 } }

A frame:

{ "channel": "l2Book",
  "data": { "coin": "BTC", "time": 1787495871629, "nLevels": 20,
            "levels": [ [ {"px":"77488.0","sz":"18.36223","n":1} ],
                        [ {"px":"77492.0","sz":"0.51","n":2} ] ] } }
FieldMeaning
levels[0]bids, best price first
levels[1]asks, best price first
pxprice of the level, as a string
sztotal size resting at that level
nhow many orders make up that level
timeserver timestamp in milliseconds
nLevelshow many levels this frame carries per side

Depth. nLevels is optional and defaults to 20. The maximum is 1000.

WARNING

time is not a unique identifier. It is the block time, and a block is applied over several flushes, so two frames can carry the same time and still differ. Use the arrival order to tell frames apart - or l2Diff and l4Book, which carry a height that does identify the state.

l2Diff

The same book as l2Book, same parameters, sent as one snapshot and then only the levels that changed. At 1000 levels that is about 113× less traffic, and the rebuilt book is identical level for level. Use it whenever you want depth.

{ "method": "subscribe", "subscription": { "type": "l2Diff", "coin": "BTC", "nLevels": 1000 } }

data holds either a Snapshot (the whole book, shaped like l2Book) or Updates (per side, upd as [px, sz, n] triples and del as bare prices). If an update's prevHeight does not match the last height you applied, you missed a frame: resubscribe to get a fresh snapshot.

Frame formats, continuity rules and the traffic measurements are on their own page: l2Diff: the incremental book.

bbo

Best bid and best offer only, pushed as the top of the book changes. The lightest stream here — use it when you need a price, not a book.

{ "method": "subscribe", "subscription": { "type": "bbo", "coin": "BTC" } }

A frame:

{ "channel": "bbo",
  "data": { "coin": "BTC", "time": 1788944430011,
            "bid": {"px":"79613","sz":"1.90375","n":6},
            "ask": {"px":"79614","sz":"13.83401","n":54} } }

bid and ask are single objects, not lists, in the same px / sz / n shape as a level of l2Book.

WARNING

This frame differs from the public Hyperliquid API. The public API returns one field, bbo, holding a list of two. We return two separate fields, bid and ask. Code written against their documentation will not find data["bbo"] here. Every other stream on this page keeps their shape.

trades

Executed trades as they are matched.

{ "method": "subscribe", "subscription": { "type": "trades", "coin": "BTC" } }

A frame:

{ "channel": "trades",
  "data": [ { "coin": "BTC", "side": "B", "px": "79614.0", "sz": "0.00035",
              "hash": "0xe28cff12f5267aeae406044403fac902054d00f890...",
              "time": 1788944433313, "tid": 1066813006098562,
              "users": ["0x807e5727654ec56e3c7bb3f3779a7a7787ada4cd",
                        "0x2cffce91b4e0c81df18726ff66b31b2b1545e1ad"] } ] }
FieldMeaning
dataa list — one frame can carry several trades
sideB for a buy, A for a sell
px / szprice and size of the trade
hashtransaction hash
tidtrade id
timetimestamp in milliseconds
usersthe two addresses on the two sides of the trade

l4Book

The book order by order rather than aggregated by price: every resting order with its price, size, id and the address that owns it. This is the deepest view of the market that exists.

{ "method": "subscribe", "subscription": { "type": "l4Book", "coin": "BTC" } }

The first message is a full snapshot, then changes stream on every block. There is no depth parameter here — nLevels does not apply to l4Book, which always carries the whole book order by order.

A snapshot, cut down to one order per side — a real one carries hundreds or thousands:

{ "channel": "l4Book",
  "data": { "Snapshot": { "coin": "LTC", "time": 1788944447014, "height": 1141111700,
    "levels": [
      [ {"user":"0x4e60e3a4...","coin":"LTC","side":"B","limitPx":"54.717","sz":"7.31",
         "oid":540105017942,"timestamp":1788944446488,"orderType":"Limit","tif":"Alo",
         "origSz":"7.31","cloid":"0xf80bd700...","reduceOnly":false,
         "isTrigger":false,"triggerPx":"0.0","triggerCondition":"N/A",
         "isPositionTpsl":false,"children":[]} ],
      [ {"user":"0x4e60e3a4...","coin":"LTC","side":"A","limitPx":"54.723","sz":"7.31",
         "oid":540105019037,"timestamp":1788944446690,"orderType":"Limit","tif":"Alo",
         "origSz":"7.31","cloid":"0x0e0cd700...","reduceOnly":false,
         "isTrigger":false,"triggerPx":"0.0","triggerCondition":"N/A",
         "isPositionTpsl":false,"children":[]} ] ] } } }

levels[0] is bids and levels[1] is asks, the same way round as l2Book. Each order carries who placed it (user), its id (oid) and client id (cloid), price and size (limitPx, sz, origSz), when it was placed, its type and time-in-force, and its trigger fields.

An update:

{ "channel": "l4Book",
  "data": { "Updates": { "time": 1788944447092, "height": 1141111701,
    "order_statuses": [],
    "book_diffs": [ { "user": "0xdf83170d...", "oid": 540105022216,
                      "px": "54.742", "coin": "LTC",
                      "raw_book_diff": { "new": { "sz": "54.8" } } } ] } } }

Like l2Diff, data holds either a Snapshot or Updates, and both carry a height.

TIP

Subscribe one market at a time. The opening snapshot of a liquid market is several megabytes and takes a few seconds to arrive — that is the snapshot, not a stall. Let it finish before you subscribe to the next market, and keep the number of simultaneous l4Book markets to the ones you actually display.

NOTE

Trigger orders are not in l4Book. Stop and take-profit orders do not rest in the book until they fire, so they are not part of this stream.

bookDiffs

The raw book diffs the node itself produces, before any aggregation.

{ "method": "subscribe", "subscription": { "type": "bookDiffs", "coin": "BTC" } }

orderUpdates

Status changes of orders — placed, filled, cancelled. This stream follows an address, not a market, so there is no coin here.

{ "method": "subscribe", "subscription": { "type": "orderUpdates", "user": "0xYOUR_ADDRESS" } }

allMids

One frame carrying the mid price of every market, so you do not need a subscription per coin.

{ "method": "subscribe", "subscription": { "type": "allMids" } }

Field types

FieldType
timeunix milliseconds, 13 digits — 1788943509915
px, sz, limitPx, origSzstrings, never numbers
ninteger — how many orders are on the level
oid, tid, heightintegers
user, hash, cloid0x strings, lower case

Spot markets

Spot works the same way as perpetuals: put @<index> from spotMeta where the symbol goes. The book, the incremental channel, best bid and offer, trades and the per-order book all take spot markets.

TIP

Prices and sizes are always strings, and the number of decimals depends on the market. BTC arrives as 79499, ETH as 2511.9, DOGE as 0.09117. Parse to a number rather than assuming a format.

Several markets on one connection

Send one subscribe message per market. Each market streams as its own frame, and the coin field tells you which is which. There is no need to open a connection per market.

Next steps

Limits

What is capped today.

Examples

Working code for each of the patterns above.

External references