All Writing
Real-Time8 min read

How WebSockets actually work.

What changes when a connection stops being request/response and stays open — traced through the handshake, and a message neither side asked for.

Every post in this series so far has shared one assumption: the client asks, the server answers, the connection closes. That model breaks down the moment you need a chat message, a live score, or another user’s cursor to show up the instant it happens, not the next time someone thinks to ask. WebSockets fix this by turning the connection itself into something that just stays open — so the server can hand you data whenever it wants, not only when you request it.

The one-sentence version
A WebSocket is one TCP connection that never hangs up after the first exchange — so either side can send a message at any moment, with no new request required.

The problem: how do you get updates without asking?

Before WebSockets existed, the only tool was HTTP, and HTTP only moves in one direction per exchange — client asks, server answers, done. The workaround was polling: have the browser ask “anything new?” every few seconds, forever, whether or not the answer has changed. It works, but almost every request comes back empty, and real-time starts to mean whatever your polling interval is, not actually real-time.

Polling

  • Client repeatedly asks "anything new?" on a timer
  • Most requests come back with nothing changed
  • Update latency = however long you wait between polls
  • A new HTTP request/response cycle, every single time

WebSocket

  • One connection, opened once, left open
  • Server sends the instant there is something to send
  • Update latency ≈ network latency, not a polling interval
  • Zero connection overhead after the handshake

Step one — the handshake that upgrades HTTP

A WebSocket connection is born as an ordinary HTTP request. The magic is in a few headers that ask the server to switch protocols on this same connection instead of responding normally.

Client
Server
Step 1 of 4

It starts as a completely normal HTTP request — just with extra headers asking the server to switch protocols instead of returning a page.

Wait — is any of that encrypted?

No, and that trips people up. Sec-WebSocket-Key and Sec-WebSocket-Accept aren’t security — they’re a handshake ritual that stops a plain HTTP server (or a cache sitting in between) from accidentally treating a WebSocket upgrade as a normal request it doesn’t understand. Actual encryption comes from running the handshake over HTTPS, which upgrades it to wss:// instead of ws:// — the exact same relationship as http:// and https://.

Step two — now either side can just talk

This is the part that has no real equivalent in a request/response world. Once the socket is open, a message can originate from the server with nothing from the client prompting it — and in a chat room, a message from one client gets relayed to another through the server.

Client A
Server
Client B
Step 1 of 5

Client A sends a message over the already-open socket. No new request, no headers, no URL — just a frame of data.

101 Switching Protocols

Handshake status

Every ~30s

Typical heartbeat

As little as 2 bytes

Per-message overhead

Keeping the connection honest

An open socket can go quietly dead — a laptop sleeps, a phone switches networks, a corporate proxy silently drops idle connections — without either side getting a clean “closed” signal. The fix is a heartbeat: small ping/pong frames sent every 20–30 seconds. No pong back in time, and the server treats the connection as dead and cleans it up.

Common mistake
Treating a WebSocket as something that just stays connected forever on its own. Networks drop connections constantly — mobile especially. Production code needs reconnection logic (with backoff) on the client and a heartbeat on the server, or you end up with UIs that silently stop updating and nobody notices until a user complains.

WebSocket vs. Server-Sent Events

If data only ever needs to flow server → client — a live feed, a progress bar, a notification stream — a full bidirectional WebSocket can be more than the job needs. Server-Sent Events (SSE) cover that narrower case over plain HTTP, with automatic reconnection built into the browser for free.

WebSocket

  • True two-way — either side sends anytime
  • Binary or text frames
  • Needs its own reconnection logic
  • Right fit: chat, multiplayer, collaborative editing

Server-Sent Events

  • One-way — server to client only
  • Plain text over a regular HTTP connection
  • Browser reconnects automatically
  • Right fit: notifications, live feeds, progress updates

Where you’ve already used this

  • Chat and collaborative tools — messages, typing indicators, and live cursors (Google Docs, Figma) all ride on an open socket.
  • Live data — stock tickers, sports scores, and multiplayer game state all need updates faster than any reasonable poll interval.
  • Notifications — the little badge that updates without a page refresh is almost always a push over a persistent connection.
In practice
Most teams don’t hand-roll the raw WebSocket API — libraries like Socket.IO add automatic reconnection, fallback transports, and room/broadcast helpers on top. And the moment you run more than one server instance, a message from a client on server A needs a way to reach a client connected to server B — which is exactly the Redis pub/sub problem from the caching posts in this series, repurposed as a message bus between servers.