The chat app worked perfectly in development. In production, behind two servers and a load balancer, users could send messages but only sometimes received them — specifically, only when the recipient happened to be connected to the same server as the sender. Which is roughly a coin flip, and which is the single most common WebSocket production failure there is.
WebSocket interview questions are mostly about that gap between a working prototype and a system that survives more than one server. This guide covers the handshake, the scaling problem and its solutions, heartbeats and reconnection, and the comparison question — when a WebSocket is the wrong choice.
What WebSocket interviews actually test
- The protocol — the HTTP upgrade handshake, framing, and how it differs from HTTP.
- Scaling — the story above, plus sticky sessions and pub/sub fan-out.
- Connection health — heartbeats, half-open connections, reconnection with backoff.
- Reliability — message ordering, delivery guarantees, missed messages on reconnect.
- Alternatives — SSE, long polling, and knowing when not to use WebSockets.
The handshake and the protocol
A WebSocket connection starts as an ordinary HTTP GET carrying Upgrade: websocket, Connection: Upgrade and a random Sec-WebSocket-Key. The server responds 101 Switching Protocols with a Sec-WebSocket-Accept derived from that key, and from then on the same TCP connection carries WebSocket frames rather than HTTP messages.
Points interviewers probe:
- Why start with HTTP at all? So the connection traverses existing infrastructure — proxies, firewalls and load balancers on ports 80 and 443 — rather than needing a new port.
- The key exchange is not security.
Sec-WebSocket-Acceptproves the server understood the WebSocket protocol, preventing cache-poisoning style confusion with non-WebSocket servers. It is not authentication and not encryption; that iswss://and your own auth. - Full duplex and persistent — either side can send at any time, with no request-response pairing and no per-message HTTP headers, which is the actual performance win over polling.
- Authentication is awkward, because the browser WebSocket API cannot set custom headers. The usual patterns are a cookie sent with the handshake, a short-lived ticket in the query string, or authenticating in the first message after connecting. Naming that limitation unprompted is a good signal.
Scaling: the problem from the intro
A WebSocket is stateful — the connection lives on one specific server process. So with several servers behind a load balancer, a message published on server A cannot reach a client connected to server B. The fixes, and interviewers want both:
- A pub/sub backplane. The real answer. Every server subscribes to a shared broker — Redis pub/sub, NATS or Kafka — and publishes outbound messages there rather than writing directly to sockets. Each server then delivers to whichever clients it happens to hold. This decouples delivery from connection placement entirely.
- Sticky sessions keep a given client pinned to one server, which is necessary for the connection itself but does not solve cross-server delivery. Saying this distinction clearly is what separates a good answer from a memorised one.
Then the operational realities, which senior rounds go after:
- Connection count is the scaling unit, not requests per second. Each connection consumes memory and a file descriptor even when idle, so you tune
ulimitand plan capacity by concurrent connections. - Deploys drop every connection. Rolling restarts disconnect users en masse, and they all reconnect at once — so reconnection needs jitter or you build your own thundering herd.
- Load balancers need explicit WebSocket support and long idle timeouts, or they silently kill connections at 60 seconds. This is a classic production incident.
Our Redis interview questions guide covers the pub/sub layer and the Nginx guide covers the proxy configuration that trips people up.
Heartbeats, half-open connections and reconnection
The subtle problem: TCP does not reliably tell you when a peer vanishes. If a user's phone loses signal, the server may hold a connection it believes is alive for a very long time — a half-open connection. You are writing into a void and consuming resources.
The fix is application-level heartbeats: the protocol provides ping and pong frames, and the server pings periodically (say every 30 seconds) and closes the connection if no pong arrives within a timeout. Clients often do the same in reverse. Say explicitly that this is also what keeps intermediate proxies from timing out an idle connection.
// Reconnect with exponential backoff + jitter, then resync from a cursor
let attempt = 0;
let lastSeenId = localStorage.getItem("lastSeenId");
function connect() {
const ws = new WebSocket(url);
ws.onopen = () => {
attempt = 0;
// Replay anything missed while we were disconnected
ws.send(JSON.stringify({ type: "resume", since: lastSeenId }));
};
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
lastSeenId = msg.id;
localStorage.setItem("lastSeenId", msg.id);
ws.send(JSON.stringify({ type: "ack", id: msg.id }));
};
ws.onclose = () => {
const base = Math.min(30000, 1000 * 2 ** attempt++);
// Jitter is the part people omit — without it every client returns at once
setTimeout(connect, base * (0.5 + Math.random() * 0.5));
};
}
On reconnection, the client-side answer expected is: detect the close, reconnect with exponential backoff plus jitter (jitter being the part that prevents every client returning simultaneously after an outage), cap the maximum delay, and — the part people forget — resynchronise state. Messages sent while disconnected are simply gone unless you handle them, which leads to the next section.
Delivery guarantees and ordering
A question that separates candidates: does a WebSocket guarantee delivery? The honest answer is that it guarantees ordering within a connection because it rides on TCP, but it guarantees nothing about your application: a message written to a socket that then drops is lost, and the sender gets no error.
So for anything that matters you build guarantees on top:
- Application-level acknowledgements — the client confirms receipt by message ID, and the server retries unacknowledged messages.
- Sequence numbers so a client can detect gaps.
- A durable log plus cursor — persist messages, have the client send its last-seen ID on reconnect, and replay the difference. This is how real chat systems work, and describing it is a strong senior answer.
- Idempotent handling, because retries mean duplicates.
The framing to state: the WebSocket is a transport, not a message queue. Candidates who assume delivery semantics they have not built are exactly what this question is designed to find.
WebSocket vs SSE vs polling
Interviewers ask this to see whether you reach for WebSockets reflexively:
- Long polling — the client makes a request the server holds until data is available. Works everywhere, no special infrastructure, but higher latency and more overhead. Still a legitimate fallback.
- Server-Sent Events (SSE) — a one-way server-to-client stream over plain HTTP. Automatic reconnection and event IDs are built into the browser API, it works with existing HTTP infrastructure, and it is genuinely simpler. The right choice for notifications, live dashboards, activity feeds and streaming LLM responses — anywhere the client does not need to push.
- WebSocket — bidirectional and low latency. Correct when the client genuinely sends frequently: chat, collaborative editing, multiplayer, live trading.
The mature answer is that a large share of real-time features only need SSE, and choosing it avoids the entire scaling and reconnection burden above. Saying that reads as judgment rather than enthusiasm. Also mention that HTTP/2 removed SSE's old six-connection-per-domain limit, and that WebRTC is the answer for peer-to-peer media rather than either of these.
MDN, the RFC, real projects, ChatGPT — where each fits
- MDN's WebSocket documentation — the clearest reference for the client API and the handshake.
- RFC 6455 — the protocol spec, worth skimming for framing and close codes, which interviewers occasionally ask about.
- Building a chat app and then running two server instances — highest yield by far. You will reproduce the intro's bug yourself, and the pub/sub answer will never leave you.
- Socket.IO's documentation — useful even if you do not use it, because it documents the problems (reconnection, fallbacks, rooms, adapters) that a raw WebSocket leaves to you.
- Your load balancer's docs — specifically the idle timeout setting, which causes more production incidents than the protocol does.
- ChatGPT — good for generating a server and explaining frames. It will not ask why only half the messages arrive in production.
- Greenroom — the spoken layer. Ari, the AI interviewer, runs the round out loud and pushes the scaling and delivery follow-ups. Fair tradeoff: Ari will not load-test your socket server.
How to prepare for a WebSocket interview
- Week 1: the protocol. Implement a raw WebSocket server, inspect the handshake in DevTools, and explain the 101 response aloud.
- Week 2: scaling. Run two instances behind a proxy, reproduce the cross-server delivery bug, then fix it with a Redis pub/sub backplane.
- Week 3: resilience. Add heartbeats, kill the network mid-session, and implement reconnection with backoff, jitter and a last-seen cursor replay.
- Final week: rehearse the WebSocket-versus-SSE comparison as a judgment call, then run two full spoken mocks with system design follow-ups.
Building the rest of the stack? The Redis guide covers the backplane, the gRPC guide covers the other streaming transport, the Nginx guide covers proxy configuration, and the system design guide covers where real-time fits architecturally.
Frequently asked questions
What are the most common WebSocket interview questions?
The most common questions cover the HTTP upgrade handshake and why WebSockets start as an HTTP request, how you scale WebSockets across multiple servers, why sticky sessions alone do not solve cross-server message delivery, how heartbeats detect half-open connections, how reconnection with exponential backoff and jitter works, whether WebSockets guarantee delivery, and when Server-Sent Events would be a better choice.
How do you scale WebSockets across multiple servers?
Use a pub/sub backplane. Because a WebSocket connection lives on one specific server process, a message produced on one server cannot reach a client connected to another. Every server subscribes to a shared broker such as Redis pub/sub, NATS or Kafka and publishes outbound messages there rather than writing directly to sockets, so each server delivers to whichever clients it holds. Sticky sessions keep a client pinned to one server but do not solve cross-server delivery.
Why do you need heartbeats in a WebSocket connection?
TCP does not reliably signal when a peer disappears, so if a client loses network connectivity the server may hold a half-open connection it believes is alive, consuming memory and a file descriptor while writing into a void. Application-level ping and pong frames let the server detect this — pinging periodically and closing the connection if no pong arrives within a timeout. Heartbeats also prevent intermediate proxies from closing an idle connection.
Do WebSockets guarantee message delivery?
No. Because they ride on TCP, WebSockets guarantee ordering within a single connection, but they guarantee nothing at the application level — a message written to a socket that subsequently drops is lost and the sender receives no error. For anything important you build guarantees on top using application-level acknowledgements by message ID, sequence numbers to detect gaps, and a durable log with a client cursor so missed messages can be replayed on reconnect.
What is the difference between WebSockets and Server-Sent Events?
WebSockets are bidirectional and full duplex over a single TCP connection, suiting chat, collaborative editing and multiplayer where the client sends frequently. Server-Sent Events are one-way server-to-client over ordinary HTTP, with automatic reconnection and event IDs built into the browser API. A large share of real-time features — notifications, live dashboards, activity feeds and streaming responses — only need SSE, which avoids the entire WebSocket scaling and reconnection burden.
How do you authenticate a WebSocket connection?
It is awkward because the browser WebSocket API cannot set custom headers, so you cannot simply send an Authorization header. The common patterns are relying on a cookie automatically sent with the upgrade handshake, passing a short-lived single-use ticket as a query parameter that the server validates and immediately invalidates, or connecting first and requiring an authentication message before accepting any other traffic. Avoid putting long-lived tokens in the URL, since they land in logs.