Docs
Docs
Home
Getting Started
Agent Tooling
CLI
Supported Chains
Acala
Aptos
Arbitrum
Arc
Asset Hub
Astar
Avalanche
Base
Berachain
Bifrost
Binance Smart Chain
Bittensor
Blast
Boba Network
Bridge Hub
Celo
Centrifuge
Chiliz
Cronos
Enjin
Ethereum
Etherlink
Flow EVM Gateway
Gnosis
Hydration
Hyperliquid
Immutable
Ink
IoTeX
Kusama
Linea
LISK
Manta Atlantic
Manta Pacific
Mantle
MegaETH
Monad
Movement
Neuroweb
opBNB
Optimism
Plasma
Polkadot
Polygon
Pulsechain
Robinhood
Ronin
Scroll
Sonic
Starknet
Taiko
Tempo
Sui
TRON
Unichain
Viction
World Chain
XDC Network
XX Network
Zetachain
zkSync Era
Zora
Supported ChainsHyperliquidHyperliquid HyperCoregRPC Streaming API

StreamOrderbookSnapshots - Real-time Order Book Streaming

Stream generated order book snapshots with individual order visibility from Hyperliquid L1 Gateway via gRPC.

Hyperliquid RPC endpoint: endpoint URLs, plans and pricing.

Stream continuous order book snapshots starting from a position, providing real-time access to every individual open order across all markets on Hyperliquid. Each snapshot contains complete order metadata including order IDs, timestamps, trigger conditions, and child orders.

Snapshot availability

This RPC is the public method for streaming generated order-book snapshots. Snapshots intentionally do not appear in ListFeeds. Snapshot availability and maximum response size vary by endpoint. Oversized responses return RESOURCE_EXHAUSTED.

Client receive limits

Large snapshots can exceed a gRPC client inbound message limit even when the endpoint can deliver the response. Client receive limits are separate from endpoint delivery limits. Configure them per client and workload; there is no universal fixed size that fits every snapshot.

Positioning Note

Start this stream from a timestamp cursor. V3 position.block_number and V2 block_height are not supported for order-book snapshots.

Full Code Examples

Clone our gRPC Code Examples Repository for complete, runnable implementations in Go, Python, and Node.js.

When to Use This Method

StreamOrderbookSnapshots is essential for:

  • Market Making - Monitor individual order changes and adjust quotes in real-time
  • Trading Algorithms - Access live order-level data for execution strategies
  • Order Flow Analysis - Track individual orders appearing and disappearing across snapshots
  • Whale Watching - Detect large orders and trigger order clustering in real-time
  • Risk Management - Monitor market conditions with full order granularity

Method signature

gRPC API version
protobuf
rpc StreamOrderbookSnapshots(StreamRequest) returns (stream Record) {}

V3 accepts only an inclusive Unix-millisecond position.timestamp; position.block_number and filters return INVALID_ARGUMENT, and explicit zero is invalid. A positioned stream starts with the snapshot covering the requested timestamp. An unpositioned stream sends the latest existing snapshot immediately and then each newer snapshot.

protobuf
position: {
  timestamp: 1785736814057
}

In each Record, block_number and timestamp are typed transport cursors. They are outside the snapshot JSON. Decoded Record.data is the snapshot's top-level array of [coin, [bids, asks]] tuples. Snapshot RPCs are outside ListFeeds, and a timestamp outside retained history returns NOT_FOUND.

cURL request
grpcurl \
  -import-path content/docs/hyperliquid/grpc \
  -proto v3.proto \
  -H "x-api-key: ${DWELLIR_API_KEY}" \
  -d '{"position":{"timestamp":"1785736814057"}}' \
  "${HYPERLIQUID_GRPC_ENDPOINT}" \
  hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamOrderbookSnapshots

Response Stream

Each streamed message contains a full order book snapshot with every individual open order across all markets. Snapshot size varies with market conditions and endpoint. In V3, block_number and timestamp are typed transport cursors and decoded Record.data is the top-level array below. In V2, decode the wrapper above first and then read its inner data array.

Large Message Size

Snapshot availability and maximum response size vary by endpoint. Oversized responses return RESOURCE_EXHAUSTED. Independently, configure the client inbound message limit per client and workload.

Top-Level Structure

JSON
[
  ["BTC", [[{ "coin": "BTC", "side": "B", "oid": 333003526755 }], []]],
  ["ETH", [[], []]]
]

The root array contains one entry per market. Transport cursors are not nested inside it.

Market Entry Structure

Each element in decoded V3 Record.data is a 2-element array (tuple):

JSON
[
  "BTC",
  [
    [ ...bid orders... ],
    [ ...ask orders... ]
  ]
]
IndexTypeDescription
[0]stringCoin/asset symbol. Perp markets use ticker names (e.g. "BTC", "ETH"). Spot markets use @-prefixed numeric IDs (e.g. "@1", "@105"). HIP-3 builder-deployed perps use the dex prefix, such as xyz: for the XYZ dex (e.g. "xyz:TSLA")
[1]array[2]Two sub-arrays: [0] = bid orders (sorted descending by price), [1] = ask orders (sorted ascending by price)

Order Object

Each order in the bid/ask arrays is an individual order with full metadata. See the GetOrderBookSnapshot Field Reference for the complete field-by-field breakdown.

JSON
{
  "coin": "BTC",
  "side": "B",
  "limitPx": "84500.0",
  "sz": "0.5",
  "oid": 333003526755,
  "timestamp": 1772276628506,
  "triggerCondition": "N/A",
  "isTrigger": false,
  "triggerPx": "0.0",
  "children": [],
  "isPositionTpsl": false,
  "reduceOnly": false,
  "orderType": "Limit",
  "origSz": "0.5",
  "tif": "Alo",
  "cloid": "0x00000000000000000000000000000318"
}

Coin Symbol Conventions

PatternTypeExamples
Plain tickerPerpetual futures"BTC", "ETH", "AAVE", "ARB"
@ + numberSpot markets"@1", "@10", "@105"
xyz: + tickerHIP-3 perps on the XYZ dex: equities, commodities, FX and indices"xyz:TSLA", "xyz:TSM", "xyz:SOFTBANK"

Common Use Cases

1. Order Flow Tracking

Compare consecutive snapshots to detect new, modified, and cancelled orders:

Python
class OrderFlowTracker:
    def __init__(self):
        self.previous_orders = {}  # oid -> order

    def track(self, snapshot):
        """Compare snapshots to detect order changes"""
        current_orders = {}

        for market in snapshot:
            coin = market[0]
            bids = market[1][0]
            asks = market[1][1]

            for order in bids + asks:
                current_orders[order['oid']] = order

        # Detect changes
        new_oids = set(current_orders) - set(self.previous_orders)
        removed_oids = set(self.previous_orders) - set(current_orders)

        for oid in new_oids:
            order = current_orders[oid]
            print(f'NEW: {order["coin"]} {order["side"]} '
                  f'{order["sz"]} @ {order["limitPx"]} '
                  f'({order["orderType"]})')

        for oid in removed_oids:
            order = self.previous_orders[oid]
            print(f'REMOVED: {order["coin"]} {order["side"]} '
                  f'{order["sz"]} @ {order["limitPx"]}')

        self.previous_orders = current_orders

2. Trigger Order Monitor

Track stop-loss and take-profit orders clustering around price levels:

JavaScript
function analyzeTriggerOrders(snapshot, targetCoin) {
    for (const market of snapshot) {
        if (market[0] !== targetCoin) continue;

        const allOrders = [...market[1][0], ...market[1][1]];
        const triggerOrders = allOrders.filter(o => o.isTrigger);

        // Group by trigger price
        const triggerLevels = {};
        for (const order of triggerOrders) {
            const px = order.triggerPx;
            if (!triggerLevels[px]) {
                triggerLevels[px] = { count: 0, totalSz: 0, types: [] };
            }
            triggerLevels[px].count++;
            triggerLevels[px].totalSz += parseFloat(order.sz);
            triggerLevels[px].types.push(order.orderType);
        }

        // Report significant trigger clusters
        const sorted = Object.entries(triggerLevels)
            .sort((a, b) => b[1].totalSz - a[1].totalSz);

        console.log(`\n${targetCoin} Trigger Order Clusters:`);
        for (const [px, data] of sorted.slice(0, 5)) {
            console.log(`  ${px}: ${data.count} orders, ` +
                `size ${data.totalSz.toFixed(2)}`);
        }
    }
}

3. Large Order Detection

Monitor for whale-sized orders appearing in the stream:

Go
func detectLargeOrders(data []byte, threshold float64) {
    var snapshot [][]interface{}

    if err := json.Unmarshal(data, &snapshot); err != nil {
        return
    }

    for _, market := range snapshot {
        coin := market[0].(string)
        sides := market[1].([]interface{})

        for _, side := range sides {
            orders := side.([]interface{})
            for _, o := range orders {
                order := o.(map[string]interface{})
                sz, _ := strconv.ParseFloat(order["sz"].(string), 64)
                if sz >= threshold {
                    log.Printf("LARGE ORDER: %s %s %.2f @ %s (%s)",
                        coin, order["side"], sz,
                        order["limitPx"], order["orderType"])
                }
            }
        }
    }
}

Error Handling and Reconnection

JavaScript
class RobustOrderbookStreamer {
    constructor(endpoint, apiKey) {
        this.endpoint = endpoint;
        this.apiKey = apiKey;
        this.maxRetries = 5;
        this.retryDelay = 1000;
        this.currentRetries = 0;
    }

    async startStreamWithRetry() {
        while (this.currentRetries < this.maxRetries) {
            try {
                await this.startStream();
                this.currentRetries = 0;
                this.retryDelay = 1000;
            } catch (error) {
                this.currentRetries++;
                console.error(`Stream attempt ${this.currentRetries} failed:`, error.message);

                if (this.currentRetries >= this.maxRetries) {
                    throw new Error('Max retry attempts exceeded');
                }

                // Exponential backoff
                await this.sleep(this.retryDelay);
                this.retryDelay *= 2;
            }
        }
    }

    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

Important Notes

  • Individual orders, not aggregated levels. Each entry is an individual order with full metadata (order ID, timestamp, trigger info, children, etc.).
  • Bids are sorted by price descending (highest price first). Asks are sorted by price ascending (lowest price first).
  • Children are never nested. Child orders always have an empty children array.
  • Trigger orders (isTrigger: true) have tif: null and meaningful triggerCondition / triggerPx values.
  • Once triggered, the order becomes isTrigger: false, triggerCondition: "Triggered", triggerPx: "0.0", and receives a tif value (typically "Gtc").

For detailed response examples including orders with TP/SL children, triggered orders, and all field descriptions, see the GetOrderBookSnapshot documentation.

Best Practices

  1. Message Size Configuration: Configure the client inbound message limit per client and workload, and account separately for endpoint delivery limits; oversized responses return RESOURCE_EXHAUSTED.
  2. Connection Management: Implement robust reconnection logic with exponential backoff
  3. Memory Management: Use bounded collections for storing historical snapshots; avoid keeping many full snapshots in memory simultaneously
  4. Performance: Process snapshots asynchronously to avoid blocking the stream
  5. Monitoring: Track stream health and snapshot rates
  6. Resource Cleanup: Properly close streams and connections on shutdown

Current Limitations

  • Replay History: Available snapshot history varies by endpoint; a timestamp outside retained history returns NOT_FOUND
  • Backpressure: High-volume periods may require careful handling to avoid overwhelming downstream systems
  • Availability: Snapshot availability and maximum response size vary by endpoint; oversized responses return RESOURCE_EXHAUSTED

Resources

  • GitHub: gRPC Code Examples - Complete working examples
  • Copy Trading Bot - Production-ready trading bot example
  • Pricing - Dedicated node cluster pricing details

Need help? Contact our support team or check the Hyperliquid gRPC documentation.

StreamOrderStatuses - Real-time Order Status Streaming

Stream order lifecycle events from Hyperliquid L1 Gateway via gRPC. Track opens, fills, cancellations, and rejections per block in real time.

StreamRawBookDiffs - Real-time Book Diff Streaming

Stream incremental order book changes from Hyperliquid L1 Gateway via gRPC. Reconstruct the resting book from per-block additions, updates, and removals.

On this page

When to Use This MethodV2 decoded wrapperResponse StreamTop-Level StructureMarket Entry StructureOrder ObjectCoin Symbol ConventionsCommon Use Cases1. Order Flow Tracking2. Trigger Order Monitor3. Large Order DetectionError Handling and ReconnectionImportant NotesBest PracticesCurrent LimitationsResources