What Is a WebSocket? A Practical Guide

A WebSocket is a persistent, two-way connection between client and server over a single TCP connection. Unlike REST, where every exchange is a fresh request/response pair, a WebSocket connection stays open — either side can send a message at any time, without the other side having asked for one.

The Handshake

A WebSocket connection starts as a regular HTTP request that asks to “upgrade” the protocol:

GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

If the server agrees, it responds 101 Switching Protocols and the connection becomes a WebSocket — the URL scheme switches from http(s):// to ws:// (or wss:// for the encrypted version, which you should default to the same way you’d default to HTTPS).

Why WebSocket Instead of Polling

Before WebSockets, “real-time” usually meant polling — the client asks “anything new?” every few seconds, most of the time getting back “no.” WebSockets flip that: the server pushes a message the instant something happens, with no wasted requests in between. This matters for chat, live notifications, collaborative editing, price tickers, or anything else where the client needs to react to server-side events without asking first.

Frames, Not Requests

Once connected, both sides exchange frames — individual messages sent over the open connection, not fresh HTTP requests. There’s no built-in request/response pairing; if you need to correlate a sent message with a specific reply, that’s typically handled at the application level (an id field in a JSON payload, for example), not by the protocol itself.

WebSocket vs. REST vs. GraphQL Subscriptions

  • REST — request/response, one exchange per HTTP call. Simple, cacheable, no persistent connection.
  • WebSocket — a persistent connection either side can push to. No built-in typing or query language of its own.
  • GraphQL subscriptions — a typed, schema-aware way to describe what real-time updates a client wants, commonly implemented on top of a WebSocket connection under the hood.

Security Notes

  • Always prefer wss:// over ws:// — same reasoning as HTTPS over HTTP, the connection is otherwise unencrypted for its entire lifetime, not just one request.
  • Authenticating a WebSocket connection is less standardized than REST: the browser WebSocket API can’t attach custom headers during the handshake, so auth commonly travels as a query parameter, a cookie already present on the domain, or an initial message sent right after the connection opens.

Testing WebSockets in HTTP Titan

HTTP Titan connects to a ws:///wss:// URL (with {{variable}} interpolation for switching environments) and keeps the connection open — send as many messages as you want without reconnecting, with every inbound and outbound frame logged in order so you can see the full conversation. Subprotocol negotiation is supported directly; custom handshake headers aren’t available from the browser (a limitation of the browser WebSocket API itself, not HTTP Titan) and require the desktop app.