← Back to blog

Server-Sent Events vs WebSockets for Market Data Delivery

Trade-offs between SSE and WebSockets for streaming market data - reconnection, scalability, browser limits, and when each makes sense.

Oliver Benns
Oliver Benns

Software engineer · Creator of Hedge UI


Every trading application needs a way to push data from the server to the browser. WebSockets are the default choice, but Server-Sent Events (SSE) deserve serious consideration depending on your use case. The two technologies solve overlapping but distinct problems, and the right choice depends on your data flow, infrastructure, and scale requirements.

The fundamental difference

WebSockets provide a full-duplex, bidirectional connection. Both client and server can send messages at any time. The protocol starts as HTTP and upgrades to a persistent TCP connection.

Server-Sent Events provide a unidirectional stream from server to client over a standard HTTP connection. The client can only receive data, not send it (beyond the initial request). The connection stays open and the server pushes events through it.

For market data delivery, where data flows almost entirely from server to client, this distinction matters less than you might think.

SSE advantages

Simpler infrastructure

SSE runs over standard HTTP. It works with existing load balancers, CDNs, proxies, and monitoring tools without special configuration. WebSockets require infrastructure that understands the protocol upgrade and maintains persistent connections, which not every reverse proxy handles well out of the box.

Automatic reconnection

SSE has built-in reconnection with Last-Event-ID support. If the connection drops, the browser automatically reconnects and sends the ID of the last received event, allowing the server to resume from where it left off:

// Server app.get("/stream/prices", (req, res) => { res.setHeader("Content-Type", "text/event-stream"); res.setHeader("Cache-Control", "no-cache"); res.setHeader("Connection", "keep-alive"); const lastId = req.headers["last-event-id"]; let sequenceId = lastId ? parseInt(lastId, 10) : 0; const interval = setInterval(() => { sequenceId++; const data = JSON.stringify(getLatestPrices()); res.write(`id: ${sequenceId}\ndata: ${data}\n\n`); }, 100); req.on("close", () => clearInterval(interval)); });
// Client const source = new EventSource("/stream/prices"); source.onmessage = (event) => { const prices = JSON.parse(event.data); updatePriceDisplay(prices); }; source.onerror = () => { // Browser handles reconnection automatically console.log("Connection lost, reconnecting..."); };

With WebSockets, you build all of this yourself - reconnection logic, backoff timers, and state reconciliation.

HTTP/2 multiplexing

SSE connections over HTTP/2 are multiplexed over a single TCP connection. You can open multiple SSE streams (one for prices, one for orders, one for trades) without consuming additional TCP connections. WebSockets cannot use HTTP/2 multiplexing - each WebSocket is its own TCP connection.

WebSocket advantages

Bidirectional communication

If the client needs to send messages to the server - subscription changes, order submissions, heartbeat pongs - WebSockets handle this natively. With SSE, you need a separate mechanism (regular HTTP requests, fetch calls) for client-to-server communication.

In a trading application, the client sends:

  • Subscribe/unsubscribe requests for specific instruments
  • Order placement and cancellation
  • Heartbeat responses

These can absolutely be handled via fetch requests alongside an SSE stream, but it means managing two communication channels instead of one.

Binary data

WebSockets support binary frames natively. If your market data is encoded in Protocol Buffers or MessagePack, WebSockets deliver it without base64 encoding overhead. SSE is text-only, so binary data must be encoded, adding latency and bandwidth.

Higher throughput

For very high message rates (hundreds per second), WebSockets have lower overhead per message. SSE messages include field prefixes (data:, id:, event:) and double newline terminators that add bytes to every message. At 500 messages per second, this overhead becomes measurable.

Browser connection limits

Browsers limit the number of concurrent HTTP connections per domain (typically 6 for HTTP/1.1). Each SSE stream counts against this limit. If your application opens multiple SSE streams plus makes regular API calls, you can hit the ceiling. HTTP/2 resolves this with multiplexing, but not all infrastructure supports it end-to-end.

WebSockets have their own connection limit separate from HTTP, so they do not compete with regular API traffic.

A practical comparison

FactorSSEWebSocket
DirectionServer to clientBidirectional
ProtocolHTTPCustom (upgraded from HTTP)
ReconnectionBuilt-inManual
Binary supportNo (text only)Yes
HTTP/2 multiplexingYesNo
Infrastructure complexityLowMedium
Browser connection limitShares with HTTPSeparate limit
Message overheadHigherLower
Proxy/CDN compatibilityExcellentVariable

When SSE makes sense for trading

SSE works well when:

  • Your data flow is mostly one-directional - Market data streams, price feeds, and trade history are server-to-client. Client actions (placing orders) happen infrequently and can use regular HTTP endpoints.
  • Your infrastructure is HTTP-native - If you are behind a CDN, API gateway, or reverse proxy that does not handle WebSocket upgrades well, SSE avoids the problem entirely.
  • You want simpler client code - The EventSource API is simpler than managing a WebSocket connection, especially around reconnection and state recovery.
  • You are delivering to many clients at different rates - SSE streams can be individually throttled server-side without complex subscription management.

When WebSockets are the better choice

WebSockets win when:

  • You need real bidirectional communication - If the client sends frequent messages (subscription management, order updates, heartbeats), a single WebSocket is cleaner than SSE plus fetch.
  • Message rate is very high - Above 100+ messages per second, the per-message overhead of SSE becomes a concern.
  • You use binary encoding - Protocol Buffers or MessagePack for market data requires WebSocket binary frames or base64 encoding over SSE.
  • Your infrastructure already supports WebSockets - If your load balancers, proxies, and monitoring are already configured for WebSocket traffic, there is no reason to switch.

The hybrid approach

Some trading platforms use both:

  • SSE for market data - Price streams, trade history, and order book updates flow over SSE with automatic reconnection and Last-Event-ID recovery
  • REST for actions - Order placement, cancellation, and account operations go through regular HTTP endpoints
  • WebSocket for private channels - Order status updates and account events that require authentication and bidirectional heartbeating use a WebSocket
// Market data via SSE const priceStream = new EventSource("/stream/prices?symbols=BTC,ETH"); priceStream.onmessage = handlePriceUpdate; // Orders via REST async function placeOrder(order: OrderRequest) { return fetch("/api/orders", { method: "POST", body: JSON.stringify(order), }); } // Private updates via WebSocket const ws = new WebSocket("/ws/account"); ws.onmessage = handleAccountUpdate;

This uses each technology where it is strongest. Market data gets the simplicity and reconnection of SSE. Private channels get the bidirectional capability of WebSockets.

Making the decision

For most trading applications, WebSockets remain the pragmatic default. The ecosystem is mature, most exchanges expose WebSocket APIs, and the bidirectional capability avoids managing two transport layers.

We went with WebSockets for the straightforward reason that Binance's streaming API is WebSocket-native. A single connection multiplexes order book, trade, and ticker streams through JSON SUBSCRIBE/UNSUBSCRIBE control messages - a useMessenger hook diffs the active stream names each render and only sends commands for the delta.

But if you are building the server side as well and want simpler infrastructure, fewer reconnection bugs, and better compatibility with standard HTTP tooling, SSE is a legitimate choice for the market data layer. Test both with your actual data volumes and infrastructure before committing.

Kickstart Your Trading Application

Hedge UI is a React starter kit with production-ready trading components, real-time data handling, and customisable layouts — so you can ship faster.

Get Hedge UI