Top 49 WebSockets & Real-time Interview Questions & Answers (2026)

49 Questions 20 Beginner 19 Intermediate 10 Advanced

About WebSockets & Real-time

Top 50 WebSockets and real-time communication interview questions covering Socket.IO, SSE, scaling, security, and protocols. Companies hiring for WebSockets & Real-time roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.

What to Expect in a WebSockets & Real-time Interview

Expect a mix of conceptual and practical WebSockets & Real-time questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.

How to Use This Guide

Work through the WebSockets & Real-time questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.

Curated by Tech Baithak Editorial Team  ·  Last updated: June 2026

Beginner 20 questions

Core concepts every WebSockets & Real-time developer must know.

01

What is WebSocket?

WebSocket is a communication protocol that provides a persistent, full-duplex (bidirectional) connection between a client and a server over a single TCP connection. Unlike HTTP, which is request-response based and stateless, WebSocket keeps the connection open after the initial handshake, allowing either side to send data at any time without the overhead of establishing a new connection. WebSocket is defined in RFC 6455 and is natively supported in all modern browsers via the WebSocket JavaScript API. It is the foundation for real-time features like live chat, notifications, collaborative editing, and live data dashboards.

Open this question on its own page
02

How does WebSocket differ from HTTP?

HTTP is a request-response protocol: the client sends a request, the server responds, and the connection is closed (or kept alive briefly for reuse). The server can never push data to the client without the client first asking. WebSocket, by contrast, maintains a persistent connection after the initial HTTP handshake. Once established, both the client and server can send messages at any time — truly bidirectional. WebSocket also has significantly lower overhead per message: after the handshake, frames have only 2–14 bytes of overhead compared to HTTP headers that can be hundreds of bytes. HTTP is ideal for traditional request-response interactions; WebSocket is ideal for real-time, event-driven communication where the server needs to push updates unprompted.

Open this question on its own page
03

What is the WebSocket handshake?

The WebSocket connection begins with an HTTP Upgrade handshake. The client sends a standard HTTP GET request with special headers: Upgrade: websocket, Connection: Upgrade, and a Sec-WebSocket-Key (a base64-encoded random value). The server responds with HTTP status 101 Switching Protocols, echoes back a Sec-WebSocket-Accept header (derived by hashing the key with a GUID), and the connection is upgraded from HTTP to the WebSocket protocol. After this handshake, the TCP connection remains open and both sides communicate using WebSocket frames instead of HTTP messages. The handshake happens over the same port as HTTP (80) or HTTPS (443), which helps with firewall compatibility.

Open this question on its own page
04

What is real-time communication?

Real-time communication refers to data exchange that occurs with minimal latency, enabling near-instantaneous delivery of information between sender and receiver. In web applications, it means the server can push updates to clients immediately when data changes, without requiring the client to poll repeatedly. Examples include: live chat messages appearing instantly, stock prices updating as trades happen, collaborative document editing showing other users' cursors and keystrokes in real time, and sports scores updating the moment a goal is scored. Technologies enabling real-time communication include WebSockets (full-duplex), Server-Sent Events (server-to-client only), WebRTC (peer-to-peer), and long polling (HTTP-based fallback).

Open this question on its own page
05

What are common use cases for WebSockets?

WebSockets are ideal for applications that require low-latency, bidirectional, real-time data flow. Common use cases: (1) Live chat — messaging apps like Slack, Discord, WhatsApp Web; (2) Collaborative tools — Google Docs-style real-time editing, Figma's multiplayer design; (3) Live dashboards — monitoring metrics, analytics dashboards, server health monitors; (4) Financial applications — real-time stock prices, cryptocurrency trading platforms, order book updates; (5) Gaming — multiplayer browser games requiring low-latency input; (6) Notifications — push notifications, alert systems; (7) Live sports — score updates, play-by-play commentary; (8) IoT — device telemetry, remote control. Use cases requiring only server-to-client updates (like news feeds) often use Server-Sent Events instead for simplicity.

Open this question on its own page
06

What is Socket.IO?

Socket.IO is a JavaScript library that provides a higher-level abstraction over WebSockets with additional features. It consists of a server library (Node.js) and a client library (browser/Node). Key additions over raw WebSockets include: automatic reconnection when the connection drops, event-based communication (emit/on pattern instead of raw message strings), rooms and namespaces for organizing connections, broadcasting to multiple clients, fallback transports (falls back to HTTP long polling if WebSocket is unavailable), and acknowledgments for confirmed message delivery. Socket.IO does NOT use the standard WebSocket protocol by default — its protocol adds a layer on top, meaning Socket.IO clients and servers must both use the Socket.IO library.

Open this question on its own page
07

What is the difference between WebSockets and Server-Sent Events (SSE)?

Server-Sent Events (SSE) is a simpler, unidirectional protocol for streaming data from server to client over a standard HTTP connection. WebSockets and SSE differ in: (1) Direction — WebSockets are full-duplex (both sides send); SSE is one-way (server to client only); (2) Protocol — SSE uses plain HTTP, WebSockets use their own protocol; (3) Browser support — SSE uses the native EventSource API; WebSockets use the WebSocket API; (4) Reconnection — SSE has built-in automatic reconnection; WebSockets require custom reconnection logic; (5) Complexity — SSE is simpler and works with standard HTTP infrastructure; (6) HTTP/2 — SSE multiplexes natively over HTTP/2; WebSocket has separate multiplexing. Use SSE for notifications, live feeds, and progress updates. Use WebSockets for interactive, bidirectional communication.

Open this question on its own page
08

What is long polling?

Long polling is a technique that simulates real-time server-to-client push using standard HTTP. Instead of the server responding immediately, it holds the request open until new data is available (or a timeout occurs). When the server has data, it responds, the client processes the response, and immediately sends a new request to wait for the next piece of data. This creates a continuous cycle that mimics push behavior. Long polling works everywhere HTTP works (no special protocol support needed) but is less efficient than WebSockets — each "push" requires a new HTTP handshake, headers overhead, and server resources for each held connection. It was the primary real-time technique before WebSockets were widely supported. Socket.IO uses long polling as a fallback transport.

Open this question on its own page
09

What is the WebSocket protocol (ws:// and wss://)?

WebSocket URLs use the schemes ws:// and wss:// analogously to HTTP's http:// and https://. ws:// is the unencrypted WebSocket protocol — the connection data is sent in plaintext, susceptible to eavesdropping. wss:// is WebSocket Secure — the WebSocket connection is wrapped in TLS (the same as HTTPS), providing encryption, authentication, and integrity protection. In production, always use wss://. Modern browsers block mixed content — if your page is served over HTTPS, any WebSocket connections must use wss:// or the browser will refuse the connection. wss:// typically runs on port 443, the same as HTTPS, which avoids firewall issues that port 80 (ws://) may not have.

Open this question on its own page
10

How do you create a WebSocket connection in JavaScript?

Creating a WebSocket connection in JavaScript uses the native WebSocket API: const ws = new WebSocket('wss://example.com/ws'). After creation, you listen for events: ws.onopen = () => console.log('Connected') fires when the connection is established; ws.onmessage = (event) => console.log(event.data) fires when a message arrives; ws.onerror = (error) => console.error(error) fires on errors; ws.onclose = (event) => console.log('Closed:', event.code) fires when the connection closes. To send data: ws.send('Hello') or ws.send(JSON.stringify({ type: 'chat', text: 'Hello' })). The ws.readyState property tells the connection state: 0 (CONNECTING), 1 (OPEN), 2 (CLOSING), 3 (CLOSED).

Open this question on its own page
11

What events does a WebSocket connection have?

The WebSocket API exposes four primary events: (1) open — fires when the connection is successfully established after the handshake; this is when you can safely start sending messages; (2) message — fires when a message is received from the server; the event object contains a data property with the message content (string or Blob); (3) error — fires when an error occurs; unfortunately, the browser intentionally provides minimal error details for security reasons; (4) close — fires when the connection is closed, with a code (WebSocket close code, e.g., 1000 for normal closure, 1006 for abnormal) and reason string. You can listen using either ws.onopen = handler or ws.addEventListener('open', handler).

Open this question on its own page
12

What is a WebSocket frame?

A WebSocket frame is the basic unit of data transmission in the WebSocket protocol. Unlike HTTP which sends full messages, WebSocket organizes data into frames that can be sent in a stream. A frame consists of: a FIN bit (indicates if this is the final fragment), an opcode (0x1 for text, 0x2 for binary, 0x8 for close, 0x9 for ping, 0xA for pong), a mask bit (client-to-server frames must be masked for security), a payload length (7-bit, 7+16-bit, or 7+64-bit encoding), an optional masking key (4 bytes for client frames), and the payload data. The frame header overhead is only 2–14 bytes, making WebSocket extremely efficient for high-frequency small messages compared to HTTP's kilobytes of headers per request.

Open this question on its own page
13

How do you send data over a WebSocket connection?

Data is sent over WebSocket using the ws.send(data) method, which accepts three data types: String (text message, most common), ArrayBuffer (raw binary data), and Blob (binary large object, useful for files). For structured data, serialize to JSON: ws.send(JSON.stringify({ type: 'message', payload: 'Hello' })). The server then parses the JSON string. For binary protocols (images, audio streams, game state), use ArrayBuffer for efficiency — binary avoids the overhead of base64 encoding. Always check ws.readyState === WebSocket.OPEN before calling send(), as sending on a closed connection throws an error. You can also monitor ws.bufferedAmount to check how much data is queued but not yet sent to the network.

Open this question on its own page
14

What is a WebSocket ping/pong?

WebSocket ping/pong is a built-in heartbeat mechanism defined in the WebSocket protocol. The server sends a ping frame (opcode 0x9), and the client is required by the spec to respond with a pong frame (opcode 0xA) containing the same payload. This serves two purposes: (1) Connection keepalive — prevents firewalls, proxies, and load balancers from closing idle connections due to timeout; (2) Liveness detection — if the server sends a ping and doesn't receive a pong within a timeout, it knows the client is disconnected and can clean up server-side resources. The browser's WebSocket API handles pong responses automatically — you don't need to implement it manually. The ws Node.js library fires a ping event when a ping is received and a pong event when a pong arrives.

Open this question on its own page
15

What happens when a WebSocket connection is lost?

When a WebSocket connection is lost unexpectedly (network drop, server restart, browser tab backgrounding on mobile), the close event fires with close code 1006 (abnormal closure — no close frame was received). The connection does not automatically reconnect — this is left to the application developer. The standard approach is exponential backoff reconnection: attempt reconnection after 1s, then 2s, 4s, 8s, up to a maximum interval (e.g., 30s), to avoid overwhelming the server. Socket.IO handles this automatically. Libraries like ReconnectingWebSocket wrap the native WebSocket with automatic reconnection logic. During reconnection, the application must handle state: queue messages sent during disconnection, or notify the user of the interrupted connection and allow manual retry.

Open this question on its own page
16

What is Socket.IO's fallback mechanism?

Socket.IO implements a transport escalation strategy to maximize compatibility. By default, it first establishes an HTTP long-polling connection (which works everywhere HTTP works) and then attempts to upgrade to WebSocket once the long-polling connection is confirmed working. This ensures connectivity even in environments where WebSockets are blocked by strict firewalls, corporate proxies, or older infrastructure. If the upgrade fails, it continues over long polling with minimal disruption. You can configure Socket.IO to start with WebSocket directly (transports: ['websocket']) for better performance when you know your environment supports it. The fallback mechanism is why Socket.IO is popular in enterprise environments where network policies may block non-HTTP traffic.

Open this question on its own page
17

How does a chat application use WebSockets?

A WebSocket-based chat application works as follows: (1) Each user connects to the WebSocket server on page load, creating a persistent connection; (2) The server maintains a map of userId → WebSocket connection; (3) When User A sends a message, their browser sends it to the server via ws.send(JSON.stringify({ to: 'UserB', text: 'Hello' })); (4) The server receives the message, looks up User B's connection, and calls connectionB.send(...) to deliver it; (5) User B's browser receives the message event and updates the UI. For group chats, the server iterates all connections in a room and sends to each. The key advantage: message delivery is near-instant (milliseconds) without any polling — messages "push" directly to connected users the moment they're sent.

Open this question on its own page
18

How do you close a WebSocket connection?

A WebSocket connection is closed gracefully using ws.close(code, reason). The close code is a numeric status (e.g., 1000 for normal closure, 1001 for going away, 1008 for policy violation). The reason is an optional human-readable string explaining why the connection is closing. A graceful close sends a close frame to the other party, which must respond with its own close frame before the TCP connection is terminated — this ensures both sides know the connection is intentionally ending. You can detect close initiation by the server by listening to the client's close event. Calling ws.close() without arguments sends close code 1000. If the connection is force-closed (network failure), no close frame is sent and the other party detects it via timeout or TCP RST.

Open this question on its own page
19

What browsers support WebSockets?

WebSockets have universal browser support across all modern browsers since 2012. All versions of Chrome (from v16), Firefox (from v11), Safari (from v7), Edge (from v12), and Opera support the WebSocket API. Internet Explorer 10 and 11 also support WebSockets. Mobile browsers — Mobile Safari (iOS 6+), Android Browser (4.4+), and Chrome for Android — all support WebSockets. According to CanIUse.com, WebSocket support is at ~97%+ of global browser usage. The only environments where WebSockets might be blocked are restrictive corporate firewalls/proxies that only allow standard HTTP traffic, or very old embedded browsers in IoT devices. For these edge cases, Socket.IO's long-polling fallback or SSE provides the necessary compatibility.

Open this question on its own page
20

What triggers can break a WebSocket connection?

WebSocket connections can be terminated by many factors: (1) Network interruption — WiFi dropout, mobile network switching (3G/4G), VPN reconnection; (2) Server restart or crash — the server process terminates, closing all connections; (3) Proxy/firewall timeout — HTTP proxies and load balancers often close idle TCP connections after 60-90 seconds; (4) Browser navigation — navigating away from the page, refreshing, or closing the tab; (5) Browser throttling — mobile browsers may close WebSocket connections when a tab is in the background for extended periods; (6) Server-side close — the server explicitly calls ws.close(); (7) Memory pressure — the browser kills the background tab and its connections; (8) TLS certificate issues for wss:// connections. Robust applications implement heartbeat (ping/pong) and reconnection logic to handle all these scenarios.

Open this question on its own page
Intermediate 19 questions

Practical knowledge for developers with hands-on experience.

01

How do you implement a WebSocket server in Node.js using the `ws` library?

The ws library is the most popular bare-bones WebSocket server for Node.js. Install with npm install ws. Basic server setup: const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', (ws, req) => { ws.on('message', (data) => { console.log('Received:', data.toString()); ws.send('Echo: ' + data); }); ws.on('close', () => console.log('Client disconnected')); ws.send('Welcome!'); }). To broadcast to all clients: wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) client.send(message); }). The ws library integrates with existing HTTP servers (Express, Fastify) by attaching to the server instance rather than creating its own port, enabling WebSocket and HTTP on the same port.

Open this question on its own page
02

What are Socket.IO rooms and namespaces?

Namespaces and Rooms are Socket.IO's two-level organization system for connections. A namespace is a separate communication channel within the same socket connection — essentially a path multiplexed over one TCP connection. Default namespace is /; you create custom ones with io.of('/chat'). Different namespaces can have different auth middleware. A room is a logical group within a namespace that sockets can join and leave dynamically. socket.join('room-123') adds the socket to a room; io.to('room-123').emit('event', data) broadcasts to all sockets in that room. Rooms are perfect for chat rooms, game sessions, or per-user notification channels. Unlike namespaces (separate resources), rooms are purely server-side groupings with no client-side counterpart.

Open this question on its own page
03

How do you handle WebSocket reconnection logic?

Robust reconnection uses exponential backoff with jitter to avoid thundering herd problems (all clients reconnecting simultaneously after a server restart). Implementation: let retryDelay = 1000; const maxDelay = 30000; function connect() { const ws = new WebSocket(url); ws.onopen = () => { retryDelay = 1000; }; ws.onclose = () => { const jitter = Math.random() * 1000; setTimeout(() => connect(), Math.min(retryDelay + jitter, maxDelay)); retryDelay *= 2; }; }. Key considerations: (1) State reconciliation — after reconnecting, fetch missed events from the server using a "last seen" event ID; (2) Message queuing — buffer messages sent while disconnected and replay them after reconnection; (3) User feedback — show a "reconnecting..." indicator in the UI; (4) Max attempts — stop retrying after N failures and show an error. Libraries like ReconnectingWebSocket encapsulate this logic.

Open this question on its own page
04

What is the difference between Socket.IO and raw WebSockets?

Key differences: (1) Protocol — raw WebSocket sends plain strings/binary; Socket.IO adds its own message format with event names and acknowledgments; (2) Interoperability — a standard WebSocket client cannot connect to a Socket.IO server (and vice versa) without Socket.IO's library; (3) Features — Socket.IO adds rooms, namespaces, auto-reconnection, event-based API, broadcasting, acknowledgments, and long-polling fallback; (4) Performance — Socket.IO has higher overhead per message due to its protocol layer; raw WebSocket is leaner for high-frequency binary data; (5) Complexity — Socket.IO is simpler to use for common patterns; raw WebSocket requires implementing patterns manually; (6) Bundle size — Socket.IO client adds ~45KB to the browser bundle. Choose raw WebSocket for performance-critical applications with custom protocols; choose Socket.IO for rapid development of standard real-time features.

Open this question on its own page
05

How do you authenticate WebSocket connections?

WebSocket connections lack cookie-based auth by default after the protocol upgrade, so authentication must be handled explicitly. Three common approaches: (1) Query parameter token — pass a JWT or session token in the WebSocket URL: new WebSocket('wss://api.example.com/ws?token=xxx'); the server validates it in the connection event handler. Simple but tokens appear in server logs; (2) First message authentication — establish the WebSocket connection unauthenticated, then send credentials as the first message; the server authenticates before allowing further messages; (3) Cookie-based — WebSocket upgrade requests send cookies automatically, so if the user has an HTTP session cookie, the server can read it from the upgrade request headers (req.headers.cookie in Node.js). In Socket.IO, use the auth option: io({ auth: { token: 'xxx' } }) and validate in middleware with io.use((socket, next) => { verifyToken(socket.handshake.auth.token) }).

Open this question on its own page
06

How do WebSockets work behind a load balancer?

WebSockets behind a load balancer require sticky sessions (session affinity) because the connection is persistent — once established with a specific server instance, all messages must go to the same instance. Standard round-robin load balancing breaks WebSocket connections. Solutions: (1) Sticky sessions by IP or cookie — NGINX (ip_hash), HAProxy (balance source), or AWS ALB (cookie-based stickiness) route the same client to the same backend. Requires configuring the load balancer. (2) Shared state via Redis — instead of sticky sessions, use a Redis pub/sub layer: each server instance subscribes to Redis channels and forwards relevant messages to its local clients. This is the recommended scalable approach. Socket.IO provides socket.io-redis adapter that handles this automatically. (3) WebSocket-aware proxies — NGINX and HAProxy support WebSocket proxying with the Upgrade header.

Open this question on its own page
07

What is Redis Pub/Sub and how does it help with WebSocket scaling?

When WebSocket servers scale horizontally, a message sent to a client on Server A cannot reach a client connected to Server B — they have separate in-memory connection pools. Redis Pub/Sub solves this by acting as a message broker between server instances. Each server instance subscribes to Redis channels relevant to its clients. When Server A needs to send a message to all users in room "game-42", it publishes to the Redis channel room:game-42. Redis delivers that message to all subscribers — Server A, B, and C all receive it and each forward it to their local connections in that room. Socket.IO's @socket.io/redis-adapter implements this pattern automatically: you just configure the Redis connection and io.to(room).emit() works correctly across all instances without code changes.

Open this question on its own page
08

How do you implement presence (online/offline) with WebSockets?

Presence tracking with WebSockets follows this pattern: (1) On connection — when a user's WebSocket connects, the server records them as online (onlineUsers.set(userId, ws)) and broadcasts a "user-online" event to relevant users; (2) On disconnect — when the connection closes (close event), remove from the map and broadcast "user-offline"; (3) Heartbeat for ghost detection — users can disconnect without a clean close (network drop). Implement ping/pong: the server pings every 30s; if no pong within 5s, mark as offline. In multi-server environments, store presence in Redis with TTL: SET user:123:online 1 EX 35 (expires after 35s, refreshed by each pong). This prevents phantom-online users if a server crashes. For group chat, broadcast presence only to users sharing a conversation to avoid broadcasting to all connected users.

Open this question on its own page
09

What is the WebSocket subprotocol?

The WebSocket subprotocol is an application-level protocol negotiated during the handshake via the Sec-WebSocket-Protocol header. The client lists the protocols it supports (comma-separated), and the server selects one and includes it in the response. The subprotocol defines how messages are structured and interpreted. Examples: STOMP (Simple Text Oriented Messaging Protocol) — used with message brokers like ActiveMQ and RabbitMQ over WebSockets; WAMP (Web Application Messaging Protocol) — provides RPC and Pub/Sub patterns; MQTT over WebSocket — used in IoT applications. If no subprotocol header is sent, both sides must agree out-of-band on the message format (often raw JSON). In Socket.IO's protocol, the subprotocol is socket.io (though it doesn't use standard WebSocket subprotocol negotiation).

Open this question on its own page
10

How do you handle binary data over WebSockets?

WebSocket natively supports binary frames (opcode 0x2) in addition to text frames. On the client, set ws.binaryType = 'arraybuffer' (default is blob) to receive binary data as ArrayBuffer objects. Sending binary: ws.send(arrayBuffer) or ws.send(blob). Use cases: transmitting images, audio samples, game state encoded in a compact binary format (reducing bandwidth vs. JSON). For example, encoding game position as a Float32Array (Float32Array([x, y, rotation])) sends 12 bytes vs. ~30 bytes of JSON. On the server (Node.js ws library), binary messages arrive as Buffer objects. Protobuf or MessagePack are common binary serialization formats used with WebSocket binary frames, offering significant bandwidth savings over JSON for high-frequency or large messages.

Open this question on its own page
11

How do you broadcast messages to multiple clients?

Broadcasting sends a message to multiple clients simultaneously. In raw WebSocket (Node.js ws library): wss.clients.forEach(client => { if (client !== sender && client.readyState === WebSocket.OPEN) { client.send(message); } }). The check client !== sender excludes the sending client. In Socket.IO, broadcasting is built-in: socket.broadcast.emit('event', data) sends to all except sender; io.emit('event', data) sends to all including sender; io.to('room').emit('event', data) sends to a specific room. For targeted broadcast (e.g., send to all sessions of a specific user), maintain a Map<userId, Set<WebSocket>> for users with multiple open connections. Broadcasting should be asynchronous — avoid blocking the event loop by sending to thousands of clients synchronously.

Open this question on its own page
12

What are the security considerations for WebSocket connections?

WebSocket security requires attention to: (1) Always use wss:// — encrypt connections to prevent eavesdropping and man-in-the-middle attacks; (2) Origin validation — check the Origin header during handshake to prevent cross-site WebSocket hijacking (CSWSH); (3) Authentication — validate tokens/sessions before accepting the connection, not after; (4) Input validation — WebSocket messages bypass web application firewalls; validate and sanitize all incoming data server-side; (5) Rate limiting — limit message rate per connection to prevent DoS; (6) Message size limits — enforce maximum message size to prevent memory exhaustion; (7) DoS protection — limit the number of open connections per IP; (8) Avoid broadcasting sensitive data — validate that the recipient is authorized to receive each message; (9) CSRF — WebSockets are not susceptible to traditional CSRF (cookies are sent but the server validates Origin), but token-based auth eliminates any ambiguity.

Open this question on its own page
13

How does message ordering work in WebSockets?

WebSocket guarantees in-order message delivery over a single connection — messages sent by one party arrive at the other in the exact order they were sent. This is because WebSocket runs over TCP, which guarantees ordered delivery. However, ordering guarantees break in several scenarios: (1) Multiple connections — a user with multiple browser tabs has separate connections; messages from different tabs may interleave on the server; (2) Reconnection — after a disconnect, messages sent during the gap are lost (unless queued); new messages after reconnection arrive, but there's a gap; (3) Multi-server — in a horizontally scaled setup, messages from different server instances broadcast via Redis may arrive in a different order than sent due to network timing. For strict ordering in distributed systems, use sequence numbers or vector clocks to detect and handle out-of-order delivery.

Open this question on its own page
14

What is backpressure in WebSocket communication?

Backpressure occurs when the sender produces data faster than the receiver can process it, causing memory buildup. In WebSocket, the ws.bufferedAmount property (client-side) shows how many bytes are queued in the browser's send buffer but not yet transmitted. If you call ws.send() faster than the network can carry the data, bufferedAmount grows unboundedly, eventually crashing the browser tab. The solution: implement flow control by checking bufferedAmount before sending — if (ws.bufferedAmount < THRESHOLD) ws.send(data). On the server side (Node.js), the ws.send() callback and the drain event on the underlying socket signal when buffered data has been sent. For high-throughput scenarios (video streaming, game state), implement a producer-consumer pattern where the producer pauses when the buffer is full.

Open this question on its own page
15

How do you test WebSocket applications?

WebSocket testing operates at multiple levels: (1) Unit testing server handlers — test event handler functions in isolation by mocking the socket object; (2) Integration testing — use the ws library as a test client to send messages and assert responses: const client = new WebSocket('ws://localhost:8080'); client.on('message', msg => expect(JSON.parse(msg)).toEqual(expected)); (3) Socket.IO testing — use socket.io-client in Jest tests with the server running on a dynamic port; (4) Load testing — tools like Artillery (ws engine), k6 (native WebSocket support), and Gatling simulate thousands of concurrent WebSocket connections; (5) Manual testing — tools like Postman, Insomnia, and browser DevTools (Network tab → WS filter) allow manual WebSocket inspection; (6) End-to-end — Playwright and Cypress support WebSocket interception for E2E tests.

Open this question on its own page
16

How do WebSockets interact with firewalls and proxies?

WebSockets use the standard HTTP/HTTPS ports (80/443) for the initial handshake and upgrade, which generally passes through most firewalls. However, several proxy-related issues exist: (1) HTTP proxies — many corporate transparent proxies don't understand the Upgrade mechanism and close the connection after the handshake. Solution: use wss:// (encrypted traffic bypasses proxy inspection in most cases); (2) Long-lived connections — proxies and load balancers often have idle connection timeouts (60s–5min). Solution: implement WebSocket ping/pong heartbeat to keep connections alive; (3) NGINX configuration — requires explicit proxy_http_version 1.1, proxy_set_header Upgrade $http_upgrade, and proxy_set_header Connection upgrade settings; (4) AWS ALB — natively supports WebSocket without special configuration when using HTTP/HTTPS listeners; (5) Cloudflare — supports WebSocket on all plans (previously paid only).

Open this question on its own page
17

What is STOMP protocol and how is it used with WebSockets?

STOMP (Simple Text Oriented Messaging Protocol) is a simple, interoperable protocol originally designed for message brokers (like ActiveMQ, RabbitMQ). It defines a frame-based messaging protocol with commands like CONNECT, SUBSCRIBE, SEND, and DISCONNECT. When used over WebSockets, STOMP adds a structured messaging layer on top of the raw WebSocket transport, enabling integration with enterprise message brokers. A Spring Boot application with spring-websocket and spring-messaging naturally speaks STOMP over WebSocket — the client subscribes to topics (/topic/updates) and the server broadcasts messages to those topics. The SockJS client library (often paired with STOMP) provides WebSocket with HTTP fallbacks. This stack is popular in Java enterprise applications that need real-time features integrated with existing messaging infrastructure.

Open this question on its own page
18

What is the maximum message size for WebSockets?

The WebSocket protocol does not define a hard maximum message size — frame payload lengths can theoretically be up to 2^63 bytes (64-bit payload length field). However, practical limits are imposed at multiple levels: (1) Server library limits — the Node.js ws library defaults to 100MB (maxPayload option); (2) Browser limits — browsers typically reject messages over 100MB; (3) Proxy/load balancer limits — NGINX has configurable buffer sizes; (4) Memory limits — processing a very large message requires holding it in memory, risking OOM crashes. In practice, WebSocket is designed for many small, frequent messages — it's not the right tool for large file transfers. For files, use HTTP multipart upload. For large data streams, use binary chunking: split large data into fixed-size frames and reassemble on the receiving end using the FIN bit.

Open this question on its own page
19

How do you monitor and debug WebSocket connections?

WebSocket monitoring and debugging uses several tools: (1) Browser DevTools — Chrome/Firefox DevTools Network tab, filter by "WS", shows connection status, all sent/received frames with timestamps and sizes, enabling message-level debugging; (2) Wireshark — for low-level TCP/WebSocket frame inspection, especially useful for debugging protocol-level issues with custom subprotocols; (3) Server-side logging — log connection events (open, close, error), message receipt, and client identifiers; (4) APM tools — New Relic, Datadog, and Dynatrace provide WebSocket connection tracking and error rates in production; (5) Custom metrics — track connections per second, active connections, messages/second, average message size, and close code distribution using Prometheus + Grafana; (6) Socket.IO Admin UI — an official dashboard showing all connected sockets, rooms, and namespaces with the ability to disconnect clients and emit events.

Open this question on its own page
Advanced 10 questions

Deep expertise questions for senior and lead roles.

01

How do you scale WebSocket servers horizontally?

Horizontal scaling of WebSocket servers requires solving the state distribution problem — connections are stateful and tied to specific server instances. The architecture: (1) Sticky sessions at the load balancer ensure the same client always reaches the same server (NGINX ip_hash, AWS ALB cookie stickiness); (2) Shared pub/sub via Redis — Socket.IO Redis adapter or custom Redis Pub/Sub allows any server to broadcast to clients on any other server; (3) Shared session state — store authentication and user data in Redis so any server can validate connections; (4) Connection limits per node — a single Node.js process handles ~10K-100K concurrent connections depending on memory and message frequency; use Node.js cluster module or PM2 to utilize all CPU cores; (5) Horizontal Pod Autoscaler in Kubernetes with sticky sessions via NGINX Ingress; (6) Dedicated WebSocket gateway (separate from stateless REST API) that scales independently based on connection count metrics.

Open this question on its own page
02

What is the difference between WebSockets and WebRTC?

WebSockets and WebRTC are fundamentally different communication technologies. WebSockets use a client-server model over TCP — all communication routes through a server, which acts as relay. WebRTC enables direct peer-to-peer communication between browsers (or native apps) — once a P2P connection is established via a signaling server, data travels directly between clients without a server intermediary. Key differences: (1) Latency — WebRTC P2P is often lower latency (no server hop) and uses UDP for real-time media; (2) Use cases — WebRTC is designed for audio/video streaming and high-frequency data; WebSockets for text messaging and event distribution; (3) Complexity — WebRTC requires ICE/STUN/TURN infrastructure for NAT traversal, SDP offer/answer negotiation; WebSocket is much simpler; (4) Browser support — both have wide support, but WebRTC implementation varies across browsers. WebSockets handle the WebRTC signaling channel (offer/answer exchange) in many implementations.

Open this question on its own page
03

How do you implement end-to-end encryption over WebSockets?

wss:// provides transport-layer encryption (TLS) — data is encrypted between client and server, but the server can see message content. End-to-end encryption (E2EE) encrypts messages so only the intended recipient can decrypt them — not even the server. Implementation: (1) Key exchange — use the Web Crypto API's ECDH to perform Diffie-Hellman key exchange between clients (mediated by the server but without the server learning the shared secret); (2) Encryption — use AES-GCM (authenticated encryption) with the shared key to encrypt message payloads before sending; (3) Server as relay — the server only sees opaque encrypted blobs and routes them without being able to read content; (4) Key management — handle key storage (IndexedDB), key rotation, and multi-device sync. Libraries like libsodium-wrappers (JavaScript port of libsodium) simplify the cryptographic operations. Signal Protocol (used by WhatsApp, Signal) adds forward secrecy with double ratchet algorithm.

Open this question on its own page
04

What is the actor model and how does it apply to real-time systems?

The actor model is a mathematical model of concurrent computation where the fundamental unit is an actor — an independent entity with its own state that communicates exclusively via asynchronous message passing. Actors don't share memory, eliminating concurrency bugs like race conditions and deadlocks. Application to real-time WebSocket systems: each WebSocket connection can be modeled as an actor that processes messages sequentially in its own mailbox. Frameworks like Akka (JVM) and Elixir/Phoenix use the actor model natively. Phoenix Channels (Elixir) run each channel on a lightweight process (BEAM actor), enabling millions of concurrent WebSocket connections per server — the "2 million websocket connections" demo used this architecture. The actor model also naturally handles fault isolation: one crashed actor doesn't affect others, and supervisors can restart failed actors automatically. Orleans (.NET) and Proto.Actor bring this model to other ecosystems.

Open this question on its own page
05

How do you handle WebSocket connections in a Kubernetes environment?

Running WebSocket servers in Kubernetes (K8s) introduces specific challenges. (1) Sticky sessions — use NGINX Ingress with nginx.ingress.kubernetes.io/affinity: "cookie" annotation to ensure WebSocket clients reconnect to the same pod; (2) Pod restarts — K8s rolling updates terminate pods; clients must detect disconnection and reconnect to a new pod. Configure terminationGracePeriodSeconds generously (60-300s) to allow graceful connection draining; (3) HPA scaling — standard CPU/memory-based HPA doesn't work well for WebSocket workloads; use custom metrics (active connections per pod) with KEDA (Kubernetes Event Driven Autoscaling); (4) Service mesh — Istio and Linkerd support WebSocket with circuit breaking and observability via Envoy sidecar; (5) Redis adapter — mandatory for cross-pod communication; use Redis Sentinel or Redis Cluster for high availability; (6) Health checks — liveness probes must not close WebSocket connections; use a separate HTTP endpoint for health checks.

Open this question on its own page
06

What is CRDT (Conflict-free Replicated Data Type) and how does it apply to real-time collaboration?

CRDTs are data structures designed to be replicated across multiple nodes where updates can be made concurrently without coordination, and all replicas eventually converge to the same state — without requiring a central authority to resolve conflicts. Types: G-Counter (grow-only counter), LWW-Register (last-write-wins), RGA/LSEQ (ordered lists for collaborative text editing). In real-time collaborative applications (Google Docs, Figma, Notion), CRDTs enable offline editing — users can edit without a server connection, and changes merge deterministically when they reconnect. The Yjs library implements CRDT-based shared data types (Y.Text, Y.Map, Y.Array) and integrates with WebSocket providers (y-websocket) to sync state across clients. Unlike Operational Transformation (OT, used by Google Docs's older system), CRDTs don't require a central server to transform operations — all replicas can merge directly. Automerge is another popular CRDT library.

Open this question on its own page
07

How do you implement rate limiting for WebSocket connections?

WebSocket rate limiting must occur at two levels: connection rate (new handshakes per IP/time) and message rate (messages per connection/time). (1) Connection rate limiting at the reverse proxy: NGINX limit_req_zone limits WebSocket upgrade requests per IP; (2) Message rate limiting on the server: implement a token bucket or sliding window algorithm per connection. In Node.js: const rateLimiter = new Map(); ws.on('message', () => { const now = Date.now(); const bucket = rateLimiter.get(ws); if (now - bucket.lastReset > 1000) { bucket.count = 0; bucket.lastReset = now; } if (++bucket.count > MAX_PER_SECOND) { ws.close(1008, 'Rate limit exceeded'); } }); (3) Distributed rate limiting — use Redis with sliding window counters (INCR user:rate:userid with TTL) to share rate limit state across multiple server instances; (4) Backpressure signaling — instead of closing connections, send a rate-limit message and temporarily pause processing to allow legitimate clients to recover.

Open this question on its own page
08

What are the memory implications of maintaining many WebSocket connections?

Each WebSocket connection consumes memory for: (1) TCP socket buffers — typically 4–8KB send + 4–8KB receive kernel buffer per connection (configurable via net.core.rmem_default); (2) Application-level state — user session data, room memberships, message queues — this varies wildly by application (1KB–100KB+ per connection); (3) Node.js event emitter — the WebSocket object itself plus the socket event listener overhead (~few KB). A practical guideline: on a 1GB Node.js process with minimal per-connection state, expect ~10K–50K concurrent connections before memory pressure becomes an issue. To maximize connection density: minimize per-connection memory (share room/user data efficiently), avoid storing large buffers per connection, use binary encoding over JSON, set --max-old-space-size appropriately. Monitor with process.memoryUsage() and heap profiler. Alternatively, Elixir/BEAM handles millions of lightweight processes (actors) because each process has a much smaller overhead (~1–2KB) than a Node.js connection object.

Open this question on its own page
09

How do you implement a distributed WebSocket system with message ordering guarantees?

Guaranteeing message order in a distributed WebSocket system is complex because messages can arrive from multiple server instances via Redis pub/sub with network delays. Architecture: (1) Monotonic sequence numbers — a central or distributed counter (Redis INCR) assigns incrementing sequence numbers to messages in each conversation/channel; (2) Client-side reordering buffer — clients buffer received messages and deliver them in order using the sequence number, waiting up to a configurable timeout for missing messages; (3) Server-side ordering — route all messages for a conversation through a single actor/worker (sharded by conversation ID) to ensure in-order processing before broadcasting; (4) Kafka as message bus — replace Redis pub/sub with Apache Kafka partitioned by conversation ID. Within a partition, Kafka guarantees order. Each WebSocket server instance consumes from partitions corresponding to its connected clients; (5) Event sourcing — store events in an ordered append-only log; clients subscribe from a specific offset, ensuring they never miss or reorder events.

Open this question on its own page
10

What is the Phoenix Framework's approach to real-time communication with channels?

Phoenix Channels (Elixir) represent the state-of-the-art in real-time WebSocket architecture. Built on the BEAM virtual machine, Phoenix leverages Erlang's battle-tested concurrency model where each channel subscription runs as a separate lightweight process (1–2KB overhead). The architecture: (1) Channel modules — each topic (e.g., room:lobby) maps to a channel module with join/3, handle_in/3, and handle_out/3 callbacks; (2) PubSub — the built-in Phoenix.PubSub broadcasts across all nodes in a cluster via Erlang's distributed messaging (no Redis needed for Elixir clusters); (3) PresencePhoenix.Presence uses CRDTs to track online users across cluster nodes with automatic conflict resolution; (4) Scale — the 2 million concurrent WebSocket connections on a single server benchmark (Gary Rennie, 2015) used Phoenix Channels. This was possible because BEAM processes are far lighter than OS threads. Phoenix's approach demonstrates that language/runtime choice is often more impactful than application architecture for WebSocket scalability.

Open this question on its own page
Back to All Topics 49 questions total