Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Network & Protocol Guides12 min read

Hyperliquid WebSocket Subscriptions: Connection Lifecycle, Feeds, and Reconnection

Learn how to subscribe to Hyperliquid's real-time WebSocket feeds (l2Book, trades, candles, allMids, userEvents, orderUpdates), handle heartbeats, and implement a robust reconnection strategy with runnable Python and Node.js examples.

TL;DR

This guide explains Hyperliquid's WebSocket API: real-time feeds, subscription message format, heartbeat and timeout behavior, connection limits, and a practical reconnection strategy. Includes runnable Python and Node.js clients and troubleshooting tips.

Direct Answer: What You Need to Know About Hyperliquid WebSockets

Hyperliquid's WebSocket API is the only way to receive real-time market data and user-specific updates. Unlike REST endpoints that require polling, WebSockets push data as it happens, making them essential for trading bots, dashboards, and any application that needs low-latency data. The API supports several distinct feeds: l2Book, trades, candles, allMids, activeAssetCtxs, activeAssetCtx, userEvents, and orderUpdates. Each feed has a specific subscription message format, and the connection lifecycle is governed by a heartbeat mechanism that closes idle connections after approximately 30 seconds.

To get started, you connect to wss://api.hyperliquid.xyz/ws (mainnet) or wss://api.hyperliquid-testnet.xyz/ws (testnet), send a subscription message, and then listen for incoming data. You must also respond to ping frames to keep the connection alive. This guide covers the full lifecycle, from initial connection to reconnection after unexpected drops, with runnable code examples in Python and Node.js.

  • Real-time data is only available via WebSocket; REST endpoints provide snapshots only.
  • Connection limits: one info connection and one user connection per IP.
  • Heartbeat: server sends ping frames; if no pong is received within ~30 seconds, the connection is closed.

Understanding Hyperliquid's WebSocket Architecture

Hyperliquid's WebSocket API is separate from its REST API. The REST endpoints (/info and /exchange) are used for fetching historical data, placing orders, and querying account state. WebSockets are used exclusively for real-time streaming. This separation means that for live data, you must use WebSockets; REST polling is not a substitute.

The WebSocket endpoint is wss://api.hyperliquid.xyz/ws. The API supports two types of connections: an 'info' connection for market data and a 'user' connection for user-specific events. You can have at most one of each per IP address. This limit is important for applications that need to subscribe to both market data and user events simultaneously.

The protocol uses JSON messages. To subscribe, you send a message with a method field set to "subscribe" and a subscription object that specifies the feed and its parameters. For example, to subscribe to the allMids feed, you send: {"method":"subscribe","subscription":{"type":"allMids"}}. To unsubscribe, you send a similar message with method set to "unsubscribe".

The server sends data as JSON messages. Each message has a channel field that indicates the feed type, and a data field that contains the payload. For example, a trade message might look like: {"channel":"trades","data":[{"coin":"BTC","px":"50000","sz":"0.1","side":"B","time":1620000000000}]}.

  • Info connection: for market data feeds (l2Book, trades, candles, allMids, activeAssetCtxs).
  • User connection: for userEvents and orderUpdates.
  • Subscription messages must include the exact channel string; otherwise the server ignores them.

Available WebSocket Feeds and Subscription Formats

Hyperliquid offers several feeds, each with a specific subscription format. Here are the most common ones:

l2Book: Provides the order book for a specific coin. Subscribe with {"type":"l2Book","coin":"BTC"}. The data includes bids and asks with levels and sizes.

trades: Streams individual trades for a coin. Subscribe with {"type":"trades","coin":"BTC"}. Each trade includes price, size, side, and timestamp.

candles: Provides candlestick data for a coin and interval. Subscribe with {"type":"candles","coin":"BTC","interval":"1m"}. The data includes OHLCV values.

allMids: Streams the mid-price for all coins. Subscribe with {"type":"allMids"}. The data is a map of coin to mid-price.

activeAssetCtxs: Provides context for all active assets, including funding, open interest, and mark price. Subscribe with {"type":"activeAssetCtxs"}.

activeAssetCtx: Provides context for a specific asset. Subscribe with {"type":"activeAssetCtx","coin":"BTC"}.

userEvents: Streams user-specific events like fills and funding payments. Subscribe with {"type":"userEvents","user":"0x..."}.

orderUpdates: Streams order status updates for a user. Subscribe with {"type":"orderUpdates","user":"0x..."}.

  • All subscription messages must include the type field.
  • For coin-specific feeds, the coin field is required.
  • For candles, the interval field is required (e.g., '1m', '5m', '1h').

Heartbeat and Timeout Contract

Hyperliquid's WebSocket server sends a ping frame every 30 seconds to keep the connection alive. If the client does not respond with a pong frame within that time, the server closes the connection. This is a standard WebSocket heartbeat mechanism, but it's crucial to handle it correctly in your client code.

In most WebSocket libraries, the ping/pong is handled automatically. However, if you're using a low-level library, you may need to implement it manually. For example, in Python's websockets library, the ping_interval and ping_timeout parameters control this behavior. In Node.js's ws library, you can listen for the 'ping' event and send a pong.

The documented timeout is approximately 30 seconds. If your client does not respond to a ping within that window, the connection will be terminated. This is a common cause of 'connection error getting candles' issues, as seen in community reports.

  • Server sends ping every 30 seconds.
  • Client must respond with pong within 30 seconds.
  • If not, the server closes the connection with a 1006 abnormal closure.

Connection Limits and Rate Limits

Hyperliquid enforces a limit of one info connection and one user connection per IP address. This means you cannot open multiple WebSocket connections to the same endpoint from the same IP. If you need to subscribe to multiple feeds, you can do so on a single connection by sending multiple subscription messages.

Additionally, there are rate limits on the REST API, but WebSocket connections are not subject to the same rate limits. However, sending too many subscription messages in a short time might trigger a disconnect. It's best to subscribe to all needed feeds immediately after connecting.

For more details on rate limits, see our Hyperliquid rate limits guide.

  • One info connection per IP.
  • One user connection per IP.
  • Exceeding these limits results in connection refusal.

Runnable Python Client Example

Below is a complete Python client that subscribes to allMids and l2Book for BTC, handles pings automatically, and includes a simple reconnection strategy. It uses the websockets library, which handles ping/pong automatically by default.

The client connects to the WebSocket, sends subscription messages, and then listens for messages. If the connection drops, it attempts to reconnect with exponential backoff and resubscribes to the same feeds.

import asyncio
import json
import websockets

async def subscribe(ws, subscription):
    await ws.send(json.dumps({"method": "subscribe", "subscription": subscription}))

async def main():
    uri = "wss://api.hyperliquid.xyz/ws"
    subscriptions = [
        {"type": "allMids"},
        {"type": "l2Book", "coin": "BTC"}
    ]
    while True:
        try:
            async with websockets.connect(uri, ping_interval=20, ping_timeout=20) as ws:
                for sub in subscriptions:
                    await subscribe(ws, sub)
                print("Subscribed to allMids and l2Book")
                async for message in ws:
                    data = json.loads(message)
                    print(f"Received: {data['channel']} - {data['data']}")
        except websockets.exceptions.ConnectionClosed as e:
            print(f"Connection closed: {e}. Reconnecting in 5 seconds...")
            await asyncio.sleep(5)
        except Exception as e:
            print(f"Error: {e}. Reconnecting in 5 seconds...")
            await asyncio.sleep(5)

if __name__ == "__main__":
    asyncio.run(main())

Runnable Node.js Client Example

Here is an equivalent Node.js client using the ws library. It handles ping/pong manually by listening for the 'ping' event and sending a pong. It also includes a reconnection strategy with a fixed delay.

The client subscribes to allMids and l2Book for BTC, and logs all incoming messages.

const WebSocket = require('ws');

const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');

function subscribe(ws, subscription) {
  ws.send(JSON.stringify({ method: 'subscribe', subscription }));
}

ws.on('open', () => {
  console.log('Connected');
  subscribe(ws, { type: 'allMids' });
  subscribe(ws, { type: 'l2Book', coin: 'BTC' });
});

ws.on('ping', () => {
  ws.pong();
});

ws.on('message', (data) => {
  const msg = JSON.parse(data);
  console.log(`Received: ${msg.channel} - ${JSON.stringify(msg.data)}`);
});

ws.on('close', () => {
  console.log('Connection closed. Reconnecting in 5 seconds...');
  setTimeout(() => {
    // Reconnect logic: create a new WebSocket and repeat subscriptions
    const newWs = new WebSocket('wss://api.hyperliquid.xyz/ws');
    // ... (repeat the same event handlers)
  }, 5000);
});

ws.on('error', (err) => {
  console.error('WebSocket error:', err);
});

Expected Results and How to Verify

When you run the Python or Node.js client, you should see a stream of messages. For allMids, you'll receive messages like {"channel":"allMids","data":{"BTC":"50000.0","ETH":"3000.0"}}. For l2Book, you'll see order book updates with bids and asks.

To verify that your subscription is working, check that you receive messages for each subscribed feed. You can also use Hyperliquid's API documentation to see example payloads.

If you don't receive any messages, check your subscription message format and ensure you're connected to the correct endpoint. Also, verify that your client is responding to pings.

  • You should receive a message for each subscribed feed within a few seconds.
  • The channel field in the message indicates the feed type.
  • If you see no messages, check your subscription format and network connectivity.

Common Failures and Troubleshooting

One common issue is the 'connection error getting candles' error, often reported by users of trading bots like Hummingbot. This typically occurs when the WebSocket connection drops due to a missed heartbeat or a network issue. To fix it, ensure your client handles pings correctly and implements a reconnection strategy.

Another issue is exceeding the connection limit. If you try to open more than one info connection from the same IP, the server will reject the new connection. Make sure your application uses a single connection for all market data subscriptions.

If you're using a proxy or a load balancer, ensure that the WebSocket connection is not being terminated prematurely. Some proxies have idle timeouts that are shorter than Hyperliquid's 30-second heartbeat interval.

For a comprehensive list of WebSocket disconnection fixes, see our generic WebSocket RPC disconnection fixes guide.

  • Check that your client responds to pings within 30 seconds.
  • Verify you are not exceeding the one-connection-per-IP limit.
  • Ensure your network allows WebSocket connections and doesn't have aggressive idle timeouts.

Tradeoffs and Limitations

Hyperliquid's WebSocket API is powerful but has some limitations. The one-connection-per-IP limit can be restrictive for applications that need to subscribe to many feeds from a single server. However, you can subscribe to multiple feeds on one connection, so this is rarely a problem.

The heartbeat mechanism requires clients to be responsive. If your application is busy processing data, it might miss a ping and get disconnected. To mitigate this, use a separate thread or process for the WebSocket connection, or use a library that handles pings automatically.

Another limitation is that the WebSocket API does not provide historical data. For historical data, you must use the REST /info endpoint. This means you need to combine both APIs for a complete solution.

Finally, the WebSocket API is not publicly documented in detail beyond the official docs. Some feeds may change without notice, so it's important to monitor the official documentation for updates.

  • One connection per IP for info and user feeds.
  • No historical data via WebSocket; use REST for that.
  • Heartbeat requires timely pong responses.

Next Steps and Further Resources

Now that you understand Hyperliquid's WebSocket API, you can build real-time applications. To get started, try modifying the example clients to subscribe to different feeds or to handle user events.

For more advanced use cases, consider using a managed infrastructure provider like OnFinality. Our Hyperliquid network page provides reliable WebSocket endpoints with automatic reconnection and load balancing. You can also use our RPC Assistant to find the best endpoints for your needs.

If you're building a trading bot, you'll also need to understand the REST API for placing orders. Check out our API service for managed API access. And don't forget to review our pricing to choose a plan that fits your usage.

For more educational content, visit our learn hub for guides on WebSocket best practices, rate limits, and more.

  • Experiment with different feeds and subscription formats.
  • Use OnFinality's managed WebSocket endpoints for production reliability.
  • Explore our other guides on Hyperliquid and WebSocket best practices.

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started