Hyperliquid WebSocket vs REST: Low-Latency Data Feeds
Benchmarking the Hyperliquid WebSocket API against REST polling for L2 book and fills, with reconnect and snapshot-sync patterns for low-latency HFT bots.
Polling Hyperliquid's REST /info endpoint for the L2 book at 100ms intervals will cost you roughly 40-80ms of staleness on every tick, plus the round-trip, plus whatever rate-limit headroom you burn. The WebSocket l2Book subscription pushes the same data on change, and in our benchmarks the median book update landed 55-70ms sooner than the equivalent poll. For a market maker sitting on the top of book, that gap is the difference between getting filled on your terms and getting picked off.
This is the boring-but-load-bearing part of any Hyperliquid bot: how you get data in. Get it wrong and every clever quoting or arb decision downstream is reacting to a stale world. Here's how the two transports actually behave, measured, plus the reconnection and snapshot-sync patterns you need before you put size behind them.
The two transports, concretely
Hyperliquid exposes market data through the /info REST endpoint and a WebSocket at wss://api.hyperliquid.xyz/ws. Both speak the same underlying data model. The difference is push versus pull.
REST is request/response. You POST a JSON body like {"type": "l2Book", "coin": "ETH"} and get back the current snapshot. Simple, stateless, easy to reason about. But you only know what you asked for at the moment you asked, and Hyperliquid weights requests against an IP-based budget — an l2Book call costs 2 weight, and you have 1200 weight per minute per IP. Poll 30 coins at 100ms and you've blown through the budget in about three seconds.
The WebSocket flips it. You send one subscription message per feed and the server streams updates as they happen:
{ "method": "subscribe", "subscription": { "type": "l2Book", "coin": "ETH" } }
Now you receive a message only when the book changes. No wasted round-trips on a quiet book, no burned rate-limit weight, and — the part that matters — no fixed polling floor on your latency. The webData2 and activeAssetCtx feeds work the same way, and userFills streams your executions the instant they clear rather than making you re-poll.
What the numbers looked like
We ran a colocated client near the API region, subscribed to l2Book for BTC and ETH, and simultaneously polled the same books over REST every 100ms. Over a busy two-hour window:
- REST polling p50 staleness: ~95ms (half your poll interval plus RTT, exactly as you'd expect)
- REST polling p99: ~180ms, spiking whenever a burst of book activity fell between polls
- WebSocket p50 delivery: ~28ms from event to local receipt
- WebSocket p99: ~65ms, mostly TCP head-of-line and occasional server-side batching
The WebSocket wasn't just faster on average — it was dramatically tighter at the tail, which is where you actually get hurt. REST polling has a structural problem: a flurry of five book changes inside one 100ms window collapses into a single observation. You never see the intermediate states, so you can't tell a sweep from a slow drift. The socket shows you every step.
For fills the gap is worse. REST fill polling means you don't know you're filled until your next userFills request completes, which on a 250ms loop means a quarter-second of position uncertainty. If you're running a Hyperliquid perpetuals bot that hedges or ladders off fills, that lag compounds into real slippage. The userFills WebSocket subscription cuts it to the socket delivery time.
The catch: WebSockets need state management
Push feeds aren't free. The l2Book subscription sends a full snapshot on subscribe and then... more snapshots, at a capped depth. If you want a deep, continuously-correct book you still have to hold it in memory and trust the stream. And streams break.
The three failure modes you'll actually hit:
- Silent connection death. TCP thinks the socket is alive; no data has arrived in 30 seconds because a NAT timed out or a proxy dropped it. Without an application-level heartbeat you'll happily quote against a frozen book.
- Reconnect gaps. You drop for 800ms, reconnect, resubscribe — and you've missed every update in between. Your local book is now wrong and you don't know it.
- Ordering and duplication. After a resubscribe you get a fresh snapshot, but you may still have in-flight deltas buffered. Apply them in the wrong order and you corrupt the book.
Hyperliquid supports a ping/pong at the WebSocket layer — send {"method": "ping"} on a timer and treat a missing pong as a dead connection. Don't rely on the OS keepalive; it's too slow and too coarse.
A reconnection and snapshot-sync pattern that holds up
The rule that keeps you honest: on every reconnect, throw away your local book and rebuild from the next snapshot. Don't try to patch across the gap. Here's the skeleton we use, trimmed to the logic:
async def run_feed(coin):
while True:
try:
ws = await connect("wss://api.hyperliquid.xyz/ws")
await subscribe(ws, "l2Book", coin)
book = None # invalid until first snapshot
last_pong = time.monotonic()
async for msg in with_heartbeat(ws, interval=15):
if msg["channel"] == "pong":
last_pong = time.monotonic()
continue
if msg["channel"] == "l2Book":
book = rebuild(msg["data"]) # snapshot IS the truth
on_book(coin, book)
except (ConnectionClosed, TimeoutError):
book = None # mark stale before retry
await backoff_sleep() # jittered, capped at ~5s
Three things make this survive contact with production. First, book is explicitly None between disconnect and the first post-reconnect snapshot, and every consumer checks that before quoting — a stale book must halt trading, not degrade silently. Second, the backoff is jittered so a region blip doesn't reconnect 400 bots on the same millisecond. Third, the heartbeat runs inside the read loop, so a frozen socket trips the timeout instead of hanging forever.
Run one connection per logical feed group rather than one giant multiplexed socket. If a single coin's subscription misbehaves you want to bounce it without dropping your whole book. This matters most for a Hyperliquid market-making bot quoting dozens of assets, where one bad feed shouldn't blind the others.
When REST still wins
Don't cargo-cult the WebSocket for everything. REST is the right tool for:
- Cold-start state — pull
clearinghouseStateonce on boot to seed positions and margin, then switch towebData2for updates. - Low-frequency reference data — funding history, meta, asset contexts you check every few minutes. The funding-rate arbitrage mechanics don't need millisecond freshness on the funding number itself.
- Reconciliation — periodically fetch the authoritative REST snapshot and diff it against your streamed book. If they disagree beyond a tolerance, force a resubscribe. This is your safety net against silent stream corruption.
The pattern that works: WebSocket for the hot path, REST as ground truth and cold start. A funding arbitrage strategy leans on REST for the funding schedule but wants the socket for the price legs. A liquidation bot lives entirely on the stream because it's racing everyone else to the same fills.
If you're building the transport layer from scratch, the Python and Rust API guide covers the client-side details, and once feeds are stable a real-time trading dashboard is the fastest way to catch a silently-dead socket before your PnL does. Whichever language you pick, budget more engineering time for reconnection correctness than for the happy path — that's where the money leaks.
If your bot is still polling REST for its hot path, our market-making build starts by fixing exactly that.
Need a bot like this built?
We design, build and run trading bots on Solana, Hyperliquid and Polymarket.
Start a projectMore from the blog
Public vs Paid RPC: How to Run a Fair Benchmark
A fair comparison of public and paid RPC endpoints must account for quotas, workload, freshness and support guarantees.
Read articleRPC Benchmark Percentiles Explained: p50, p95 and p99
Why averages hide the latency spikes that break trading bots, wallets and production blockchain applications.
Read articleHyperliquid REST vs WebSocket Benchmark: What to Measure
A benchmark plan for Hyperliquid market data that separates request latency from streaming freshness and recovery.
Read article