Binance WebSocket API Guide
The Binance WebSocket API provides real-time access to cryptocurrency market data and trading updates with minimal latency. Unlike REST APIs that require polling for updates, the binance websocket api establishes a persistent connection that pushes data to your application as events occur. This guide covers everything you need to connect to Binance WebSocket streams, handle different data types, and implement robust reconnection logic.
Binance operates one of the largest cryptocurrency exchanges globally, and their WebSocket infrastructure is designed to handle millions of concurrent connections. Whether you’re building a trading bot, price tracker, or market analysis tool, understanding how to properly implement binance websocket connections is essential for reliable real-time data access.
Understanding Binance WebSocket Endpoints
Binance provides separate WebSocket endpoints for different markets and data types. The primary distinction is between spot trading and futures trading, each with dedicated base URLs.
Spot Market WebSocket Endpoints
For spot trading data, Binance offers these endpoints:
- Main Spot Stream:
wss://stream.binance.com:9443/ws - Combined Streams:
wss://stream.binance.com:9443/stream
The difference between these endpoints relates to how you subscribe to streams. The /ws endpoint is for single stream connections, while /stream allows you to combine multiple streams in one connection.
Futures Market WebSocket Endpoints
Binance futures trading uses different endpoints:
- USD-M Futures Stream:
wss://fstream.binance.com/ws - USD-M Combined Streams:
wss://fstream.binance.com/stream - COIN-M Futures Stream:
wss://dstream.binance.com/ws - COIN-M Combined Streams:
wss://dstream.binance.com/stream
USD-M futures are settled in USDT, while COIN-M futures are settled in cryptocurrency. Choose the appropriate endpoint based on your trading requirements.
Connecting to Binance WebSocket Streams
The binance api websocket uses standard WebSocket protocol connections. You can connect using any WebSocket client library in your preferred programming language.
Basic Connection in JavaScript
Here’s how to establish a basic connection to a Binance WebSocket stream:
const symbol = 'btcusdt';
const streamName = `${symbol}@trade`;
const wsUrl = `wss://stream.binance.com:9443/ws/${streamName}`;
const ws = new WebSocket(wsUrl);
ws.onopen = () => {
console.log('Connected to Binance WebSocket');
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Trade event:', data);
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
ws.onclose = (event) => {
console.log('Connection closed:', event.code, event.reason);
};
This example connects to the trade stream for Bitcoin/USDT. The connection remains open until explicitly closed or a network error occurs.
Node.js WebSocket Connection
For Node.js applications, you’ll need the ws library:
const WebSocket = require('ws');
const symbol = 'ethusdt';
const streamName = `${symbol}@ticker`;
const wsUrl = `wss://stream.binance.com:9443/ws/${streamName}`;
const ws = new WebSocket(wsUrl);
ws.on('open', () => {
console.log('Connected to Binance');
});
ws.on('message', (data) => {
const ticker = JSON.parse(data);
console.log(`${ticker.s} Price: ${ticker.c}`);
});
ws.on('error', (error) => {
console.error('Error:', error.message);
});
ws.on('close', () => {
console.log('Connection closed');
});
For more details on JavaScript WebSocket implementation patterns, see our JavaScript WebSocket guide.
Individual Stream Types
The websocket binance infrastructure supports multiple stream types, each providing different market data. Understanding each stream type helps you choose the right data source for your application.
Ticker Streams
Ticker streams provide 24-hour rolling window statistics for a symbol. There are two types: individual symbol tickers and mini tickers.
Individual Symbol Ticker (<symbol>@ticker):
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@ticker');
ws.onmessage = (event) => {
const ticker = JSON.parse(event.data);
console.log({
symbol: ticker.s,
priceChange: ticker.p,
priceChangePercent: ticker.P,
lastPrice: ticker.c,
volume: ticker.v,
quoteVolume: ticker.q,
openPrice: ticker.o,
highPrice: ticker.h,
lowPrice: ticker.l
});
};
Mini Ticker (<symbol>@miniTicker):
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@miniTicker');
ws.onmessage = (event) => {
const mini = JSON.parse(event.data);
console.log({
symbol: mini.s,
close: mini.c,
open: mini.o,
high: mini.h,
low: mini.l,
volume: mini.v,
quoteVolume: mini.q
});
};
Mini tickers use less bandwidth and are ideal when you only need basic price information.
Depth Streams (Order Book)
Depth streams provide order book updates in real-time. Binance offers partial book depth at specific levels and full order book diff streams.
Partial Book Depth (<symbol>@depth<levels>):
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@depth10');
ws.onmessage = (event) => {
const depth = JSON.parse(event.data);
console.log('Bids:', depth.bids.slice(0, 5));
console.log('Asks:', depth.asks.slice(0, 5));
console.log('Last Update ID:', depth.lastUpdateId);
};
Available levels are 5, 10, and 20. These streams send full snapshots at regular intervals (100ms or 1000ms).
Diff Depth Stream (<symbol>@depth):
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@depth');
ws.onmessage = (event) => {
const diff = JSON.parse(event.data);
console.log({
eventType: diff.e,
symbol: diff.s,
firstUpdateId: diff.U,
finalUpdateId: diff.u,
bids: diff.b,
asks: diff.a
});
};
The diff stream sends only changes to the order book, requiring you to maintain a local order book state.
Kline/Candlestick Streams
Kline streams provide candlestick data for technical analysis. The binance websocket stream supports multiple timeframes.
const interval = '1m'; // 1m, 5m, 15m, 1h, 4h, 1d, 1w, 1M
const ws = new WebSocket(`wss://stream.binance.com:9443/ws/btcusdt@kline_${interval}`);
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
const kline = message.k;
console.log({
symbol: kline.s,
interval: kline.i,
openTime: new Date(kline.t),
closeTime: new Date(kline.T),
open: kline.o,
high: kline.h,
low: kline.l,
close: kline.c,
volume: kline.v,
isClosed: kline.x
});
};
The isClosed field indicates whether the kline is finalized. Use this to avoid processing incomplete candles.
Trade Streams
Trade streams provide real-time information about individual trades as they execute on the exchange.
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@trade');
ws.onmessage = (event) => {
const trade = JSON.parse(event.data);
console.log({
symbol: trade.s,
tradeId: trade.t,
price: trade.p,
quantity: trade.q,
buyerOrderId: trade.b,
sellerOrderId: trade.a,
tradeTime: new Date(trade.T),
isBuyerMaker: trade.m
});
};
The isBuyerMaker field indicates market direction. When true, the buyer placed a maker order (limit order), and the seller took it with a market order.
Combined Streams
Combined streams allow you to subscribe to multiple data streams through a single WebSocket connection. This approach is more efficient than opening separate connections for each stream.
Subscribing to Multiple Streams
const streams = [
'btcusdt@trade',
'ethusdt@trade',
'btcusdt@ticker',
'ethusdt@ticker'
];
const wsUrl = `wss://stream.binance.com:9443/stream?streams=${streams.join('/')}`;
const ws = new WebSocket(wsUrl);
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log('Stream:', message.stream);
console.log('Data:', message.data);
};
Combined stream messages wrap the actual data in an object with stream and data properties.
Dynamic Stream Subscription
You can also subscribe and unsubscribe from streams dynamically after the connection is established:
const ws = new WebSocket('wss://stream.binance.com:9443/ws');
ws.onopen = () => {
// Subscribe to streams
ws.send(JSON.stringify({
method: 'SUBSCRIBE',
params: [
'btcusdt@trade',
'ethusdt@ticker'
],
id: 1
}));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.result === null) {
console.log('Subscription confirmed');
} else {
console.log('Stream data:', message);
}
};
// Later, unsubscribe from a stream
function unsubscribe(streams) {
ws.send(JSON.stringify({
method: 'UNSUBSCRIBE',
params: streams,
id: 2
}));
}
Dynamic subscription is useful for applications that need to change their data sources based on user actions or trading strategies.
User Data Streams
User data streams provide real-time updates about your account activity, including order updates, balance changes, and execution reports. These streams require authentication through a listen key.
Creating a Listen Key
Before connecting to a user data stream, you must obtain a listen key from Binance’s REST API:
async function createListenKey() {
const response = await fetch('https://api.binance.com/api/v3/userDataStream', {
method: 'POST',
headers: {
'X-MBX-APIKEY': 'your_api_key_here'
}
});
const data = await response.json();
return data.listenKey;
}
Connecting to User Data Stream
async function connectUserDataStream() {
const listenKey = await createListenKey();
const ws = new WebSocket(`wss://stream.binance.com:9443/ws/${listenKey}`);
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
switch (update.e) {
case 'executionReport':
console.log('Order update:', {
symbol: update.s,
orderId: update.i,
orderStatus: update.X,
price: update.p,
quantity: update.q,
executedQty: update.z
});
break;
case 'outboundAccountPosition':
console.log('Account update:', update.B);
break;
case 'balanceUpdate':
console.log('Balance changed:', {
asset: update.a,
delta: update.d
});
break;
}
};
// Keep the listen key alive
setInterval(async () => {
await fetch(`https://api.binance.com/api/v3/userDataStream?listenKey=${listenKey}`, {
method: 'PUT',
headers: {
'X-MBX-APIKEY': 'your_api_key_here'
}
});
}, 30 * 60 * 1000); // Every 30 minutes
return ws;
}
Listen keys expire after 60 minutes of inactivity. Send a keepalive request every 30 minutes to maintain the connection.
Reconnection Handling
WebSocket connections can drop due to network issues, server maintenance, or rate limiting. Implementing robust reconnection logic ensures your application maintains data continuity.
Automatic Reconnection Strategy
class BinanceWebSocket {
constructor(streamName) {
this.streamName = streamName;
this.ws = null;
this.reconnectDelay = 1000;
this.maxReconnectDelay = 60000;
this.reconnectAttempts = 0;
}
connect() {
const url = `wss://stream.binance.com:9443/ws/${this.streamName}`;
this.ws = new WebSocket(url);
this.ws.onopen = () => {
console.log('Connected to Binance');
this.reconnectDelay = 1000;
this.reconnectAttempts = 0;
};
this.ws.onmessage = (event) => {
this.handleMessage(JSON.parse(event.data));
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
this.ws.onclose = (event) => {
console.log(`Connection closed: ${event.code}`);
this.scheduleReconnect();
};
}
scheduleReconnect() {
this.reconnectAttempts++;
const delay = Math.min(
this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1),
this.maxReconnectDelay
);
console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
setTimeout(() => this.connect(), delay);
}
handleMessage(data) {
// Process incoming data
console.log(data);
}
close() {
if (this.ws) {
this.ws.close();
}
}
}
// Usage
const binanceWs = new BinanceWebSocket('btcusdt@trade');
binanceWs.connect();
This implementation uses exponential backoff to avoid overwhelming the server during connection issues. For more information on close codes, see our guide on WebSocket close codes.
Handling Specific Close Codes
Different close codes require different handling strategies:
ws.onclose = (event) => {
switch (event.code) {
case 1000: // Normal closure
console.log('Connection closed normally');
break;
case 1001: // Going away
case 1006: // Abnormal closure
console.log('Unexpected closure, reconnecting...');
this.scheduleReconnect();
break;
case 1008: // Policy violation
console.error('Policy violation, check rate limits');
break;
case 1011: // Server error
console.log('Server error, waiting before reconnect');
setTimeout(() => this.scheduleReconnect(), 5000);
break;
default:
console.log(`Closed with code ${event.code}`);
this.scheduleReconnect();
}
};
Rate Limits and Connection Limits
Binance imposes limits on WebSocket connections to ensure fair resource distribution across all users.
Connection Limits
- Maximum 5 connections per IP to
stream.binance.com - Maximum 10 connections per IP for combined streams
- Maximum 1024 streams per connection for combined streams
- Message rate limit: 5 messages per second per connection
Best Practices
To work within these limits:
- Use combined streams when monitoring multiple symbols
- Batch subscriptions instead of making multiple requests
- Implement connection pooling for applications requiring many streams
- Cache data locally to reduce redundant subscriptions
- Monitor ping/pong frames to detect connection health
// Ping/pong monitoring
ws.on('ping', () => {
console.log('Received ping from server');
ws.pong();
});
ws.on('pong', () => {
console.log('Pong received');
this.lastPong = Date.now();
});
// Check connection health
setInterval(() => {
if (Date.now() - this.lastPong > 60000) {
console.warn('No pong received in 60s, connection may be stale');
ws.terminate();
}
}, 10000);
Python Implementation
For Python applications, the websockets library provides an async interface for binance real-time data connections.
Basic Python WebSocket Client
import asyncio
import json
import websockets
async def binance_websocket():
url = "wss://stream.binance.com:9443/ws/btcusdt@trade"
async with websockets.connect(url) as websocket:
print("Connected to Binance WebSocket")
while True:
try:
message = await websocket.recv()
data = json.loads(message)
print(f"Trade: {data['s']} Price: {data['p']} Qty: {data['q']}")
except websockets.ConnectionClosed:
print("Connection closed")
break
except Exception as e:
print(f"Error: {e}")
break
Advanced Python Client with Reconnection
import asyncio
import json
import websockets
from websockets.exceptions import ConnectionClosed
class BinanceWebSocketClient:
def __init__(self, streams):
self.streams = streams
self.url = f"wss://stream.binance.com:9443/stream?streams={'/'.join(streams)}"
self.reconnect_delay = 1
self.max_reconnect_delay = 60
async def connect(self):
while True:
try:
async with websockets.connect(self.url) as websocket:
print("Connected to Binance")
self.reconnect_delay = 1
await self.handle_messages(websocket)
except ConnectionClosed as e:
print(f"Connection closed: {e.code}")
await self.reconnect()
except Exception as e:
print(f"Error: {e}")
await self.reconnect()
async def handle_messages(self, websocket):
async for message in websocket:
data = json.loads(message)
await self.process_message(data)
async def process_message(self, data):
stream = data.get('stream')
stream_data = data.get('data')
if 'trade' in stream:
print(f"Trade on {stream}: {stream_data['p']}")
elif 'ticker' in stream:
print(f"Ticker {stream_data['s']}: {stream_data['c']}")
elif 'kline' in stream:
kline = stream_data['k']
print(f"Kline {kline['s']}: O:{kline['o']} H:{kline['h']} L:{kline['l']} C:{kline['c']}")
async def reconnect(self):
delay = min(self.reconnect_delay, self.max_reconnect_delay)
print(f"Reconnecting in {delay}s...")
await asyncio.sleep(delay)
self.reconnect_delay = min(self.reconnect_delay * 2, self.max_reconnect_delay)
# Usage
streams = ['btcusdt@trade', 'ethusdt@ticker', 'btcusdt@kline_1m']
client = BinanceWebSocketClient(streams)
asyncio.run(client.connect())
For more Python WebSocket patterns, see our Python WebSockets guide.
Handling User Data Streams in Python
import asyncio
import json
import aiohttp
import websockets
class BinanceUserDataStream:
def __init__(self, api_key, api_secret):
self.api_key = api_key
self.api_secret = api_secret
self.listen_key = None
async def create_listen_key(self):
async with aiohttp.ClientSession() as session:
headers = {'X-MBX-APIKEY': self.api_key}
async with session.post(
'https://api.binance.com/api/v3/userDataStream',
headers=headers
) as response:
data = await response.json()
self.listen_key = data['listenKey']
return self.listen_key
async def keep_alive(self):
while True:
await asyncio.sleep(30 * 60) # 30 minutes
async with aiohttp.ClientSession() as session:
headers = {'X-MBX-APIKEY': self.api_key}
await session.put(
f'https://api.binance.com/api/v3/userDataStream?listenKey={self.listen_key}',
headers=headers
)
print("Listen key refreshed")
async def connect(self):
await self.create_listen_key()
url = f"wss://stream.binance.com:9443/ws/{self.listen_key}"
# Start keepalive task
asyncio.create_task(self.keep_alive())
async with websockets.connect(url) as websocket:
async for message in websocket:
data = json.loads(message)
await self.handle_event(data)
async def handle_event(self, data):
event_type = data.get('e')
if event_type == 'executionReport':
print(f"Order update: {data['s']} {data['X']} Price: {data['p']}")
elif event_type == 'outboundAccountPosition':
print(f"Account update: {len(data['B'])} balances")
elif event_type == 'balanceUpdate':
print(f"Balance update: {data['a']} Delta: {data['d']}")
# Usage
# user_stream = BinanceUserDataStream('your_api_key', 'your_api_secret')
# asyncio.run(user_stream.connect())
Common Issues and Solutions
Issue: Connection Immediately Closes
Problem: WebSocket connects but immediately closes with code 1006.
Solution: Check that your stream name is formatted correctly. Symbol names must be lowercase, and stream parameters must match Binance’s documentation exactly.
// Incorrect
const ws = new WebSocket('wss://stream.binance.com:9443/ws/BTCUSDT@trade');
// Correct
const ws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@trade');
Issue: Data Appears Delayed
Problem: Prices from WebSocket lag behind the exchange website.
Solution: This usually indicates network latency or processing delays in your code. Minimize processing in the onmessage handler by offloading work to separate functions or workers.
ws.onmessage = (event) => {
// Fast: queue for processing
messageQueue.push(event.data);
// Slow: parsing and complex logic blocks receiving next message
// const data = JSON.parse(event.data);
// performComplexCalculations(data);
};
Issue: Too Many Connections Error
Problem: Binance rejects new connections with “Too many connections” message.
Solution: Use combined streams to consolidate multiple subscriptions into fewer connections.
// Instead of 10 separate connections
// Use one combined stream
const streams = symbols.map(s => `${s}@ticker`);
const ws = new WebSocket(`wss://stream.binance.com:9443/stream?streams=${streams.join('/')}`);
Issue: Missing Messages During Reconnection
Problem: Data gaps occur when reconnecting after disconnection.
Solution: Use Binance’s REST API to fetch any missed data using timestamps from your last received message.
async function fillDataGap(symbol, lastUpdateTime) {
const response = await fetch(
`https://api.binance.com/api/v3/trades?symbol=${symbol.toUpperCase()}&limit=1000`
);
const trades = await response.json();
return trades.filter(t => t.time > lastUpdateTime);
}
Frequently Asked Questions
What is the difference between Binance WebSocket and REST API?
The binance websocket api provides real-time data through a persistent connection, pushing updates as they occur. The REST API requires you to poll for data repeatedly, which introduces latency and consumes more resources. WebSockets are ideal for live price monitoring, order book tracking, and trading bots that need immediate notifications. REST APIs are better for historical data retrieval, account management operations, and one-time queries. Most production applications use both: WebSockets for real-time updates and REST for historical data and trading operations.
How many WebSocket connections can I open to Binance?
Binance limits connections to 5 per IP address for individual streams and 10 per IP for combined streams. Each combined stream connection can subscribe to up to 1024 different streams. For applications requiring more data sources, use combined streams to maximize efficiency. If you need more connections than these limits allow, consider using multiple IP addresses through a proxy service or VPS infrastructure. Always implement connection pooling and stream multiplexing before resorting to multiple IPs.
Do I need API keys to connect to Binance WebSocket streams?
Public market data streams (ticker, trades, depth, klines) do not require API keys and can be accessed anonymously. However, user data streams that provide account updates, order execution reports, and balance changes require authentication through a listen key. To obtain a listen key, you must have a Binance account and valid API credentials. The listen key is generated through the REST API and must be refreshed every 60 minutes to maintain the connection.
How do I handle Binance WebSocket disconnections in production?
Implement exponential backoff reconnection logic to handle temporary network issues without overwhelming the server. Store the timestamp of your last received message so you can fetch missed data using the REST API after reconnecting. Monitor ping/pong frames to detect stale connections before they fail. Use health check mechanisms to verify data is flowing and trigger reconnection if updates stop arriving. Consider implementing a circuit breaker pattern that temporarily disables reconnection attempts after repeated failures, preventing your application from entering an infinite reconnection loop during extended outages.