Skip to content

WebSockets vs HTTP, Polling, and SSE

WebSockets are not the only way to move data between a browser and a server, and they are not always the right one. To choose well you need to know the alternatives. This lesson walks through four other approaches and lines them up against WebSockets on the two axes that matter most: latency (how soon the client learns about a server-side event) and overhead (how much wasted work happens per useful message).

The baseline. The client asks; the server answers; the exchange ends. The server can never speak first. For fetching pages and submitting forms this is perfect. For learning about events that happen on the server, it offers nothing — the client would have to ask again, which leads us to polling.

The client asks “anything new?” on a fixed timer — say every few seconds — and the server replies immediately, usually with “no” most of the time.

sequenceDiagram
  participant C as Client
  participant S as Server
  loop every few seconds
    C->>S: GET /updates
    S-->>C: 200 (nothing new)
  end
  Note over S: event happens here
  C->>S: GET /updates
  S-->>C: 200 (here is the update)
Short polling: repeated requests, mostly empty answers

Latency is bounded by your interval — an event can sit unseen for up to one polling period. Overhead is high: most requests carry full HTTP headers and return nothing useful. Tighten the interval and you cut latency but multiply the wasted requests. It is simple and works everywhere, which is its only real virtue.

A smarter variant. The client sends a request, and the server holds it open until either an event occurs or a timeout is reached, then responds. The client immediately sends another request and waits again.

This pushes latency down close to real-time — the response comes as soon as the event does — without a busy timer. But each delivered message still costs a full request/response cycle and a reconnect, so under heavy event rates the overhead climbs and it can strain server connection limits.

SSE opens one long-lived HTTP connection over which the server streams events to the client as they happen. It is efficient, auto-reconnects, and rides on ordinary HTTP. But it is deliberately one-way: server → client only. The client cannot send data back over the same channel; to talk to the server it makes separate normal HTTP requests.

A WebSocket also keeps one connection open, but it is bidirectional: after the handshake, both sides push messages freely with minimal per-message overhead. Latency is as low as the network allows in both directions, and there is no per-message header tax.

ApproachDirectionLatency to clientPer-message overheadBest when
HTTP request/responseClient → server (one-shot)N/A (no push)One full cycle per requestPages, forms, plain APIs
Short pollingClient asks repeatedlyUp to one intervalHigh (mostly empty)Trivial, occasional checks
Long pollingClient asks, server holdsNear real-timeOne cycle per eventReal-time-ish on plain HTTP
SSEServer → client onlyNear real-timeLow (one stream)Server push, no client uplink
WebSocketBoth directionsLowest, both waysLowest (framed messages)Interactive, two-way real-time
  • If the client only ever reads a stream of server events — a news feed, a live log tail, progress updates — SSE is simpler and rides on plain HTTP infrastructure.
  • If both sides need to send frequently and interactively — chat, collaboration, games, live controls — WebSockets are the natural fit.
  • If you need something today on the most basic infrastructure and traffic is light, long polling is a reasonable stopgap; short polling only for the truly trivial.
What is the key limitation of Server-Sent Events compared to WebSockets?
Why does short polling tend to have high overhead?
You are building an interactive collaborative whiteboard where every user both sends and receives edits constantly. Which fits best?
How does long polling reduce latency compared to short polling?