Real-Time Options for Pushing Data to Clients

Four Ways to Get Fresh Data to a Client, and When to Use Each

Real-Time Options for Pushing Data to Clients

Short polling, long polling, Server-Sent Events, and WebSockets — how each works, what they cost, and how to choose between SSE and WebSockets.

8 min read Level 3/5 #system-design#realtime#sse
What you'll learn
  • Explain how polling, long polling, SSE, and WebSockets deliver updates
  • Compare them on latency, overhead, direction, and complexity
  • Decide between SSE and WebSockets for a given feature

Standard HTTP is pull: the client asks, the server answers, the connection closes. But plenty of features need push — a new chat message, a live score, a “your order shipped” toast. Since the server can’t dial an arbitrary browser, we have a handful of techniques that simulate or enable server push. Here are the four, from crudest to most capable.

Short polling

The client asks “anything new?” on a fixed timer — say every 5 seconds.

Real-Time Options for Pushing Data to Clients — architecture diagram

Dead simple, works everywhere, no special server. But it’s wasteful: most requests return nothing, every poll pays a full request/header round trip, and your update latency is bounded by the poll interval (poll every 5s, updates can be up to 5s stale). Fine for low-stakes, low-frequency data; bad at scale.

Long polling

Smarter: the client makes a request, and the server holds it open until there is something to send (or a timeout fires). The instant data arrives, the server responds; the client immediately opens the next request.

This cuts the empty responses and gets near-real-time latency over ordinary HTTP, with no new protocol. The cost is many hanging connections — each waiting client ties up a connection — and the reconnect churn after every message. It was the workhorse before SSE and WebSockets and is still a solid fallback.

Server-Sent Events (SSE)

SSE is a one-way streaming channel built into HTTP. The client opens a GET with Accept: text/event-stream; the server keeps the response open and writes events as plain text whenever it likes. The browser’s EventSource API handles parsing and automatic reconnection for you.

An SSE endpoint in Node, and the browser client script.js
// --- server (Express): one long-lived response, many events ---
app.get('/events', (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive',
  });
  const timer = setInterval(() => {
    res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`); // one event
  }, 1000);
  req.on('close', () => clearInterval(timer)); // clean up when client leaves
});

// --- browser: reconnects automatically on drop ---
const es = new EventSource('/events');
es.onmessage = (e) => console.log(JSON.parse(e.data));
▶ Preview: console

SSE is server-to-client only, text-only, and runs over plain HTTP — so it passes through proxies cleanly and gets multiplexing on HTTP/2. It’s the perfect fit for feeds, notifications, live dashboards, and progress streams where the client only needs to listen.

WebSockets

WebSockets give you a full-duplex connection: after an HTTP Upgrade handshake, the TCP connection is repurposed into a persistent two-way channel where either side sends messages (text or binary) at any time, with minimal framing overhead.

Real-Time Options for Pushing Data to Clients — architecture diagram

This is what you want for chat, multiplayer games, collaborative editing, live trading — anything where the client also sends frequent messages. The price is operational: a stateful long-lived connection per client, which (as the next lesson shows) is genuinely hard to scale across many server instances.

The comparison

TechniqueDirectionLatencyOverheadComplexityAuto-reconnect
Short pollingPullPoll intervalHigh (empty requests)TrivialN/A
Long pollingPull (held)Near real-timeMedium (reconnects)LowManual
SSEServer → clientReal-timeLowLowBuilt in
WebSocketsBidirectionalReal-timeLowest per messageHighManual

SSE vs WebSockets: the real decision

Most “do I need WebSockets?” questions are actually “SSE or WebSockets?” The rule of thumb:

  • Client only needs to receive? Use SSE. It’s simpler, auto-reconnects, rides plain HTTP, and survives proxies and HTTP/2 multiplexing without fuss.
  • Client also needs to send frequently, with low latency? Use WebSockets. Two-way, binary-capable, lowest per-message overhead.

When you do need true bidirectional real-time at scale, the hard part isn’t opening a socket — it’s that those sockets are stateful. That problem is big enough to get its own lesson, next.