WebSocket

A WebSocket is a persistent, bidirectional connection between a client and a server, defined by RFC 6455. The connection starts as an HTTP request, upgrades to the WebSocket protocol via a Connection: Upgrade handshake, and then carries framed binary or text messages in either direction until either side closes it.

Why it matters

WebSockets are the transport layer for nearly every modern real-time feature: chat, presence, live cursors, notifications, collaborative editing, game state, live dashboards. The defining property is that the server can push to the client without the client polling. Latency drops from polling-interval-bound (seconds) to network-RTT-bound (tens of milliseconds).

For a real-time service, the WebSocket is the substrate. Everything else (the Pusher protocol, channel auth, presence channels, fan-out) sits on top of the WebSocket as application-layer semantics. Choosing where to terminate the WebSocket (regional, multi-region, edge) is the single biggest latency decision in a real-time architecture.

How it works

A WebSocket connection has three phases.

Handshake. The client sends an HTTP/1.1 GET with Upgrade: websocket, Connection: Upgrade, and a Sec-WebSocket-Key header. The server responds with 101 Switching Protocols and a derived Sec-WebSocket-Accept header. After that response, the connection is no longer an HTTP exchange; it is a framed WebSocket.

Data frames. Either side can send a frame at any time. Frames have an opcode (text, binary, close, ping, pong) and a payload. Text frames carry UTF-8 strings, typically JSON in real-time protocols. Binary frames carry arbitrary bytes.

Close. Either side sends a close frame. The other replies. The TCP connection terminates.

A minimal client-side connection in browser JS:

const ws = new WebSocket('wss://ws.example.com/app/your-app-key');
ws.onopen = () =>
    ws.send(
        JSON.stringify({
            event: 'pusher:subscribe',
            data: { channel: 'live' },
        }),
    );
ws.onmessage = (e) => console.log('frame', e.data);
ws.onclose = () => console.log('disconnected');

Higher-level SDKs (pusher-js, laravel-echo) wrap this with auto-reconnect, channel multiplexing, private channel auth, and presence state, so applications rarely interact with the raw WebSocket object directly.

Each open WebSocket counts as one entry on the concurrent connections gauge for the real-time service, regardless of how many channels it subscribes to.

Related terms

See also

What is a WebSocket?
A WebSocket is a persistent bidirectional connection between a client and server, defined by RFC 6455. The connection starts as an HTTP request, upgrades to the WebSocket protocol via a handshake header, and then carries framed messages in either direction until either side closes it.
How is a WebSocket different from HTTP polling?
HTTP polling repeats short request/response cycles. The client asks. The server answers. The connection closes. A WebSocket holds one connection open and lets either side send a frame any time. Lower latency, lower overhead per message, and no client-side polling loop.
What is wss versus ws?
wss:// is WebSocket over TLS, the encrypted variant, and the only one used in production. ws:// is the plaintext variant, intended for local development. Any production real-time service exposes a wss:// endpoint.