Getting Started

This section shows how to connect to Hyperliquid Data Stream and start receiving data.

Quick inspection with JSON mode

By default, the connection starts in JSON mode. In this mode, the server sends text frames with order book diffs for subscribed coins.

Example: subscribe to BTC order book diffs.

# Using websocat: https://github.com/vi/websocat

echo '{"method":"subscribe","coin":"BTC"}' \
  | websocat ws://<host>:<port>

You should start receiving newline-delimited JSON order book diff events almost immediately.

Example response:

{"coin":"BTC","time":"...","side":"A","px":"72223.0","sz":"0","oid":123,"user":"0x..."}
{"coin":"BTC","time":"...","side":"B","px":"72182.0","sz":"0.3","oid":456,"user":"0x..."}

JSON mode only delivers order book diffs.

It does not deliver:

  • Block frames
  • Ping frames
  • Timing metrics
  • Mempool transactions

For production use, use binary mode.

Production flow with binary mode

Production clients should use the following connection sequence:

  1. Connect to the WebSocket endpoint.
  2. Send esp to upgrade to binary mode.
  3. Send prime to enable pings, metrics, and server error events.
  4. Subscribe to required coins or streams.
  5. Read frames continuously.
  6. On disconnect, reconnect and repeat the full sequence.

Example sequence:

{"method":"esp","version":1}
{"method":"prime"}
{"method":"subscribe","coin":"BTC"}

To subscribe to the mempool stream:

{"method":"subscribe","stream":"mempool"}

The mempool stream may not be enabled on every Hyperliquid Data Stream instance. If it is not available, the server returns a non-disconnecting error.

Rust client example

A complete Rust client is available in the example client implementation. It connects to the stream, upgrades to binary mode, subscribes to one coin, and prints decoded frames.

Run:

cargo run --example client -- ws://<host>:<port> BTC

Required dependencies:

[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.26"
futures-util = "0.3"

Example connection sequence:

let (ws, _) = connect_async(&url).await?;
let (mut tx, mut rx) = ws.split();

// 1. Upgrade to binary protocol.
tx.send(Message::Text(
    format!(r#"{{"method":"esp","version":{BINARY_VERSION}}}"#).into(),
))
.await?;

// 2. Enable prime streams: pings, metrics, and server errors.
tx.send(Message::Text(r#"{"method":"prime"}"#.into())).await?;

// 3. Subscribe to order book diffs for one coin.
tx.send(Message::Text(
    format!(r#"{{"method":"subscribe","coin":"{coin}"}}"#).into(),
))
.await?;

To add the mempool stream:

tx.send(Message::Text(
    r#"{"method":"subscribe","stream":"mempool"}"#.into()
))
.await?;

The read loop should continuously consume incoming frames and dispatch them by tag.

What's next?