GetOrderBookSnapshot - Get Order Book Data Retrieve a full order book snapshot with individual order visibility from Hyperliquid L1 Gateway via gRPC. Premium endpoint available on dedicated nodes.
Retrieve a full order book snapshot at a specific point in time from the Hyperliquid L1 Gateway. Returns every individual open order across all markets with complete metadata including order IDs, timestamps, trigger conditions, and child orders.
Dedicated Node Required
This is a premium endpoint available only with dedicated nodes. It is not available on shared infrastructure. Contact support to provision a dedicated node.
GetOrderBookSnapshot is essential for:
Market Microstructure Analysis - Access every individual order with full metadata
Queue Position Tracking - See exact order placement timestamps and sizes
Whale Watching - Monitor large orders with their original sizes and trigger conditions
Trading Strategies - Analyze order distribution, TP/SL clustering, and trigger order density
Risk Management - Assess market impact with individual order granularity
rpc GetOrderBookSnapshot(Timestamp) returns (OrderBookSnapshot) {}
Request Parameters Request block* string
Block height at which this snapshot was taken
timestamp* integer
Unix timestamp in milliseconds when the snapshot was taken
data* array
Array of market entries (one per trading pair). ~656 markets in a typical snapshot
Request Message Python Node.js
package main import ( "context" "encoding/json" "fmt" "log" "os" "time" pb "hyperliquid-grpc-client/api/v2" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" ) type Order struct { Coin string `json:"coin"` Side string `json:"side"` LimitPx string `json:"limitPx"` Sz string `json:"sz"` Oid int64 `json:"oid"` Timestamp int64 `json:"timestamp"` TriggerCondition string `json:"triggerCondition"` IsTrigger bool `json:"isTrigger"` TriggerPx string `json:"triggerPx"` Children []Order `json:"children"` IsPositionTpsl bool `json:"isPositionTpsl"` ReduceOnly bool `json:"reduceOnly"` OrderType string `json:"orderType"` OrigSz string `json:"origSz"` Tif *string `json:"tif"` Cloid *string `json:"cloid"` } type Snapshot struct { Block string `json:"block"` Timestamp int64 `json:"timestamp"` Data json.RawMessage `json:"data"` } func getOrderBookSnapshot(ctx context.Context, client pb.HyperliquidL1GatewayClient) (*Snapshot, error) { ctx, cancel := context.WithTimeout(ctx, 120*time.Second) defer cancel() // Request current snapshot (timestamp_ms 0 = latest) request := &pb.Timestamp{TimestampMs: 0} response, err := client.GetOrderBookSnapshot(ctx, request) if err != nil { return nil, fmt.Errorf("RPC call failed: %v", err) } fmt.Printf("Response size: %d bytes\n\n", len(response.Data)) var snapshot Snapshot if err := json.Unmarshal(response.Data, &snapshot); err != nil { return nil, fmt.Errorf("failed to parse JSON: %v", err) } return &snapshot, nil } func main() { endpoint := os.Getenv("HYPERLIQUID_ENDPOINT") apiKey := os.Getenv("API_KEY") if endpoint == "" { log.Fatal("Error: HYPERLIQUID_ENDPOINT environment variable is required.") } if apiKey == "" { log.Fatal("Error: API_KEY environment variable is required.") } fmt.Println("Hyperliquid Go gRPC Client - Get Order Book Snapshot") fmt.Println("====================================================") fmt.Printf("Endpoint: %s\n\n", endpoint) // Set up TLS connection creds := credentials.NewTLS(nil) opts := []grpc.DialOption{ grpc.WithTransportCredentials(creds), grpc.WithDefaultCallOptions( grpc.MaxCallRecvMsgSize(500 * 1024 * 1024), // 500MB max ), } fmt.Println("Connecting to gRPC server...") conn, err := grpc.NewClient(endpoint, opts...) if err != nil { log.Fatalf("Failed to connect: %v", err) } defer conn.Close() client := pb.NewHyperliquidL1GatewayClient(conn) fmt.Println("Connected successfully!\n") fmt.Println("Fetching order book snapshot...\n") // Get order book snapshot with API key ctx := context.Background() ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey) snapshot, err := getOrderBookSnapshot(ctx, client) if err != nil { log.Fatalf("Failed to get order book: %v", err) } fmt.Printf("Block: %s\n", snapshot.Block) timestamp := time.UnixMilli(snapshot.Timestamp) fmt.Printf("Time: %s\n", timestamp.Format("2006-01-02 15:04:05 UTC")) // Parse the market data var markets []json.RawMessage if err := json.Unmarshal(snapshot.Data, &markets); err != nil { log.Fatalf("Failed to parse markets: %v", err) } fmt.Printf("Total markets: %d\n", len(markets)) } import grpc import json import sys import os from datetime import datetime from dotenv import load_dotenv import hyperliquid_pb2 import hyperliquid_pb2_grpc load_dotenv() def get_order_book_snapshot(): endpoint = os.getenv('HYPERLIQUID_ENDPOINT') api_key = os.getenv('API_KEY') if not endpoint: print("Error: HYPERLIQUID_ENDPOINT environment variable is required.") sys.exit(1) if not api_key: print("Error: API_KEY environment variable is required.") sys.exit(1) print('Hyperliquid Python gRPC Client - Get Order Book Snapshot') print('========================================================') print(f'Endpoint: {endpoint}\n') credentials = grpc.ssl_channel_credentials() options = [ ('grpc.max_receive_message_length', 500 * 1024 * 1024), # 500MB max ] metadata = [('x-api-key', api_key)] print('Connecting to gRPC server...') with grpc.secure_channel(endpoint, credentials, options=options) as channel: client = hyperliquid_pb2_grpc.HyperliquidL1GatewayStub(channel) print('Connected successfully!\n') # Request latest snapshot (timestamp_ms 0 = latest) request = hyperliquid_pb2.Timestamp(timestamp_ms=0) print('Fetching order book snapshot...\n') try: response = client.GetOrderBookSnapshot(request, metadata=metadata) print(f'Response size: {len(response.data)} bytes\n') process_snapshot(response.data) except grpc.RpcError as e: print(f'RPC error: {e}') except Exception as e: print(f'Error: {e}') def process_snapshot(data): try: snapshot = json.loads(data.decode('utf-8')) print('ORDER BOOK SNAPSHOT') print('===================') print(f'Block: {snapshot["block"]}') dt = datetime.fromtimestamp(snapshot['timestamp'] / 1000) print(f'Time: {dt.strftime("%Y-%m-%d %H:%M:%S UTC")}') markets = snapshot['data'] print(f'Total markets: {len(markets)}') # Count orders across all markets total_bids = 0 total_asks = 0 for market in markets: coin = market[0] orders = market[1] total_bids += len(orders[0]) total_asks += len(orders[1]) print(f'Total bid orders: {total_bids:,}') print(f'Total ask orders: {total_asks:,}') print(f'Total orders: {total_bids + total_asks:,}') # Show top 3 markets by order count market_counts = [] for market in markets: coin = market[0] orders = market[1] count = len(orders[0]) + len(orders[1]) market_counts.append((coin, count)) market_counts.sort(key=lambda x: -x[1]) print('\nTop markets by order count:') for coin, count in market_counts[:5]: print(f' {coin}: {count:,} orders') except json.JSONDecodeError as e: print(f'Failed to parse JSON: {e}') except Exception as e: print(f'Error processing snapshot: {e}') if __name__ == '__main__': get_order_book_snapshot() const grpc = require('@grpc/grpc-js'); const protoLoader = require('@grpc/proto-loader'); const path = require('path'); require('dotenv').config(); const PROTO_PATH = path.join(__dirname, 'v2.proto'); const packageDefinition = protoLoader.loadSync(PROTO_PATH, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }); const proto = grpc.loadPackageDefinition(packageDefinition); async function getOrderBookSnapshot() { const endpoint = process.env.HYPERLIQUID_ENDPOINT; const apiKey = process.env.API_KEY; if (!endpoint) { console.error('Error: HYPERLIQUID_ENDPOINT environment variable is required.'); process.exit(1); } if (!apiKey) { console.error('Error: API_KEY environment variable is required.'); process.exit(1); } console.log('Hyperliquid Node.js gRPC Client - Get Order Book Snapshot'); console.log('========================================================='); console.log(`Endpoint: ${endpoint}\n`); const metadata = new grpc.Metadata(); metadata.add('x-api-key', apiKey); // 500MB max to handle the large response const client = new proto.hyperliquid_l1_gateway.v2.HyperliquidL1Gateway( endpoint, grpc.credentials.createSsl(), { 'grpc.max_receive_message_length': 500 * 1024 * 1024 } ); console.log('Fetching order book snapshot...\n'); // Request latest snapshot (timestamp_ms 0 = latest) client.GetOrderBookSnapshot({ timestamp_ms: 0 }, metadata, (error, response) => { if (error) { console.error('gRPC error:', error.message); return; } try { const snapshot = JSON.parse(response.data); console.log(`Response size: ${response.data.length} bytes\n`); console.log('ORDER BOOK SNAPSHOT'); console.log('==================='); console.log(`Block: ${snapshot.block}`); const date = new Date(snapshot.timestamp); console.log(`Time: ${date.toISOString()}`); console.log(`Total markets: ${snapshot.data.length}`); // Count orders across all markets let totalBids = 0; let totalAsks = 0; const marketCounts = []; for (const market of snapshot.data) { const coin = market[0]; const orders = market[1]; const bidCount = orders[0].length; const askCount = orders[1].length; totalBids += bidCount; totalAsks += askCount; marketCounts.push({ coin, count: bidCount + askCount }); } console.log(`Total bid orders: ${totalBids.toLocaleString()}`); console.log(`Total ask orders: ${totalAsks.toLocaleString()}`); console.log(`Total orders: ${(totalBids + totalAsks).toLocaleString()}`); // Show top markets by order count marketCounts.sort((a, b) => b.count - a.count); console.log('\nTop markets by order count:'); for (const { coin, count } of marketCounts.slice(0, 5)) { console.log(` ${coin}: ${count.toLocaleString()} orders`); } } catch (error) { console.error('Failed to parse response:', error.message); } }); } getOrderBookSnapshot(); Response Message
{ "block": "908730000", "timestamp": 1772276651839, "data": [ ... ] }
{
" coin " : " 0G " ,
" side " : " B " ,
" limitPx " : " 0.59341 " ,
" sz " : " 52.0 " ,
" oid " : 333003526755 ,
" timestamp " : 1772276628506 ,
" triggerCondition " : " N/A " ,
" isTrigger " : false ,
" triggerPx " : " 0.0 " ,
" children " : [],
" isPositionTpsl " : false ,
" reduceOnly " : false ,
" orderType " : " Limit " ,
" origSz " : " 52.0 " ,
" tif " : " Alo " ,
" cloid " : " 0x00000000000000000000000000000318 "
}
A parent limit order can have up to 2 child orders (stop-loss and/or take-profit) attached:
{
" coin " : " AAVE " ,
" side " : " B " ,
" limitPx " : " 104.6 " ,
" sz " : " 1.94 " ,
" oid " : 332954766819 ,
" timestamp " : 1772272640873 ,
" triggerCondition " : " N/A " ,
" isTrigger " : false ,
" triggerPx " : " 0.0 " ,
" children " : [
{
" coin " : " AAVE " ,
" side " : " A " ,
" limitPx " : " 94.3 " ,
" sz " : " 1.94 " ,
" oid " : 332954766820 ,
" timestamp " : 1772272640873 ,
" triggerCondition " : " Price below 102.5 " ,
" isTrigger " : true ,
" triggerPx " : " 102.5 " ,
" children " : [],
" isPositionTpsl " : false ,
" reduceOnly " : true ,
" orderType " : " Stop Market " ,
" origSz " : " 1.94 " ,
" tif " : null ,
" cloid " : null
},
{
" coin " : " AAVE " ,
" side " : " A " ,
" limitPx " : " 102.0 " ,
" sz " : " 1.94 " ,
" oid " : 332954766821 ,
" timestamp " : 1772272640873 ,
" triggerCondition " : " Price above 110.87 " ,
" isTrigger " : true ,
" triggerPx " : " 110.87 " ,
" children " : [],
" isPositionTpsl " : false ,
" reduceOnly " : true ,
" orderType " : " Take Profit Market " ,
" origSz " : " 1.94 " ,
" tif " : null ,
" cloid " : null
}
],
" isPositionTpsl " : false ,
" reduceOnly " : false ,
" orderType " : " Limit " ,
" origSz " : " 1.94 " ,
" tif " : " Gtc " ,
" cloid " : null
}
An order where the trigger condition has already been met and the order is now active:
{
" coin " : " ARB " ,
" side " : " A " ,
" limitPx " : " 0.1099 " ,
" sz " : " 601.7 " ,
" oid " : 331886608601 ,
" timestamp " : 1772189655929 ,
" triggerCondition " : " Triggered " ,
" isTrigger " : false ,
" triggerPx " : " 0.0 " ,
" children " : [],
" isPositionTpsl " : false ,
" reduceOnly " : true ,
" orderType " : " Take Profit Limit " ,
" origSz " : " 601.7 " ,
" tif " : " Gtc " ,
" cloid " : null
}
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").
Message Size Configuration : Set gRPC max receive message length to at least 500 MB
Timeout : Use a generous timeout (60-120 seconds) for the RPC call due to the large response
Data Validation : Always validate JSON structure before processing
Error Recovery : Implement retry logic with exponential backoff
Resource Management : Close gRPC connections properly to avoid resource leaks
Streaming Alternative : For continuous updates, consider using StreamOrderbookSnapshots instead
Data Retention : Historical order book data is limited to a 24-hour rolling window
Rate Limits : Be mindful of request frequency to avoid overwhelming the service
Availability : This endpoint requires a dedicated node and is not available on shared infrastructure
Need help? Contact our support team or check the Hyperliquid gRPC documentation .