Skip to content

WebSocket vs SSE

1. Decision

Choose Server-Sent Events (SSE) for unidirectional, server-to-client real-time streaming (e.g., live news updates, AI LLM token streaming, sports scores, stock price feeds); choose WebSocket for full-duplex, bidirectional real-time communication (e.g., chat applications, multiplayer games, collaborative canvas editing).


2. 30-Second Answer

Both WebSocket and SSE provide low-latency real-time data streaming over TCP. Server-Sent Events (SSE) is a lightweight, standardized W3C browser protocol operating strictly unidirectionally from server to client over standard HTTP (text/event-stream). SSE leverages standard HTTP infrastructure (HTTP/2 multiplexing, native browser reconnection via EventSource, HTTP status codes, simple firewall traversal). WebSocket provides full-duplex, bidirectional TCP messaging using custom binary/text frame protocols (ws:// / wss://). Choose SSE when clients only need to receive pushed updates (simpler operational footprint); choose WebSocket when clients must send high-frequency messages back to the server over the same socket connection.


3. Decision Matrix

Option Best For Avoid When Latency Scalability Consistency Operational Complexity
SSE (Server-Sent Events) LLM token streaming (ChatGPT response), live news feeds, stock tickers, system monitoring alerts Bidirectional client-server interaction (chat, gaming), binary file streaming Low (<10ms server push over HTTP/2) High (Operates over standard HTTP/2 multiplexed connections) Built-in automatic reconnection & Event ID tracking Low (Standard HTTP text/event-stream)
WebSocket (ws:// / wss://) Bi-directional interactive chat, collaborative editing (Figma), multiplayer games Unidirectional server-to-client streaming, simple static news updates Ultra-Low (<5ms binary frame) Medium to High (Stateful persistent TCP socket cluster requiring Pub/Sub backplane) Custom heartbeat & reconnect logic required Medium to High

4. Selection Rules

Requirement Best Choice Rationale / Example
LLM Token Response Streaming (ChatGPT UI) SSE Server streams text tokens as generated; client makes standard HTTP requests
Interactive Real-Time Chat App WebSocket Client sends messages and receives incoming peer messages over same socket
Native Automatic Browser Reconnection SSE Browser EventSource API automatically reconnects and sends Last-Event-ID header
HTTP/2 Multiplexing Over Single TCP Connection SSE Multiple SSE streams share 1 HTTP/2 TCP connection natively without domain sharding
Binary Data Streaming (Audio/Video Chunks) WebSocket Native support for ArrayBuffer and Blob binary frames (SSE is UTF-8 text only)
Enterprise Corporate Firewall Traversal SSE Operates over standard HTTPS Port 443 without triggering WebSocket proxy blocks

5. Tradeoffs

  1. Unidirectional Simplicity vs Bidirectional Duplex Power
  2. Gain (SSE): Extremely simple server implementation (text/event-stream); no custom framing protocol.
  3. Lose (SSE): Client cannot push messages back over the SSE stream (must issue separate HTTP POST calls).
  4. Standard HTTP/2 Multiplexing vs Custom TCP Socket Management
  5. Gain (SSE): Runs over standard HTTP/2; bypasses HTTP/1.1 6-connection-per-domain browser limit natively.
  6. Lose (SSE): Under HTTP/1.1, consuming multiple SSE connections exhausts browser socket pools without HTTP/2.
  7. Native Auto-Reconnect & Resumption vs Custom Ping/Pong Logic
  8. Gain (SSE): EventSource automatically retries connection and transmits Last-Event-ID for seamless stream resumption.
  9. Lose (WebSocket): Developers must code custom heartbeat ping/pong, reconnect loops, and message buffer queues.
  10. UTF-8 Text Payload vs Binary Framing Support
  11. Gain (WebSocket): Efficient binary framing for raw bytes, audio streams, and Protobuf payloads.
  12. Lose (WebSocket): Requires custom frame parsing libraries.
  13. Infrastructure & Proxy Compatibility
  14. Gain (SSE): Leverages standard HTTP load balancers, API Gateways, and corporate proxies without modification.
  15. Lose (WebSocket): Corporate firewalls or strict proxies may drop Upgrade: websocket headers.

6. Interview Counter Questions

  1. How does the EventSource API in the browser handle automatic reconnection and message recovery via Last-Event-ID?
  2. What is the HTTP/1.1 6-connection limit bug in SSE and how does HTTP/2 solve it?
  3. How do you implement SSE streaming in Node.js / Go backend servers (Content-Type: text/event-stream)?
  4. Why did OpenAI choose SSE over WebSockets for streaming ChatGPT completion responses?
  5. How does load balancing differ between SSE and WebSockets?
  6. Can SSE transport binary data (e.g., images/audio)?
  7. What happens when an Nginx proxy buffers SSE responses, and how do you fix it (X-Accel-Buffering: no)?
  8. How does cross-origin authorization (CORS & Cookies/Headers) differ between SSE and WebSockets?
  9. When would you choose Long Polling over SSE?
  10. How do you scale SSE horizontally across multiple server nodes (Redis Pub/Sub)?

10. Gold Standard Answers

  1. Each SSE event includes an id: 123 tag. If the connection drops, EventSource automatically reconnects and sends HTTP header Last-Event-ID: 123. The server reads this header and replays missed events from that ID offset.
  2. Browsers enforce a max limit of 6 concurrent HTTP/1.1 connections per domain name. Opening 6 SSE tabs blocks all further HTTP requests to that domain. HTTP/2 multiplexes unlimited SSE streams over a single TCP connection, fixing the issue.
  3. Set headers: Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive. Format body: data: {"token": "hello"}\n\n. Flush the response stream immediately after writing each message block.
  4. ChatGPT streaming is strictly unidirectional (server pushing generated LLM tokens to client). SSE utilizes standard HTTP authentication, automatic browser reconnection, zero custom framing, and works natively over HTTP/2 without WebSocket overhead.
  5. Both require long-lived connections. However, SSE uses standard HTTP, allowing standard L7 HTTP load balancers to route initial GET requests easily. WebSockets require proxies to support HTTP Upgrade headers.
  6. Not natively. SSE is strictly UTF-8 text. Binary data must be Base64-encoded, which adds a 33% byte size overhead penalty. Use WebSockets for native binary streaming.
  7. Reverse proxies (Nginx) buffer HTTP responses by default to optimize throughput, holding SSE events in RAM instead of pushing them immediately. Fix by sending header X-Accel-Buffering: no or setting proxy_buffering off; in Nginx config.
  8. SSE uses standard HTTP, so EventSource supports standard CORS, HTTP authorization headers (via fetch or polyfills), and cookies. WebSockets ignore standard CORS after the initial HTTP Upgrade handshake.
  9. Choose Long Polling only for legacy browsers lacking SSE support, or when infrastructure proxies forcibly terminate long-lived HTTP streaming connections every 30 seconds.
  10. Just like WebSockets, use a Redis Pub/Sub backplane. When an event occurs, publish to Redis; each SSE server node consumes the message and writes it to matching local client SSE response streams.

8. Common Mistakes

  • Forgetting to disable response buffering on Nginx (X-Accel-Buffering: no), causing SSE events to freeze until buffer fills.
  • Using SSE over HTTP/1.1 across multiple browser tabs, hitting the 6-connection per domain browser limit.
  • Encoding large binary media files into Base64 over SSE instead of using WebSockets.
  • Using WebSockets for purely unidirectional server-push applications (e.g., live news ticker), adding unnecessary operational complexity.
  • Failing to include \n\n trailing newlines in SSE message payloads, causing the client EventSource to hang waiting for message boundaries.

9. Keywords

SSE, Server-Sent Events, WebSocket, EventSource, Last-Event-ID, text/event-stream, HTTP/2 Multiplexing, Unidirectional, Full-Duplex, ChatGPT Token Streaming, X-Accel-Buffering, Base64 Encoding, Redis Pub/Sub.


10. Cheat Sheet

  • Core Rule: Unidirectional Server-to-Client Stream = SSE; Bidirectional Interactive Communication = WebSocket.
  • Protocols: SSE = Standard HTTP/2 (text/event-stream); WebSocket = Custom TCP protocol (ws://, wss://).
  • Auto-Reconnect: SSE has native browser auto-reconnect + Last-Event-ID message replay built-in.
  • Nginx Fix: Always send X-Accel-Buffering: no for SSE to prevent Nginx from caching event chunks.
  • HTTP/2 Requirement: Always run SSE over HTTP/2 to bypass HTTP/1.1's 6-connection per domain browser limit.
  • Data Format: SSE = UTF-8 Text only (JSON); WebSocket = Text + Native Binary (ArrayBuffer).

11. Related Decisions