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://overws://— 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
WebSocketAPI 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.