Real-time WebSocket scraping for crypto exchanges and EVM chains

Imagine you trade on Binance using REST polling once per second. In that time, the price could have shifted 0.5%, and you missed an arbitrage opportunity. WebSocket subscriptions deliver events as they happen—latency drops from 500 ms to 10–50 ms. For price monitoring, order books, and on-chain even

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1270
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1011

Imagine you trade on Binance using REST polling once per second. In that time, the price could have shifted 0.5%, and you missed an arbitrage opportunity. WebSocket subscriptions deliver events as they happen—latency drops from 500 ms to 10–50 ms. For price monitoring, order books, and on-chain events, the difference is critical.

Polling a REST API every N seconds is the wrong tool for event-driven tasks. With a 1-second poll interval, the average detection delay is 0.5 seconds. WebSocket subscriptions push events immediately; latency is only network-dependent (10–50 ms to the nearest exchange server). For price monitoring, order books, and on-chain events, the difference is fundamental. One of our clients cut latency from 800 ms to 30 ms by implementing WebSocket scraping for 50 pairs across 5 exchanges—saving up to 40% of lost profit.

Parameter REST Polling WebSocket
Event latency 500 ms – 2 s 10–50 ms
Server load High (N requests/min) Low (one connection)
Reaction to changes Delayed, possible misses Instant, all events in sequence
Implementation complexity Low Medium, requires reconnect logic

Why WebSocket scraping beats REST polling for real-time data?

WebSocket cuts latency by 10x compared to REST polling (0.5 s → 50 ms)—saving up to 40% of lost profit. For crypto trading and DeFi bots, this difference is critical.

How to set up WebSocket connections to exchanges?

Each exchange has its own subscription protocol. Patterns are similar but details vary.

Binance: stream names via symbol@streamType

import asyncio import json import websockets async def binance_stream(symbols: list[str]): streams = '/'.join([f"{s.lower()}@trade" for s in symbols]) url = f"wss://stream.binance.com:9443/stream?streams={streams}" async with websockets.connect(url, ping_interval=20, ping_timeout=10) as ws: async for message in ws: data = json.loads(message) stream_data = data.get('data', data) yield { 'exchange': 'binance', 'symbol': stream_data['s'], 'price': float(stream_data['p']), 'amount': float(stream_data['q']), 'timestamp': stream_data['T'], 'is_buyer_maker': stream_data['m'], } 

Coinbase Advanced Trade: subscribe with channel and product_ids

subscribe_msg = { "type": "subscribe", "channel": "ticker", "product_ids": ["BTC-USD", "ETH-USD"], } 

Kraken

Uses subscription ID generation and has a specific response format with pairs in arrays. Details are in the official Kraken WebSocket API documentation.

Ethereum/EVM: WebSocket subscriptions via web3.py

On-chain events via WebSocket subscriptions to an Ethereum node (Alchemy, Infura, QuickNode, or your own node):

from web3 import AsyncWeb3, WebSocketProvider async def subscribe_to_transfers(token_address: str): w3 = AsyncWeb3(WebSocketProvider( "wss://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" )) # ERC-20 Transfer event signature hash transfer_sig = w3.keccak(text="Transfer(address,address,uint256)").hex() subscription_id = await w3.eth.subscribe('logs', { 'address': token_address, 'topics': [transfer_sig] }) async for payload in w3.socket.process_subscriptions(): if payload['subscription'] == subscription_id: log = payload['result'] yield decode_transfer_log(log) 

Ethereum JSON-RPC WebSocket supports three subscription types: newHeads (new blocks), logs (contract events), and newPendingTransactions (mempool transactions). See the official Ethereum documentation for more details.

Why reconnect and staleness watchdog matter?

WebSocket connections can drop for various reasons: server timeout, network hiccups, exchange service restarts. A production system must recover automatically:

import asyncio import websockets from datetime import datetime class RobustWebSocketClient: def __init__(self, url: str, reconnect_delay: float = 1.0): self.url = url self.reconnect_delay = reconnect_delay self.max_reconnect_delay = 60.0 self.last_message_at = None self.stale_threshold = 30 # seconds without messages = staleness async def connect_with_retry(self, on_message, on_subscribe): delay = self.reconnect_delay while True: try: async with websockets.connect( self.url, ping_interval=20, ping_timeout=10, close_timeout=5, ) as ws: await on_subscribe(ws) delay = self.reconnect_delay # reset on success async for msg in ws: self.last_message_at = datetime.utcnow() await on_message(msg) except (websockets.ConnectionClosed, websockets.InvalidHandshake, OSError) as e: print(f"Connection error: {e}, reconnecting in {delay}s") await asyncio.sleep(delay) delay = min(delay * 2, self.max_reconnect_delay) async def staleness_watchdog(self): """Detect silent connection drop""" while True: await asyncio.sleep(10) if self.last_message_at: elapsed = (datetime.utcnow() - self.last_message_at).seconds if elapsed > self.stale_threshold: raise RuntimeError(f"Connection stale: {elapsed}s without data") 

Exponential backoff reconnection and a staleness watchdog are the minimum for industrial-grade scraping.

How to manage an order book via WebSocket?

Most exchanges send order book updates as incremental changes—only levels that changed. Maintaining a local order book:

from sortedcontainers import SortedDict class LocalOrderBook: def __init__(self): self.bids = SortedDict(lambda k: -k) # descending self.asks = SortedDict() # ascending self.last_update_id = 0 def apply_snapshot(self, snapshot: dict): self.bids.clear() self.asks.clear() for price, qty in snapshot['bids']: self.bids[float(price)] = float(qty) for price, qty in snapshot['asks']: self.asks[float(price)] = float(qty) self.last_update_id = snapshot['lastUpdateId'] def apply_update(self, update: dict): if update['u'] <= self.last_update_id: return # stale update, ignore for price, qty in update['b']: # bids p, q = float(price), float(qty) if q == 0: self.bids.pop(p, None) else: self.bids[p] = q for price, qty in update['a']: # asks p, q = float(price), float(qty) if q == 0: self.asks.pop(p, None) else: self.asks[p] = q self.last_update_id = update['u'] def best_bid(self) -> tuple[float, float]: k = next(iter(self.bids)) return k, self.bids[k] def best_ask(self) -> tuple[float, float]: k = next(iter(self.asks)) return k, self.asks[k] 

Important: on startup, get a snapshot via REST, then apply WebSocket updates starting with lastUpdateId > snapshotId. Updates before the snapshot are discarded; a gap in the Uu sequence requires a new snapshot.

Scaling: multiple pairs and exchanges

A single async event loop in Python handles 50–200 simultaneous WebSocket connections. For more, use multiple processes or a Go service (goroutines are significantly lighter than asyncio tasks).

Fanout results: processed messages are published to Redis Pub/Sub or Kafka for downstream consumers. The WebSocket handler should do minimal processing and publish quickly—heavy processing is done by a separate consumer.

Monitoring health

Metrics for each WebSocket connection: messages per second, reconnect count, last message timestamp, lag from exchange timestamp to processing timestamp. Use Grafana + Prometheus alerting on stale connections (no messages for active pair > 60 seconds).

Metric Description Alert Threshold
messages/sec Number of messages per second < 0.5x expected
reconnects Number of reconnections per hour > 5
last_message_age Time since last message > 60 s
lag Delay from exchange time > 500 ms

What's included in WebSocket scraping setup

  • Connection to exchanges / blockchain nodes via WebSocket (Binance, Coinbase, Kraken, Ethereum, Polygon, Solana, and others)
  • Implementation of reconnect logic with exponential backoff and staleness watchdog
  • Local order book aggregation with snapshot synchronization
  • Publishing normalized data to Redis Pub/Sub or Kafka
  • Monitoring and alerts (Grafana, Prometheus)
  • Documentation of architecture and configuration
  • Training your team on system operation

Our experience and guarantees

Over 5 years, we've completed 50+ real-time scraping projects for crypto exchanges, DeFi protocols, and NFT marketplaces. We guarantee stable operation, automatic recovery after failures, and 24/7 monitoring. We work with Ethereum, Binance, Polygon, Arbitrum, Solana, and other networks.

Setup of real-time scraping for 3–5 exchanges with monitoring of 20–50 pairs, reconnect logic, and publishing to Redis/Kafka takes 1–2 days. Contact us for a cost estimate. Order now to get a consultation.