Building Real-Time APIs: WebSockets vs SSE vs Long Polling
Building Real-Time APIs: WebSockets vs SSE vs Long Polling
Real-time data — live dashboards, chat messages, stock prices, notifications, collaborative editing — requires pushing data from server to client without the client repeatedly asking "anything new?" Three patterns dominate: WebSockets, Server-Sent Events (SSE), and long polling.
The Three Patterns
WebSockets
What: Full-duplex TCP connection. Both client and server can send messages at any time.
Connection: HTTP upgrade handshake → persistent TCP connection
Client: GET /ws (Upgrade: websocket)
Server: 101 Switching Protocols
─── Full-duplex communication ───
Client → Server: {"type": "subscribe", "channel": "prices"}
Server → Client: {"symbol": "AAPL", "price": 185.50}
Client → Server: {"type": "unsubscribe", "channel": "prices"}
Strengths:
- Bidirectional — client and server both send freely
- Lowest latency — no HTTP overhead per message
- Binary and text support
- Best for high-frequency updates (trading, gaming, chat)
Weaknesses:
- Stateful — each connection must be maintained server-side
- Load balancing is complex (sticky sessions or connection state sharing)
- Reconnection logic is on the client
- No built-in multiplexing (one connection per WebSocket endpoint)
- Proxy/firewall issues in some enterprise environments
- Memory overhead per connection (~2-10KB per connection)
Server-Sent Events (SSE)
What: Unidirectional stream from server to client over HTTP. Client subscribes, server pushes events.
Connection: Standard HTTP request → server keeps connection open, sends events
Client: GET /events (Accept: text/event-stream)
Server: 200 OK (Content-Type: text/event-stream)
─── Server pushes events ───
Server → Client: event: price\ndata: {"symbol": "AAPL", "price": 185.50}\n\n
Server → Client: event: price\ndata: {"symbol": "AAPL", "price": 185.55}\n\n
Strengths:
- Simple — standard HTTP (works through proxies, CDNs, load balancers)
- Auto-reconnection — browser
EventSourceAPI reconnects automatically - Event IDs — server can resume from where client disconnected
- Lightweight — less overhead than WebSocket for server-to-client only
- CDN-cacheable (with proper headers)
Weaknesses:
- Unidirectional only — server to client (client sends via regular HTTP requests)
- Text only (no binary)
- Connection limit — browsers limit to 6 SSE connections per domain (HTTP/1.1)
- No built-in authentication (cookies or URL tokens)
- Less tooling than WebSockets
Long Polling
What: Client makes a request. Server holds it open until data is available or timeout. Client immediately reconnects.
Connection: Repeated HTTP requests
Client: GET /updates?since=123
Server: (waits up to 30 seconds)
Server: 200 OK {"data": [...], "last_id": 456}
Client: GET /updates?since=456
Server: (waits...)
Strengths:
- Works everywhere — standard HTTP, no special protocols
- No firewall/proxy issues
- Simple server implementation (just delay the response)
- Stateless — each request is independent
Weaknesses:
- Higher latency — round-trip per update
- Higher bandwidth — HTTP headers on every request
- Server resource consumption — holding connections open
- Not truly real-time — gaps between polls
- Scaling is inefficient compared to WebSocket/SSE
Comparison Table
| Feature | WebSocket | SSE | Long Polling |
|---|---|---|---|
| Direction | Bidirectional | Server → Client | Server → Client |
| Protocol | WebSocket (TCP) | HTTP | HTTP |
| Latency | Lowest | Low | Medium |
| Reconnection | Manual | Automatic | Manual |
| Binary data | ✅ Yes | ❌ No | ❌ No |
| HTTP/2 multiplexing | ❌ No | ✅ Yes | ✅ Yes |
| CDN-friendly | ❌ No | ✅ Yes | ✅ Yes |
| Proxy-friendly | ⚠️ Sometimes | ✅ Yes | ✅ Yes |
| Browser connections | Unlimited | 6/domain (HTTP/1.1) | 6/domain |
| Server memory | ~2-10KB/conn | ~1-5KB/conn | Minimal |
| Scalability | ⚠️ Stateful | ⚠️ Stateful | ✅ Stateless |
Decision Framework
Choose WebSocket When:
- Bidirectional communication — chat, multiplayer games, collaborative editing
- High-frequency updates — trading platforms, live sports, real-time analytics
- Binary data — file transfer, audio/video streaming
- Client-initiated messages — the client needs to send data frequently
Choose SSE When:
- Server-to-client only — notifications, live feeds, dashboards
- Standard HTTP infrastructure — CDNs, load balancers, proxies
- Auto-reconnection needed — EventSource handles reconnection automatically
- AI/LLM streaming — OpenAI, Anthropic, and most AI APIs use SSE for streaming responses
Choose Long Polling When:
- Maximum compatibility — must work everywhere, including restrictive networks
- Infrequent updates — updates every 30-60 seconds, not milliseconds
- Simple implementation — no WebSocket infrastructure, no SSE support issues
- Stateless architecture — don't want to maintain connection state
Real-World Usage
| Company | Technology | Use Case |
|---|---|---|
| Slack | WebSocket | Real-time messaging |
| Discord | WebSocket | Chat, voice, presence |
| OpenAI | SSE | Streaming LLM responses |
| Anthropic | SSE | Streaming Claude responses |
| GitHub | SSE | Live issue/PR updates |
| Stripe | WebSocket | Dashboard real-time data |
| Twitter/X | SSE | Streaming API |
| Firebase | WebSocket | Realtime Database |
| Vercel | SSE | Build log streaming |
Scaling Considerations
WebSocket Scaling
- Requires sticky sessions (or shared connection state)
- Connection count is limited by server memory and file descriptors
- Use Redis pub/sub or NATS for cross-server message routing
- Consider managed services: Pusher, Ably, Socket.IO
SSE Scaling
- Standard HTTP — works with existing load balancers
- HTTP/2 multiplexes connections (solves 6-connection limit)
- Can be CDN-cached with proper headers
- Easier to scale than WebSockets
When to Use a Managed Service
If you need 10K+ concurrent connections, consider a managed real-time service instead of building your own:
| Service | Strengths |
|---|---|
| Pusher | Simple pub/sub, great SDK |
| Ably | Enterprise, guaranteed ordering |
| Socket.IO | Self-hosted, most popular |
| Supabase Realtime | Postgres changes → clients |
| Firebase Realtime DB | Real-time sync, offline |
Building real-time APIs? Explore Pusher, Ably, and real-time API tools on APIScout — comparisons, guides, and developer resources.