◈   ⌘ api · Intermediate

Binance API WebSocket: Real-Time Data for Crypto Traders

Learn how to use Binance API WebSocket streams for live price feeds, order book updates, and trade data with Python examples and practical tips.

Uncle Solieditor · voc · 14.03.2026 ·views 472
◈   Contents
  1. → What Is the Binance WebSocket API and Why Use It
  2. → Getting Started: Binance WebSocket Python Setup
  3. → Spot vs Futures WebSocket Streams on Binance
  4. → User Data Stream: Authenticating WebSocket for Private Data
  5. → Binance WebSocket Rate Limits and Connection Management
  6. → Using WebSocket Data in Real Trading Workflows
  7. → Frequently Asked Questions
  8. → Conclusion

REST APIs are great for snapshots. But if you're trading seriously — running bots, building dashboards, or reacting to market moves in milliseconds — you need a persistent connection that pushes data to you the moment something changes. That's exactly what the Binance API WebSocket delivers. Instead of hammering endpoints every second and burning through rate limits, you open one connection and let Binance stream prices, order book changes, and trade executions directly to your code. This guide walks through everything: setup, authentication, spot vs. futures streams, rate limits, and real Python examples you can actually run.

What Is the Binance WebSocket API and Why Use It

The Binance WebSocket API is a persistent, full-duplex connection between your application and Binance's servers using the WebSocket protocol. Once connected, data flows continuously without you needing to ask for it. Compare that to REST polling — if you're checking BTC price every 500ms, you're making 120 requests per minute and risking hitting rate limits. With WebSocket, one connection delivers every trade tick as it happens, with sub-100ms latency in most cases.

Binance offers WebSocket streams for spot markets, futures (USDT-M and COIN-M), and options. Competing platforms like Bybit and OKX have their own WebSocket implementations, but Binance's documentation is among the most complete and the stream variety is unmatched — over a dozen stream types covering everything from individual symbol tickers to full order book depth updates.

Getting Started: Binance WebSocket Python Setup

Before writing a single line of code, check the Binance API WebSocket documentation at the official Binance developer portal. The base URL for spot WebSocket streams is wss://stream.binance.com:9443, and for futures (USDT-M) it's wss://fstream.binance.com. Public market data streams require no API key — you just connect and subscribe. User data streams (your orders and balances) need authentication, which we'll cover below.

Install the dependencies first:

pip install websocket-client requests python-dotenv

Here's a minimal working example connecting to the Binance spot WebSocket and receiving live BTC/USDT trade data:

import websocket
import json

SYMBOL = "btcusdt"
STREAM_URL = f"wss://stream.binance.com:9443/ws/{SYMBOL}@aggTrade"

def on_message(ws, message):
    data = json.loads(message)
    price = float(data['p'])
    quantity = float(data['q'])
    side = 'BUY' if not data['m'] else 'SELL'
    print(f"{side} {quantity:.6f} BTC @ ${price:,.2f}")

def on_error(ws, error):
    print(f"WebSocket error: {error}")

def on_close(ws, close_status_code, close_msg):
    print(f"Connection closed: {close_status_code}")

def on_open(ws):
    print(f"Connected to Binance WebSocket stream for {SYMBOL.upper()}")

if __name__ == "__main__":
    ws = websocket.WebSocketApp(
        STREAM_URL,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
        on_open=on_open
    )
    ws.run_forever()
The 'm' field in aggTrade messages indicates whether the buyer is the market maker. If m=True, it was a sell order hitting the bid. If m=False, it was a buy order lifting the ask. This is how you determine trade direction from WebSocket data.

Spot vs Futures WebSocket Streams on Binance

The Binance API WebSocket behaves slightly differently for spot and futures markets. The endpoints differ, and futures streams carry additional fields — funding rates, mark price, liquidation orders — that don't exist in spot. If you're trading perpetuals on Binance Futures (or comparing with similar products on Bybit or OKX), you'll want the futures-specific streams.

Binance WebSocket Endpoints: Spot vs Futures
MarketBase WebSocket URLExample Stream
Spotwss://stream.binance.com:9443/ws/btcusdt@aggTrade
USDT-M Futureswss://fstream.binance.com/ws/btcusdt@aggTrade
COIN-M Futureswss://dstream.binance.com/ws/btcusd_perp@aggTrade
Testnet Spotwss://testnet.binance.vision/ws/btcusdt@aggTrade

For futures, the mark price stream is particularly valuable — it shows you the index-based price used for liquidations, not just the last trade price. Here's how to subscribe to the Binance API WebSocket futures mark price stream:

import websocket
import json

# Binance USDT-M Futures mark price stream
STREAM_URL = "wss://fstream.binance.com/ws/btcusdt@markPrice@1s"

def on_message(ws, message):
    data = json.loads(message)
    mark_price = float(data['p'])
    index_price = float(data['i'])
    funding_rate = float(data['r'])
    next_funding = data['T']
    print(f"Mark: ${mark_price:,.2f} | Index: ${index_price:,.2f} | Funding: {funding_rate*100:.4f}%")

ws = websocket.WebSocketApp(
    STREAM_URL,
    on_message=on_message,
    on_error=lambda ws, e: print(f"Error: {e}"),
    on_close=lambda ws, c, m: print("Closed")
)
ws.run_forever()

User Data Stream: Authenticating WebSocket for Private Data

Market data is public — anyone can connect. But to receive your own order fills, balance updates, and position changes over WebSocket, you need a user data stream. Authentication works differently here compared to REST: you first make a REST call to create a listen key, then connect to the WebSocket using that key. The listen key expires after 60 minutes unless you send a keepalive ping every 30 minutes.

import requests
import websocket
import json
import threading
import time
import os
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.getenv("BINANCE_API_KEY")
BASE_URL = "https://api.binance.com"

def get_listen_key():
    """Create a new user data stream listen key."""
    headers = {"X-MBX-APIKEY": API_KEY}
    response = requests.post(
        f"{BASE_URL}/api/v3/userDataStream",
        headers=headers
    )
    response.raise_for_status()
    return response.json()["listenKey"]

def keepalive_listen_key(listen_key):
    """Extend listen key validity — call every 30 minutes."""
    headers = {"X-MBX-APIKEY": API_KEY}
    requests.put(
        f"{BASE_URL}/api/v3/userDataStream",
        headers=headers,
        params={"listenKey": listen_key}
    )

def on_message(ws, message):
    data = json.loads(message)
    event_type = data.get('e')
    
    if event_type == 'executionReport':
        symbol = data['s']
        side = data['S']  # BUY or SELL
        status = data['X']  # NEW, FILLED, CANCELED, etc.
        price = data['p']
        qty = data['q']
        print(f"Order Update: {side} {qty} {symbol} @ {price} — {status}")
    
    elif event_type == 'outboundAccountPosition':
        balances = {b['a']: b['f'] for b in data['B'] if float(b['f']) > 0}
        print(f"Balance Update: {balances}")

def start_user_data_stream():
    listen_key = get_listen_key()
    print(f"Listen key obtained: {listen_key[:8]}...")
    
    # Keepalive thread — pings every 29 minutes
    def keepalive_loop():
        while True:
            time.sleep(29 * 60)
            keepalive_listen_key(listen_key)
            print("Listen key refreshed")
    
    threading.Thread(target=keepalive_loop, daemon=True).start()
    
    ws_url = f"wss://stream.binance.com:9443/ws/{listen_key}"
    ws = websocket.WebSocketApp(
        ws_url,
        on_message=on_message,
        on_error=lambda ws, e: print(f"Error: {e}"),
        on_close=lambda ws, c, m: print("User stream closed")
    )
    ws.run_forever()

if __name__ == "__main__":
    start_user_data_stream()
Never hardcode your API key in source code. Load it from environment variables or a .env file. A leaked Binance API key with withdrawal permissions is a serious security risk — restrict API key permissions to read-only and trading only, and whitelist your IP in the Binance API management panel.

Binance WebSocket Rate Limits and Connection Management

Understanding Binance API WebSocket limits is critical before going live. Binance enforces hard limits on how many streams you can open and how fast you can subscribe. Hitting these limits silently drops your connection or bans your IP — neither of which is obvious until your trading bot stops receiving data.

For robust production systems, implement automatic reconnection with exponential backoff. A simple reconnect loop catches dropped connections, but without backoff you risk hammering the server during an outage and triggering an IP ban. Here's a production-grade reconnect wrapper:

import websocket
import json
import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class BinanceWebSocket:
    def __init__(self, stream_url, on_data_callback):
        self.stream_url = stream_url
        self.on_data_callback = on_data_callback
        self.reconnect_delay = 1  # seconds, doubles on each failure
        self.max_reconnect_delay = 60
    
    def on_message(self, ws, message):
        self.reconnect_delay = 1  # Reset delay on successful message
        data = json.loads(message)
        self.on_data_callback(data)
    
    def on_error(self, ws, error):
        logger.error(f"WebSocket error: {error}")
    
    def on_close(self, ws, close_status_code, close_msg):
        logger.warning(f"Disconnected (code={close_status_code}). Reconnecting in {self.reconnect_delay}s...")
        time.sleep(self.reconnect_delay)
        self.reconnect_delay = min(self.reconnect_delay * 2, self.max_reconnect_delay)
        self.connect()
    
    def connect(self):
        logger.info(f"Connecting to {self.stream_url}")
        ws = websocket.WebSocketApp(
            self.stream_url,
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close
        )
        ws.run_forever(ping_interval=20, ping_timeout=10)

# Usage
def handle_price(data):
    if 'p' in data:
        print(f"BTC Price: ${float(data['p']):,.2f}")

client = BinanceWebSocket(
    "wss://stream.binance.com:9443/ws/btcusdt@aggTrade",
    handle_price
)
client.connect()

Using WebSocket Data in Real Trading Workflows

Raw WebSocket data is only useful if you do something with it. In practice, traders pipe Binance WebSocket streams into local order books, signal generation engines, or dashboards. Platforms like VoiceOfChain consume real-time price feeds from multiple exchanges to generate trading signals the moment market conditions change — that kind of low-latency reaction is only possible because WebSockets push data rather than waiting to be polled.

A common pattern is maintaining a local order book from the diff depth stream. You subscribe to the snapshot via REST, then apply incremental updates from the WebSocket to keep it current. This gives you a live view of market depth without the overhead of repeatedly fetching the full book. Traders using Binance, Bybit, or OKX often maintain parallel local books across exchanges to spot arbitrage opportunities or compare liquidity.

Another popular use case: feeding candle data from the Binance WebSocket kline stream into a technical indicator library like TA-Lib or pandas-ta. Every time a new candle closes, your code recalculates RSI, MACD, or whatever indicator you use, and fires an alert or places an order if conditions are met. This is the core loop of most retail algorithmic trading setups built on Binance.

When running multiple WebSocket connections — for example, monitoring 20 symbols across spot and futures — use asyncio with websockets library instead of threading. It handles hundreds of concurrent connections with far less memory overhead than threads, and is the standard approach for production trading systems.

Frequently Asked Questions

Do I need an API key to use Binance WebSocket streams?
No API key is required for public market data streams like price tickers, order book depth, and trade history. You only need an API key — and a listen key obtained via REST — when subscribing to your personal user data stream for order fills and balance updates.
What is the difference between Binance spot and futures WebSocket endpoints?
Spot streams use wss://stream.binance.com:9443 while USDT-M futures streams use wss://fstream.binance.com. Futures streams carry additional data like mark price, funding rate, and liquidation events that don't exist in spot markets.
How do I prevent my Binance WebSocket connection from dropping?
Send a ping every 20 seconds using ping_interval in websocket-client, and implement an on_close handler that automatically reconnects with exponential backoff. Also note that Binance forces a disconnect after 24 hours regardless — your code must handle daily reconnects gracefully.
How many WebSocket streams can I open on Binance at once?
You can subscribe to up to 1024 streams per connection using the combined stream endpoint. You're also limited to 300 new connections per 5 minutes per IP address. For large-scale applications, use combined streams to pack multiple subscriptions into a single connection.
Can I use the Binance WebSocket API with Python on a Raspberry Pi or VPS?
Yes. The websocket-client library works on any Python 3.7+ environment including Raspberry Pi and Linux VPS. For latency-sensitive strategies, a VPS close to Binance's servers (typically AWS Tokyo or Singapore) will give you significantly faster data delivery than a home connection.
Is there an official Binance Python WebSocket library?
Binance maintains the binance-connector-python library on GitHub which includes WebSocket support with automatic reconnection. For more control, many developers use python-binance (community library) or build directly on websocket-client as shown in this guide. The official Binance API WebSocket documentation covers all stream formats in detail.

Conclusion

The Binance API WebSocket is the foundation of any serious real-time trading system. Whether you're building a price alert bot, a live dashboard, or a fully automated strategy that reacts to order book changes in milliseconds, WebSocket connections are the only practical way to get there. REST polling simply can't compete on latency or efficiency at scale.

Start with the public aggTrade or bookTicker streams — no auth required, immediate feedback, and you'll understand the data structure within minutes. Add reconnection logic before you go anywhere near live money. When you're ready to act on signals rather than just display them, layer in the user data stream to track your own fills in real time. Tools like VoiceOfChain take this further by aggregating real-time feeds across markets to surface actionable trading signals — that's the practical end-state of what you build when you master the WebSocket layer. The infrastructure is simpler than it looks once you have working code in front of you.

◈   more on this topic
◉ basics Mastering the ccxt library documentation for crypto traders ⌂ exchanges Mastering the Binance CCXT Library for Crypto Traders ⌬ bots Best Crypto Trading Bots 2025: Profitable AI-Powered Strategies