> ## Documentation Index
> Fetch the complete documentation index at: https://goldrush.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Hyperliquid WebSocket Rate Limits & Connection Limits

> The public Hyperliquid WebSocket caps subscriptions at 1000 per IP. The GoldRush Hyperliquid WebSocket API removes that limit and adds wildcard subscriptions - stream every asset on one connection.

## Hyperliquid WebSocket rate limits

The **public Hyperliquid WebSocket** (`wss://api.hyperliquid.xyz/ws`) caps each IP at **1000 active subscriptions**, and most channels require one subscription per asset - so tracking the full market means fanning out hundreds of subscriptions and risking the cap.

**The GoldRush Hyperliquid WebSocket API removes that cap.** It's a [drop-in replacement](https://goldrush.dev/docs/goldrush-hyperliquid/websocket-api/migration.md) with **no per-IP, per-key, or per-connection subscription limit**, plus [wildcard subscriptions](#wildcard-subscriptions) that stream an entire channel over a single subscription.

## No subscription cap

With no subscription limit, you can:

* Open as many concurrent subscriptions as your client supports.
* Multiplex hundreds of `l2Book` subscriptions on a single connection.
* Track every active wallet, market, and asset from one process.

## Wildcard subscriptions

Filter parameters that the public Hyperliquid WebSocket **requires** are **optional** on GoldRush. Omit them to stream the entire channel on one subscription instead of fanning out one subscription per asset.

| Channel | Public Hyperliquid | GoldRush |
| - | - | - |
| `l2Book` | `coin` required - one subscription per asset | `coin` optional - omit it to stream the **full L2 order book across every asset** on a single subscription |

So a single connection can stream Hyperliquid's full live book state without any client-side fan-out logic.

## How streaming works

Messages are pushed directly from a live Hyperliquid ingestion pipeline - no polling, no cache delay. Latency from upstream Hyperliquid event to your client is dominated by network round-trip from our Tokyo nodes.

| Channel | Push trigger |
| - | - |
| `l2Book` | Every L2 update on the subscribed coin (or every coin, if wildcard). |

## Billing

Subscriptions on this WebSocket are billed **per minute, in whole minutes**. There is no proration and there is no partial minute. Every channel bills on that basis; what differs is the unit being counted. Order-book channels (`l2Book`, `l2BookDiff`, `l4Book`, `l4BookUpdates`, `trades`) bill **per coin**. [Wallet-activity channels](#wallet-activity-channels-bill-a-flat-per-channel-rate) bill a **flat rate per channel**, whatever the address count.

> [!WARNING]
>
> **The minimum charge is one full minute per subscription.** A subscription that lives for 200 milliseconds costs exactly the same as one that lives for 60 seconds. If your client reconnects often, read [Every reconnect costs a new first minute](#every-reconnect-costs-a-new-first-minute).

### The first minute is charged up front

The moment the server accepts your `subscribe` message, it charges one full minute at the channel's per-minute rate. This happens before the first frame reaches you, so subscribing and disconnecting immediately does not avoid the charge.

This is deliberate. Without it, a client could grab a snapshot for a fraction of a credit and drop the connection, which is a far cheaper way to poll the book than the REST endpoints it would otherwise use.

### After that, every started minute is a full minute

Once the first minute is paid, the total you owe is `ceil(seconds_subscribed / 60)`, counted from the instant you subscribed:

| Time subscribed | Minutes billed |
| - | - |
| 200 ms | 1 |
| 1 s | 1 |
| 60 s | 1 |
| 61 s | 2 |
| 120 s | 2 |
| 121 s | 3 |

Any second past a full minute starts the next billable minute. Usage never accrues a fractional minute, so you can always compute a subscription's cost as `ceil(seconds / 60) x rate`.

### Per-minute rates

| Channel | Subscription shape | Credits per minute |
| - | - | - |
| [`l2Book`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l2-book) | One coin | 0.5 per coin |
| [`l2Book`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l2-book) | Wildcard (`coin` omitted) | 50 |
| [`l2BookDiff`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l2-book-diff) | One coin | 0.13 per coin |
| [`l2BookDiff`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l2-book-diff) | Wildcard (`coin` omitted) | 10 |
| [`l4Book`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l4-book) | One coin, not BTC | 3 |
| [`l4Book`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/l4-book) | `"coin": "BTC"` | 60 |
| `l4BookUpdates` | One coin | 1 per coin |
| `trades` | One coin | 0.1 per coin |

A wildcard subscription is billed as one subscription at the flat wildcard rate, no matter how many assets it streams. So the wildcard pays for itself once you are tracking enough coins to match its rate: 100 coins on `l2Book` (100 x 0.5 = 50) and 77 coins on `l2BookDiff` (77 x 0.13 = 10.01). Below that, per-coin subscriptions cost less. `l4Book` has no wildcard; `coin` is required. `l4BookUpdates` and `trades` are per-coin with no wildcard and no BTC premium.

### Wallet-activity channels bill a flat per-channel rate

[`userFills`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/user-fills), [`allFills`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/all-fills), [`liquidationFills`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/liquidation-fills), [`orderUpdates`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/order-updates), [`userNonFundingLedgerUpdates`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/user-non-funding-ledger-updates), and [`builderFills`](https://goldrush.dev/docs/api-reference/hyperliquid-websocket/builder-fills) bill on the same whole-minute basis, but at a **flat rate per channel, not per coin**:

| Channel | Subscription shape | Credits per minute |
| - | - | - |
| Any wallet-activity channel | Per connection (any number of addresses) | 1 per channel |

The rate does **not** scale with the number of addresses you track: one `userFills` subscription covering 10 addresses or 1,000 addresses is the same 1 credit per minute. Two consequences:

* **One billable subscription per (connection, channel).** Adding or removing addresses on a channel you are already subscribed to does not open a new billable subscription.
* **Up to 1,000 addresses per connection, per channel.** To track more, open additional connections. Each one bills its own 1 credit per minute per channel.

### What counts as one subscription

On the **order-book channels**, a subscription is identified by **the channel plus the exact `coin` field you sent**, on one WebSocket session. Three consequences follow:

* **Re-sending an identical `subscribe` on a live session is free.** It is deduplicated, produces no extra data, and adds no charge.
* **An array subscription is one subscription, not N.** `{"type": "l2BookDiff", "coin": ["BTC", "ETH", "SOL"]}` is a single billable subscription charged at the sum of its coins' rates: 3 x 0.13 = 0.39 credits per minute.
* **Overlapping subscriptions each bill.** Holding `coin: ["BTC", "ETH"]` and `coin: "BTC"` at the same time gives you two independent streams, both delivering BTC frames, and you pay for both.

On the **wallet-activity channels** there is no `coin` field, so the unit is the channel per connection and the address list never changes it. Everything below applies to both families.

### Every reconnect costs a new first minute

A new WebSocket session is a new subscription, even if you send byte-identical subscribe messages. So every reconnect pays the one-minute minimum again.

This matters most when a connection is flapping. A client that retries every second, holding 50 `l2BookDiff` coin subscriptions, bills 50 minutes per retry. Sixty retries in a minute bills 3,000 subscription-minutes for 60 seconds of wall-clock time.

Two things protect you:

* **Back off exponentially.** Start around 1 second and cap at 30 seconds, as in the [reconnect sketch](#reconnect-sketch) below. That bounds a flapping client to roughly 2 reconnects per minute instead of 60.
* **Prefer one long-lived connection.** Multiplex every subscription onto it rather than opening and closing sockets per query.

### `unsubscribe` must repeat the exact shape you subscribed with

An `unsubscribe` only matches a subscription whose `coin` field is *exactly* the one you sent on `subscribe`.

```text theme={null}
subscribe    { "type": "l2BookDiff", "coin": ["BTC", "ETH"] }   // one subscription
unsubscribe  { "type": "l2BookDiff", "coin": "ETH" }            // matches nothing
```

The second message is a silent no-op. Hyperliquid replies `Already unsubscribed`, the array keeps streaming both coins, and it keeps billing at the full array rate. To drop one coin out of a multi-coin subscription, unsubscribe with the exact array shape and then subscribe again with the subset you want.

### Worked example: snapshot-only across 168 coins

Subscribing to `l4Book` on 168 coins, reading the opening snapshot, and disconnecting after 400 milliseconds bills the full one-minute minimum on all 168:

| | Coins | Rate per minute | Minutes | Credits |
| - | - | - | - | - |
| BTC | 1 | 60 | 1 | 60 |
| Every other coin | 167 | 3 | 1 | 501 |
| **Total** | **168** | | | **561** |

Staying connected for a full 60 seconds costs the same 561 credits. Staying for 61 seconds costs 1,122. Disconnecting and repeating the same snapshot sweep ten times costs 5,610.

## Connection management

You're not rate-limited, but a few client-side defaults are worth tuning.

| Behavior | Recommended client setting |
| - | - |
| **Reconnect** | On unexpected close, reconnect with exponential backoff capped at \~30 seconds. Re-send your subscription messages after the new socket opens. A fixed short retry is expensive: every reconnect re-pays the [one-minute minimum](#every-reconnect-costs-a-new-first-minute) on every subscription. |
| **Heartbeat** | Send an application-level `ping` every 30 seconds. The server replies with `pong`. Most WebSocket libraries handle this automatically; verify yours does. |
| **Max message size** | L2 book snapshots for wildcard subscriptions can exceed 1 MB. Raise your client's `maxPayload` (Node `ws` library) or `max_size` (Python `websockets`) if you're receiving truncated messages. |
| **Backpressure** | If your handler can't keep up with incoming messages, your client buffer will fill. Drain to a queue or downstream consumer; don't block the read loop on application work. |

### Reconnect sketch

```typescript TypeScript theme={null}
import WebSocket from "ws";

function connect() {
  const ws = new WebSocket(
    `wss://hypercore.goldrushdata.com/ws?key=${process.env.GOLDRUSH_API_KEY}`,
    { maxPayload: 8 * 1024 * 1024 },
  );

  ws.on("open", () => {
    ws.send(JSON.stringify({
      method: "subscribe",
      subscription: { type: "l2Book" }, // wildcard - all assets
    }));
  });

  ws.on("close", () => setTimeout(connect, Math.min(30_000, backoff *= 2)));
  ws.on("error", () => ws.close());
  ws.on("message", handle);
}

let backoff = 1_000;
connect();
```

```python Python theme={null}
import asyncio, json, os
import websockets

async def consume():
    uri = f"wss://hypercore.goldrushdata.com/ws?key={os.environ['GOLDRUSH_API_KEY']}"
    backoff = 1
    while True:
        try:
            async with websockets.connect(uri, max_size=8 * 1024 * 1024, ping_interval=30) as ws:
                backoff = 1
                await ws.send(json.dumps({
                    "method": "subscribe",
                    "subscription": {"type": "l2Book"},  # wildcard
                }))
                async for raw in ws:
                    handle(json.loads(raw))
        except Exception:
            await asyncio.sleep(min(30, backoff))
            backoff *= 2

asyncio.run(consume())
```

## Watch out for client-side limits

GoldRush has no caps, but the rest of your stack might:

* **OS file descriptor limits** - if you're opening many connections in parallel, raise `ulimit -n`.
* **Reverse proxy idle timeouts** - if you're terminating WS through nginx, HAProxy, or a cloud load balancer, set the idle timeout above your heartbeat interval (typically 60 seconds minimum).
* **Browser concurrency** - browsers limit WebSocket connections per origin; one connection multiplexing many subscriptions is always preferable to many connections.

## Network and TLS

* **HTTP/1.1 Upgrade** to WSS is supported (standard WebSocket handshake).
* **TLS 1.2+** required.
* **Compression (`permessage-deflate`)** is negotiated when offered by the client.

## Need higher guarantees?

Enterprise SLA, dedicated capacity, regional pinning, and on-prem options are all available. [Email sales](mailto:sales@goldrush.dev?subject=Hyperliquid%20WebSocket%20API%20-%20Enterprise%20Inquiry).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.