WebSocket Crypto API: Real-Time Market Data for Traders
A practical guide to WebSocket crypto APIs — how they work, how to connect to Binance, OKX, and Coinbase, and how to build real-time data feeds with working code examples.
A practical guide to WebSocket crypto APIs — how they work, how to connect to Binance, OKX, and Coinbase, and how to build real-time data feeds with working code examples.
If you've ever watched a trading terminal where prices update instantly — no page refresh, no visible delay — you were looking at WebSocket technology in action. Most public APIs work on a request-response model: you ask, they answer, connection closes. That's fine for historical data. It's completely wrong for live trading. WebSocket crypto APIs flip this model. You open a single persistent connection, subscribe to price feeds or order book updates, and the exchange pushes data to you the moment it changes. For algo traders, signal developers, and anyone building real-time dashboards, this is the only approach that actually works at the speed markets move. This guide walks you through how WebSocket crypto APIs work, which ones are worth using, and how to connect to them with real code you can run today.
A WebSocket is a communication protocol that establishes a full-duplex channel over a single TCP connection. Unlike a regular HTTP request that opens, sends data, and closes, a WebSocket stays open indefinitely. Both sides — client and server — can push messages at any time without renegotiating the connection. For crypto markets, this is transformative. Order books on Binance can update hundreds of times per second. If you were polling a REST endpoint to track BTC/USDT price, you'd hit rate limits almost immediately and still receive stale data. With a websocket cryptocurrency api, the exchange streams every price tick, trade, or order book change to you as it happens. The difference isn't just performance — it's the difference between acting on current information and acting on data that's already 500 milliseconds old. For arbitrage, market making, liquidation monitoring, or even a solid alert system, that gap matters enormously. Real-time signal platforms like VoiceOfChain are built on exactly this infrastructure — aggregating live streams from multiple exchanges to surface tradeable signals the moment they form.
Understanding the difference between websocket and api (specifically REST API) is fundamental before you write a single line of code. They are not interchangeable — they solve different problems. REST is the right tool for placing orders, fetching account balances, pulling historical candlestick data, or any one-time query where you ask once and move on. WebSocket is essential for live price ticks, real-time order book depth, trade stream monitoring, and anything where you need sub-second updates continuously. Most serious trading infrastructure uses both — REST for management operations and WebSocket for data consumption. Choosing REST where WebSocket belongs is one of the most common mistakes in algo trading system design.
| Feature | WebSocket | REST API |
|---|---|---|
| Connection type | Persistent, bi-directional | One request, one response |
| Latency after connect | ~1–5ms per update | 50–200ms per request |
| Rate limits | Weight-based per stream | Strict per-minute request limits |
| Best for | Live prices, order books, trades | Place orders, account info, history |
| Auth required | No (for public streams) | Yes (for all private endpoints) |
| Reconnection handling | Required in client code | Not applicable |
Binance offers one of the most comprehensive and well-documented crypto websocket api free tiers available. Their public streams require no authentication whatsoever — you can stream BTC price ticks, order book updates, and trade data with no API key. Here is a working Python example using the websockets library that connects to Binance's BTC/USDT individual trade stream:
import asyncio
import json
import websockets
BINANCE_WS_URL = "wss://stream.binance.com:9443/ws/btcusdt@trade"
async def handle_trade(message: dict):
price = float(message['p'])
qty = float(message['q'])
side = 'BUY' if not message['m'] else 'SELL'
print(f"BTC/USDT | {side} | Price: ${price:,.2f} | Qty: {qty:.6f}")
async def connect_binance():
backoff = 1
while True: # auto-reconnect loop
try:
async with websockets.connect(BINANCE_WS_URL) as ws:
print("Connected to Binance BTC/USDT trade stream")
backoff = 1 # reset on successful connection
async for raw_msg in ws:
msg = json.loads(raw_msg)
await handle_trade(msg)
except websockets.exceptions.ConnectionClosed as e:
print(f"Connection closed: {e}. Reconnecting in {backoff}s...")
await asyncio.sleep(backoff)
backoff = min(backoff * 2, 60) # exponential backoff, cap at 60s
except Exception as e:
print(f"Unexpected error: {e}. Reconnecting in {backoff}s...")
await asyncio.sleep(backoff)
backoff = min(backoff * 2, 60)
if __name__ == "__main__":
asyncio.run(connect_binance())
The auto-reconnect loop with exponential backoff is not optional — it is essential. Binance drops WebSocket connections every 24 hours. Exchanges also disconnect during maintenance windows with no prior warning. Any production code without reconnect logic will silently fail mid-session. Here is the same concept in JavaScript, connecting to OKX's public WebSocket — useful for Node.js services or browser dashboards:
const WebSocket = require('ws');
const OKX_WS_URL = 'wss://ws.okx.com:8443/ws/v5/public';
function connectOKX() {
const ws = new WebSocket(OKX_WS_URL);
let pingInterval;
ws.on('open', () => {
console.log('Connected to OKX WebSocket');
// Subscribe to BTC-USDT and ETH-USDT tickers
const subscribeMsg = {
op: 'subscribe',
args: [
{ channel: 'tickers', instId: 'BTC-USDT' },
{ channel: 'tickers', instId: 'ETH-USDT' }
]
};
ws.send(JSON.stringify(subscribeMsg));
// OKX requires ping every 30 seconds to keep connection alive
pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send('ping');
}
}, 25000);
});
ws.on('message', (data) => {
const text = data.toString();
if (text === 'pong') return; // ignore keepalive responses
const msg = JSON.parse(text);
if (msg.data && msg.data.length > 0) {
const ticker = msg.data[0];
const price = parseFloat(ticker.last).toLocaleString('en-US', { minimumFractionDigits: 2 });
console.log(`${ticker.instId} | Last: $${price} | 24h Change: ${ticker.sodUtc8}`);
}
});
ws.on('close', (code, reason) => {
clearInterval(pingInterval);
console.log(`Disconnected (${code}). Reconnecting in 5s...`);
setTimeout(connectOKX, 5000);
});
ws.on('error', (err) => {
console.error('WebSocket error:', err.message);
ws.close(); // trigger close handler for reconnect
});
}
connectOKX();
Every exchange has different keepalive requirements. Binance sends ping frames and expects pong responses (most WebSocket libraries handle this automatically). OKX requires you to send a literal 'ping' string every 30 seconds. Bybit uses JSON-format heartbeats. Missing the keepalive will silently kill your connection — always check the exchange documentation for the specific ping format and interval.
Not all crypto websocket apis are created equal. Latency, stream availability, rate limits, and documentation quality vary significantly across exchanges. Here is a practical breakdown of the major options traders actually use:
| Exchange | Free Public Streams | Auth for Private | Docs Quality | Notable Streams |
|---|---|---|---|---|
| Binance | Yes — all public | API key required | Excellent | Trade, depth20, kline, bookTicker |
| OKX | Yes — public | API key + sign | Very good | Tickers, trades, order book L2 |
| Bybit | Yes — public | API key + sign | Good | Orderbook, public trade, kline |
| Coinbase Adv. | Yes — market data | Required for all | Good | Ticker, level2, market trades |
| Gemini | Yes — public | Required for orders | Decent | Order events, market data feed |
| KuCoin | Via token endpoint | Token required | Good | Ticker, orderbook, candles |
| Gate.io | Yes — public | API key required | Average | Trades, order book, tickers |
| Bitget | Yes — public | API key required | Good | Tickers, depth, candlesticks |
The best crypto websocket api for your use case depends heavily on what you are trading and where. For perpetual futures with high update frequency, Bybit and OKX have excellent stream reliability and competitive latency. For spot trading on major pairs, Binance's public streams are hard to beat — stable, thoroughly documented, and genuinely free. The gemini crypto websocket api is less commonly discussed but solid if you are building compliance-friendly tools for US-regulated workflows. Coinbase Advanced Trade WebSocket now requires authentication even for public market data subscriptions, which adds setup overhead but also enables a unified connection for both public and private streams. For teams that want signal-quality aggregated data across exchanges without maintaining multiple WebSocket connections, platforms like VoiceOfChain normalize streams from Binance, Bybit, and OKX into clean trading signals — worth evaluating if your focus is on acting on data rather than collecting it.
The term ethereum websocket api covers two distinct use cases that are frequently confused. On centralized exchanges like Binance, Bybit, or Coinbase, it simply means subscribing to ETH/USDT or ETH/BTC price streams — the same WebSocket API infrastructure as the Bitcoin examples above, just with different symbol identifiers. On the blockchain infrastructure side, Ethereum nodes expose a WebSocket interface through JSON-RPC subscriptions (eth_subscribe) that lets you receive on-chain events in real time: new block headers, pending mempool transactions, and smart contract log events. This is what you see in DeFi dashboards and what the web crypto api example in most Ethereum developer tutorials demonstrates. Here is a Python example using web3.py to subscribe to new Ethereum block headers via a node provider WebSocket:
import asyncio
from web3 import AsyncWeb3
from web3.providers import WebsocketProviderV2
# Replace YOUR_API_KEY with your Alchemy or Infura WebSocket key
ETH_WS_URL = "wss://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"
async def stream_new_blocks():
async with AsyncWeb3(WebsocketProviderV2(ETH_WS_URL)) as w3:
print("Connected to Ethereum node WebSocket")
subscription_id = await w3.eth.subscribe('newHeads')
print(f"Subscribed to new block headers: {subscription_id}")
async for response in w3.socket.process_subscriptions():
block = response['result']
block_num = int(block['number'], 16)
gas_used = int(block['gasUsed'], 16)
gas_limit = int(block['gasLimit'], 16)
base_fee = int(block.get('baseFeePerGas', '0x0'), 16) / 1e9 # convert to Gwei
utilization = (gas_used / gas_limit) * 100
print(
f"Block #{block_num:} | "
f"Gas: {utilization:.1f}% | "
f"Base Fee: {base_fee:.2f} Gwei | "
f"Miner: {block['miner'][:10]}..."
)
if __name__ == "__main__":
asyncio.run(stream_new_blocks())
For the blockchain.com websocket api, Blockchain.com exposes a WebSocket at wss://ws.blockchain.info/inv that supports subscribing to unconfirmed Bitcoin transactions and newly mined blocks. It is more useful for on-chain monitoring — confirming deposit arrivals, tracking large transaction flows, or building Bitcoin explorer tools — than for price trading. If you are trading on centralized exchanges like Bitget or Gate.io, you will use their exchange-specific WebSocket APIs for price data rather than blockchain node subscriptions. The two domains serve fundamentally different purposes and it is worth being clear on which one your application actually needs before you start building.
A WebSocket client that works on your laptop and one that survives weeks of continuous production operation are not the same thing. Exchanges have connection limits, cap the number of stream subscriptions per connection, and occasionally push maintenance disconnects with no advance warning. These patterns separate a working prototype from infrastructure you can actually rely on:
WebSocket crypto APIs are not an advanced topic reserved for quant teams or large trading operations — they are the baseline requirement for anyone who needs to know what markets are doing right now, not 500 milliseconds ago. Whether you are building a trading bot, a price alert system, a real-time dashboard, or feeding signals into a strategy engine, the pattern is the same: open a persistent connection, subscribe to the streams you need, handle reconnections gracefully, and process data as it arrives. Start with Binance or OKX public streams — no API key, solid documentation, high uptime, and zero cost. Get comfortable with their message formats, build your reconnection and resubscription logic, then scale to multiple streams and multiple exchanges as your needs grow. The infrastructure is not the edge. What you do with the data once you have it is where the real work begins.