Order Book WebSocket API
Watch the WebSocket Walkthrough
Get an overview of the Dwellir-hosted Hyperliquid order book server, including deployment architecture and how to stream ultra-low latency data into your trading stack.
Overview
Dwellir provides a high-performance WebSocket server delivering real-time order book data from Hyperliquid with ultra-low latency. This service offers Level 2 (L2), Level 4 (L4), and trades streaming directly from Hyperliquid nodes, significantly faster than public API endpoints.
Key Features
- Ultra-low latency - Direct node connectivity eliminates public API overhead
 - Full order book depth - Access to L4 data with individual order visibility
 - Real-time streaming - WebSocket push model for immediate updates
 - Efficient compression - Optimized bandwidth usage for high-frequency data
 - Institutional grade - Professional infrastructure with monitoring and support
 
Hosted Service by Dwellir
For production use cases requiring minimum latency, Dwellir offers hosted WebSocket servers with:
- Direct Hyperliquid node connectivity for fastest possible data access
 - Geographic distribution for optimal routing
 - Professional infrastructure and 24/7 monitoring
 - Significantly faster than public API endpoints (~10-50ms improvement)
 
📧 Contact: ben@dwellir.com for access to hosted instances
Quick Start
📦 Complete, runnable code examples: github.com/dwellir-public/hyperliquid-orderbook-server-code-examples
The repository includes 6 progressive examples covering:
- Basic WebSocket connections
 - L2 and L4 order books
 - Multiple subscriptions
 - Reconnection handling
 - Market data analysis
 
Clone it to get started quickly with your own trading applications.
- Python
 - JavaScript
 
#!/usr/bin/env python3
"""
Simple Hyperliquid WebSocket API Example using Dwellir
Subscribes to BTC trades and displays incoming messages
"""
import asyncio
import json
import websockets
async def main():
    # Contact ben@dwellir.com for server details
    ws_url = "wss://your-instance.dwellir.com/ws"
    # Connect to WebSocket
    print(f"Connecting to {ws_url}...")
    websocket = await websockets.connect(ws_url)
    print("Connected!")
    # Subscribe to BTC trades
    subscribe_message = {
        "method": "subscribe",
        "subscription": {
            "type": "trades",
            "coin": "BTC"
        }
    }
    await websocket.send(json.dumps(subscribe_message))
    print("Subscribed to BTC trades\n")
    # Listen for messages
    try:
        async for message in websocket:
            data = json.loads(message)
            print(f"Received: {json.dumps(data, indent=2)}\n")
    except KeyboardInterrupt:
        print("\nStopping...")
    finally:
        await websocket.close()
        print("Disconnected")
if __name__ == "__main__":
    asyncio.run(main())
const WebSocket = require('ws');
// Contact ben@dwellir.com for server details
const wsUrl = 'wss://your-instance.dwellir.com/ws';
console.log(`Connecting to ${wsUrl}...`);
const ws = new WebSocket(wsUrl);
ws.on('open', () => {
    console.log('Connected!');
    // Subscribe to BTC trades
    const subscription = {
        method: 'subscribe',
        subscription: {
            type: 'trades',
            coin: 'BTC'
        }
    };
    ws.send(JSON.stringify(subscription));
    console.log('Subscribed to BTC trades\n');
});
ws.on('message', (data) => {
    const message = JSON.parse(data);
    console.log('Received:', JSON.stringify(message, null, 2), '\n');
});
ws.on('error', (error) => {
    console.error('WebSocket error:', error);
});
ws.on('close', () => {
    console.log('Disconnected');
});
API Documentation
WebSocket Endpoint
wss://<your-instance>.dwellir.com/ws
The server exposes a single WebSocket endpoint for all data streaming. Clients send JSON messages to manage subscriptions and receive real-time market data updates.
Connection Management
- Connect to the WebSocket endpoint
 - Subscribe to desired data streams
 - Receive real-time updates
 - Handle reconnections gracefully
 
The orderbook server software may exit from time to time if the L2 or L4 orderbook falls out of sync. Your client implementation must include automatic reconnection logic with exponential backoff to maintain continuous data feeds during these restarts.
Message Protocol
Client → Server Messages
Subscribe to Data Stream
{
  "method": "subscribe",
  "subscription": {
    // Subscription configuration (see types below)
  }
}
Unsubscribe from Data Stream
{
  "method": "unsubscribe",
  "subscription": {
    // Same subscription object used to subscribe
  }
}
Server → Client Messages
Subscription Confirmation
{
  "channel": "subscriptionResponse",
  "data": {
    "method": "subscribe",
    "subscription": {
      // Echoed subscription details
    }
  }
}
Error Messages
{
  "channel": "error",
  "data": "Descriptive error message"
}
Common errors:
"Invalid subscription: coin not found"- Unsupported trading pair"Invalid subscription: n_levels too high"- Exceeds 100 level limit"Already subscribed"- Duplicate subscription attempt"Order book not ready"- Server still initializing
Subscription Types
1. Trades Stream
Real-time trade executions for a specific coin.
Subscribe
{
  "type": "trades",
  "coin": "BTC"
}
Response Stream
{
  "channel": "trades",
  "data": [
    {
      "coin": "BTC",
      "side": "A",              // "A" = Ask (sell), "B" = Bid (buy)
      "px": "106296.0",         // Execution price
      "sz": "0.00017",          // Trade size
      "time": 1751430933565,    // Unix timestamp (ms)
      "hash": "0xde93a8a0...",  // Transaction hash
      "tid": 293353986402527,   // Trade ID
      "users": [
        "0xcc0a3b6e...",       // Buyer address
        "0xc64cc00b..."        // Seller address
      ]
    }
  ]
}
2. L2 Order Book
Level 2 order book with price level aggregation.
Subscribe
{
  "type": "l2Book",
  "coin": "BTC",
  "nSigFigs": 3,      // Optional: 2-5, price aggregation
  "nLevels": 50,      // Optional: 1-100, default 20
  "mantissa": 5       // Optional: 2 or 5, requires nSigFigs=5
}
Response Stream
{
  "channel": "l2Book",
  "data": {
    "coin": "BTC",
    "time": 1751427259657,
    "levels": [
      [  // Bid levels [price, size, order count]
        {"px": "106217.0", "sz": "0.001", "n": 1},
        {"px": "106215.0", "sz": "0.001", "n": 1},
        {"px": "106213.0", "sz": "0.27739", "n": 1}
      ],
      [  // Ask levels
        {"px": "106233.0", "sz": "0.26739", "n": 3},
        {"px": "106258.0", "sz": "0.001", "n": 1},
        {"px": "106270.0", "sz": "0.49128", "n": 2}
      ]
    ]
  }
}
3. L4 Order Book
Level 4 order book with individual order visibility - the most detailed market microstructure data available.
Subscribe
{
  "type": "l4Book",
  "coin": "BTC"
}
Initial Snapshot
{
  "channel": "l4Book",
  "data": {
    "coin": "BTC",
    "time": 1751427259657,
    "height": 123456,
    "levels": [
      [  // Bid orders (individual)
        {
          "user": "0xcc0a3b6e...",
          "coin": "BTC",
          "side": "B",
          "limitPx": "106200.0",
          "sz": "0.5",
          "oid": 12345678,
          "timestamp": 1751427259657,
          "triggerCondition": "",
          "isTrigger": false,
          "triggerPx": "",
          "isPositionTpsl": false,
          "reduceOnly": false,
          "orderType": "limit",
          "tif": "GTC",
          "cloid": null
        }
      ],
      [  // Ask orders (individual)
        // Individual ask order objects
      ]
    ]
  }
}
Incremental Updates
{
  "channel": "l4Book",
  "data": {
    "time": 1751427259657,
    "height": 123457,
    "orderStatuses": [
      // Order status changes (fills, cancellations)
    ],
    "bookDiffs": [
      // Order book modifications (new, update, remove)
    ]
  }
}
Implementation Examples
All examples below are available in the code examples repository with full implementations and instructions.
Example 1: L2 Order Book with Spread Display
Display real-time order book data with bid/ask spreads:
#!/usr/bin/env python3
"""
L2 Order Book Example - Aggregated Price Levels
Shows bid/ask spreads with price aggregation
"""
import asyncio
import json
import websockets
def display_orderbook(data):
    """Display the order book in a simple format"""
    if data.get("channel") != "l2Book":
        return
    coin = data["data"]["coin"]
    levels = data["data"]["levels"]
    print(f"\n{'='*50}")
    print(f"📊 {coin} Order Book")
    print(f"{'='*50}")
    # Display asks (sellers) - reverse order
    print("\n🔴 ASKS (Sellers)")
    print(f"{'Price':<15} {'Size':<15} {'Orders':<10}")
    print("-" * 50)
    for ask in reversed(levels[1][:5]):  # Top 5 asks
        print(f"{ask['px']:<15} {ask['sz']:<15} {ask['n']:<10}")
    # Calculate spread
    best_bid = float(levels[0][0]['px']) if levels[0] else 0
    best_ask = float(levels[1][0]['px']) if levels[1] else 0
    spread = best_ask - best_bid
    spread_pct = (spread / best_bid * 100) if best_bid > 0 else 0
    print(f"\n{'─'*50}")
    print(f"💰 Spread: ${spread:.2f} ({spread_pct:.3f}%)")
    print(f"{'─'*50}\n")
    # Display bids (buyers)
    print("🟢 BIDS (Buyers)")
    print(f"{'Price':<15} {'Size':<15} {'Orders':<10}")
    print("-" * 50)
    for bid in levels[0][:5]:  # Top 5 bids
        print(f"{bid['px']:<15} {bid['sz']:<15} {bid['n']:<10}")
async def main():
    ws_url = "wss://your-instance.dwellir.com/ws"
    websocket = await websockets.connect(ws_url)
    print("Connected!\n")
    # Subscribe to ETH L2 order book
    subscribe_message = {
        "method": "subscribe",
        "subscription": {
            "type": "l2Book",
            "coin": "ETH",
            "nLevels": 10,
            "nSigFigs": 5
        }
    }
    await websocket.send(json.dumps(subscribe_message))
    try:
        async for message in websocket:
            data = json.loads(message)
            display_orderbook(data)
    except KeyboardInterrupt:
        await websocket.close()
if __name__ == "__main__":
    asyncio.run(main())
Example 2: Multiple Subscriptions
Handle multiple coins and data types simultaneously:
#!/usr/bin/env python3
"""
Multiple Subscriptions Example
Subscribe to different data types and coins simultaneously
"""
import asyncio
import json
import websockets
from datetime import datetime
def handle_trade(data):
    """Handle incoming trade data"""
    for trade in data["data"]:
        coin = trade.get("coin")
        side_icon = "🟢" if trade["side"] == "B" else "🔴"
        timestamp = datetime.fromtimestamp(trade["time"] / 1000)
        print(f"{side_icon} {coin}: {trade['side']} {trade['sz']} @ ${trade['px']} | {timestamp.strftime('%H:%M:%S')}")
def handle_l2_book(data):
    """Handle incoming L2 order book data"""
    coin = data["data"]["coin"]
    levels = data["data"]["levels"]
    if levels[0] and levels[1]:
        bid = levels[0][0]['px']
        ask = levels[1][0]['px']
        spread = float(ask) - float(bid)
        print(f"📊 {coin} Book: Bid ${bid} | Ask ${ask} | Spread ${spread:.2f}")
async def main():
    ws_url = "wss://your-instance.dwellir.com/ws"
    websocket = await websockets.connect(ws_url)
    # Subscribe to BTC trades
    await websocket.send(json.dumps({
        "method": "subscribe",
        "subscription": {"type": "trades", "coin": "BTC"}
    }))
    # Subscribe to ETH trades
    await websocket.send(json.dumps({
        "method": "subscribe",
        "subscription": {"type": "trades", "coin": "ETH"}
    }))
    # Subscribe to SOL L2 order book
    await websocket.send(json.dumps({
        "method": "subscribe",
        "subscription": {"type": "l2Book", "coin": "SOL", "nLevels": 5}
    }))
    try:
        async for message in websocket:
            data = json.loads(message)
            channel = data.get("channel")
            if channel == "trades":
                handle_trade(data)
            elif channel == "l2Book":
                handle_l2_book(data)
    except KeyboardInterrupt:
        await websocket.close()
if __name__ == "__main__":
    asyncio.run(main())
Example 3: Robust Client with Reconnection
Production-ready client with automatic reconnection:
#!/usr/bin/env python3
"""
Robust WebSocket Client with Reconnection
Handles disconnections and automatically reconnects
"""
import asyncio
import json
import websockets
class RobustWSClient:
    """WebSocket client with automatic reconnection"""
    def __init__(self, ws_url):
        self.ws_url = ws_url
        self.websocket = None
        self.subscriptions = []
        self.is_running = False
        self.reconnect_delay = 1
        self.max_reconnect_delay = 60
    def add_subscription(self, sub_type, coin, **kwargs):
        """Add a subscription to track"""
        sub = {
            "method": "subscribe",
            "subscription": {
                "type": sub_type,
                "coin": coin,
                **kwargs
            }
        }
        self.subscriptions.append(sub)
    async def connect(self):
        """Connect and subscribe to all tracked subscriptions"""
        try:
            self.websocket = await websockets.connect(self.ws_url)
            print(f"✅ Connected to {self.ws_url}")
            # Resubscribe to all subscriptions
            for sub in self.subscriptions:
                await self.websocket.send(json.dumps(sub))
                coin = sub["subscription"]["coin"]
                sub_type = sub["subscription"]["type"]
                print(f"✅ Subscribed to {coin} {sub_type}")
            # Reset reconnect delay
            self.reconnect_delay = 1
        except Exception as e:
            print(f"❌ Connection failed: {e}")
            raise
    async def listen(self):
        """Listen for messages with automatic reconnection"""
        self.is_running = True
        while self.is_running:
            try:
                if not self.websocket:
                    await self.connect()
                async for message in self.websocket:
                    data = json.loads(message)
                    self.handle_message(data)
            except websockets.exceptions.ConnectionClosed:
                print(f"⚠️  Connection closed. Reconnecting in {self.reconnect_delay}s...")
                await asyncio.sleep(self.reconnect_delay)
                # Exponential backoff
                self.reconnect_delay = min(self.reconnect_delay * 2, self.max_reconnect_delay)
                self.websocket = None
            except Exception as e:
                print(f"❌ Error: {e}")
                await asyncio.sleep(self.reconnect_delay)
                self.websocket = None
    def handle_message(self, data):
        """Process incoming messages"""
        channel = data.get("channel")
        if channel == "trades":
            for trade in data["data"]:
                side_icon = "🟢" if trade["side"] == "B" else "🔴"
                print(f"{side_icon} {trade['coin']}: {trade['sz']} @ ${trade['px']}")
        elif channel == "l2Book":
            coin = data["data"]["coin"]
            levels = data["data"]["levels"]
            if levels[0] and levels[1]:
                bid = levels[0][0]['px']
                ask = levels[1][0]['px']
                spread = float(ask) - float(bid)
                print(f"📊 {coin}: Bid ${bid} | Ask ${ask} | Spread ${spread:.2f}")
async def main():
    ws_url = "wss://your-instance.dwellir.com/ws"
    client = RobustWSClient(ws_url)
    client.add_subscription("trades", "BTC")
    client.add_subscription("l2Book", "ETH", nLevels=5)
    print("🚀 Starting robust WebSocket client...\n")
    try:
        await client.listen()
    except KeyboardInterrupt:
        print("\nStopping...")
        client.is_running = False
if __name__ == "__main__":
    asyncio.run(main())
Example 4: Market Metrics and Analysis
Calculate real-time market statistics:
#!/usr/bin/env python3
"""
Market Metrics and Data Analysis
Calculate VWAP, spreads, volume, and more
"""
import asyncio
import json
import websockets
from collections import deque
class MarketAnalyzer:
    """Analyze market data and calculate metrics"""
    def __init__(self, history_size=100):
        self.trades = deque(maxlen=history_size)
        self.spreads = deque(maxlen=history_size)
    def add_trade(self, price, size, side):
        """Add trade and update metrics"""
        self.trades.append({
            'price': float(price),
            'size': float(size),
            'side': side
        })
    def get_vwap(self):
        """Calculate Volume-Weighted Average Price"""
        if not self.trades:
            return 0
        total_value = sum(t['price'] * t['size'] for t in self.trades)
        total_volume = sum(t['size'] for t in self.trades)
        return total_value / total_volume if total_volume > 0 else 0
    def get_buy_sell_ratio(self):
        """Calculate buy/sell volume ratio"""
        buy_vol = sum(t['size'] for t in self.trades if t['side'] == 'B')
        sell_vol = sum(t['size'] for t in self.trades if t['side'] == 'A')
        return buy_vol / sell_vol if sell_vol > 0 else float('inf')
    def display_stats(self, coin):
        """Display current market statistics"""
        if not self.trades:
            return
        print(f"\n{'='*60}")
        print(f"📈 {coin} Market Analytics")
        print(f"{'='*60}")
        print(f"💰 VWAP: ${self.get_vwap():.2f}")
        print(f"📊 Trades: {len(self.trades)}")
        print(f"⚖️  Buy/Sell Ratio: {self.get_buy_sell_ratio():.2f}")
        print(f"{'='*60}\n")
async def main():
    ws_url = "wss://your-instance.dwellir.com/ws"
    websocket = await websockets.connect(ws_url)
    # Subscribe to BTC trades
    await websocket.send(json.dumps({
        "method": "subscribe",
        "subscription": {"type": "trades", "coin": "BTC"}
    }))
    analyzer = MarketAnalyzer()
    trade_count = 0
    try:
        async for message in websocket:
            data = json.loads(message)
            if data.get("channel") == "trades":
                for trade in data["data"]:
                    analyzer.add_trade(trade["px"], trade["sz"], trade["side"])
                    trade_count += 1
                    # Display stats every 10 trades
                    if trade_count % 10 == 0:
                        analyzer.display_stats("BTC")
    except KeyboardInterrupt:
        analyzer.display_stats("BTC")  # Final stats
        await websocket.close()
if __name__ == "__main__":
    asyncio.run(main())
More Examples
The code examples repository includes additional examples:
- Multi-coin tracker: Track order books and trades for multiple coins
 - Advanced order book analysis: Calculate order book imbalances and liquidity metrics
 - Data export: Save market data to CSV or database
 
Each example is fully documented with setup instructions and learning objectives.
Performance & Technical Specifications
Latency Characteristics
Based on real-world benchmarking of 2,662 matched trades:
| Metric | Public API | Dwellir WebSocket | Improvement | 
|---|---|---|---|
| Mean Latency | 367.60ms | 338.88ms | 28.72ms faster (8.5%) | 
| Median Latency | 263.00ms | 212.00ms | 51.00ms faster (24.1%) | 
| Min Latency | 90.00ms | 77.00ms | 13.00ms faster (16.9%) | 
| Max Latency | 9,118.00ms | 1,977.00ms | 7,141.00ms faster (361.2%) | 
Performance Victory Rate
In head-to-head comparison:
- WebSocket has lower latency: 75.5% (2,010 out of 2,662 trades)
 
The WebSocket server delivers data faster in 3 out of 4 cases, with significantly more consistent performance and protection against extreme latency spikes.
Throughput Capabilities
- Message Rate: Handles thousands of updates per second
 - Concurrent Subscriptions: Multiple coins and data types per connection
 - Compression: Levels 0-9 configurable for bandwidth optimization
 - Connection Limit: Contact for dedicated capacity requirements
 
Data Guarantees
- Ordering: Updates delivered in blockchain order
 - Consistency: Block-level atomicity for state changes
 - Reliability: Automatic reconnection with state recovery
 - Completeness: No dropped messages under normal conditions
 
Use Cases
High-Frequency Trading
- Direct L4 book access for optimal order placement
 - Minimal latency for arbitrage opportunities
 - Full market depth visibility for advanced strategies
 
Market Making
- Real-time spread monitoring and adjustment
 - Order book imbalance detection
 - Individual order tracking via L4 data
 - Inventory management with position tracking
 
Analytics & Research
- Complete trade history streaming
 - Order flow analysis and toxicity detection
 - Market microstructure studies
 - Volume and liquidity profiling
 
Risk Management
- Real-time position monitoring
 - Liquidity assessment for large orders
 - Market impact modeling
 - Volatility tracking and alerts
 
Best Practices
Connection Management
import asyncio
import websockets
import logging
class ResilientWebSocket:
    def __init__(self, uri):
        self.uri = uri
        self.reconnect_delay = 5
        
    async def connect_with_retry(self):
        while True:
            try:
                async with websockets.connect(self.uri) as ws:
                    logging.info("Connected to WebSocket")
                    await self.handle_connection(ws)
            except Exception as e:
                logging.error(f"Connection error: {e}")
                await asyncio.sleep(self.reconnect_delay)
    
    async def handle_connection(self, ws):
        # Your message handling logic here
        pass
Rate Limiting & Throttling
- Batch subscription requests when connecting
 - Implement exponential backoff for reconnections
 - Monitor message queue depth to detect backpressure
 
Data Processing
- Use separate threads/processes for heavy computations
 - Implement ring buffers for high-frequency updates
 - Consider using binary protocols for internal distribution
 
Get Started with Dwellir
Hosted WebSocket Service
Dwellir offers production-ready WebSocket servers with:
✅ Direct node connectivity - Fastest possible data access
✅ Geographic distribution - Servers in key trading locations
✅ 99.99% uptime SLA - Enterprise reliability
✅ Dedicated support - Direct access to engineering team
✅ Custom configurations - Tailored to your requirements
Contact Us
Ready to integrate ultra-low latency Hyperliquid data into your trading systems?
📧 Email: ben@dwellir.com
🌐 Website: dwellir.com
📊 Dashboard: dashboard.dwellir.com
Get in touch for:
- API credentials and server endpoints
 - Custom data requirements
 - Enterprise pricing
 - Technical integration support
 - Performance benchmarks for your use case
 
Code Examples & Resources
📦 Code Examples Repository - Complete, runnable examples in Python covering:
- WebSocket basics and connection handling
 - L2 and L4 order book processing
 - Multiple subscriptions and data routing
 - Production-ready reconnection logic
 - Market data analysis and metrics
 
🔧 Hyperliquid Order Book Server - Official server implementation for self-hosting
Access institutional-grade Hyperliquid market data with Dwellir's ultra-low latency WebSocket infrastructure. Contact us → to get started.