HAMZA KAREEM / CONCEPTS hamzawi.dev

Lesson 231 min read

Real-Time Updates: Long Polling vs SSE vs WebSockets

Long Polling vs SSE vs WebSockets

Web developmentweb development / real-time

The scenario: you need the browser to get live data — a notification badge, an order-status ping, a chat, a stock ticker. But HTTP is request→response; the server can't just "push" out of nowhere. Three ways to solve it. Picking the wrong one is a classic intermediate mistake.

Long Polling

Client sends a request; the server HOLDS it open until it has data (or times out), then responds. The client immediately re-requests.

  • Transport: plain HTTP — works everywhere, through every proxy.
  • Cost: each message = a whole new request (headers, TLS, routing).
  • Use when: low message rate, max compatibility, can't add infra.

Server-Sent Events (SSE)

ONE long-lived HTTP response that streams events. Built into browsers.

  • Direction: server → client only.
  • Free auto-reconnect + resume via Last-Event-ID.
  • Watch the ~6-connections-per-domain cap on HTTP/1.1 (HTTP/2 multiplexes and fixes it).

Minimal SSE:

const es = new EventSource('/updates');
es.onmessage = e => console.log(e.data);

Server writes chunks like data: hello\n\n with Content-Type: text/event-stream.

WebSockets

A single TCP connection UPGRADED (HTTP 101 Switching Protocols) into a full-duplex channel. Both sides send anytime.

  • Direction: bidirectional, tiny per-message overhead (a 2–14 byte frame vs full HTTP headers).
  • Not plain HTTP after the upgrade — needs ws://wss:// and sometimes proxy/LB config.
  • You re-implement heartbeats + reconnect yourself.

Decision rule

  • One-way, keep it simple → SSE.
  • Two-way, chatty → WebSockets.
  • Must cross hostile proxies / ancient clients → Long Polling.

What people get wrong

  • Reaching for WebSockets for a notification badge. SSE is simpler and auto-reconnects; with WS you own the reconnect logic.
  • Forgetting SSE's per-domain connection cap on HTTP/1.1: open 6 tabs = 6 streams, the 7th hangs. HTTP/2 removes the pain.
  • Load balancers silently killing idle connections — BOTH SSE and WS need heartbeats/timeouts tuned or they die after ~60s.

Your exercise

You're building both a "download progress %" bar and a live chat in the same app. Which transport for each, and why? Bonus: for the SSE one, what breaks when a user opens 8 tabs on HTTP/1.1 — and how does switching to HTTP/2 change your answer?