Server-Sent Events vs WebSockets: Choosing Real-Time Communication
The Need for Real-Time Communication
Traditional HTTP follows a request-response model: the client asks, the server answers. But modern web applications need real-time updates — live dashboards, chat messages, notifications, stock tickers, monitoring alerts. Two technologies solve this: Server-Sent Events (SSE) and WebSockets. Choosing the right one depends on your use case.
Server-Sent Events (SSE)
SSE is a simple, HTTP-based protocol for streaming updates from server to client. The client opens a standard HTTP connection, and the server sends events as they occur. The connection stays open, and the browser automatically reconnects if it drops.
// Client: JavaScript EventSource API
const source = new EventSource('/api/events');
source.onmessage = (event) => {
const data = JSON.parse(event.data);
updateDashboard(data);
};
source.onerror = (error) => {
console.log('SSE connection error, reconnecting...');
};
// Listen for specific event types
source.addEventListener('alert', (event) => {
showNotification(JSON.parse(event.data));
});
// Server: PHP SSE endpoint
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no'); // Disable nginx buffering
while (true) {
$data = getLatestUpdates();
if ($data) {
echo "event: update\n";
echo "data: " . json_encode($data) . "\n\n";
}
ob_flush();
flush();
sleep(1);
}
SSE features:
- Unidirectional — server to client only. Client sends data via regular HTTP requests
- Automatic reconnection — the browser handles reconnection with configurable retry intervals
- Event IDs — the server can assign IDs to events; on reconnection, the browser sends the last ID so the server can resume from where it left off
- Text-based — events are UTF-8 text (typically JSON). No binary support
- Standard HTTP — works through proxies, load balancers, CDNs, and firewalls without special configuration
WebSockets
WebSockets provide full-duplex communication over a single TCP connection. After an HTTP upgrade handshake, both client and server can send messages at any time. The protocol supports both text and binary data.
// Client: WebSocket API
const ws = new WebSocket('wss://example.com/ws');
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', channel: 'alerts' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
handleMessage(data);
};
ws.onclose = (event) => {
console.log('WebSocket closed:', event.code, event.reason);
// Manual reconnection needed
setTimeout(() => reconnect(), 3000);
};
// Server: Node.js WebSocket (ws library)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
const data = JSON.parse(message);
if (data.type === 'subscribe') {
subscribeToChannel(ws, data.channel);
}
});
// Send updates
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping', time: Date.now() }));
}
}, 30000);
});
WebSocket features:
- Bidirectional — both client and server can send messages independently
- Binary support — transmit binary data (images, files, protocol buffers) efficiently
- Low overhead — after the handshake, frames have only 2–14 bytes of overhead (vs HTTP headers on every request)
- No automatic reconnection — you must implement reconnection logic yourself
- Custom protocol — requires WebSocket-aware proxies and load balancers
Comparison
| Feature | SSE | WebSockets |
|---|---|---|
| Direction | Server → Client | Bidirectional |
| Protocol | HTTP/1.1, HTTP/2 | WS/WSS (upgrade from HTTP) |
| Data format | Text (UTF-8) | Text + Binary |
| Reconnection | Automatic (built-in) | Manual |
| Browser support | All modern (no IE) | All modern (including IE 10+) |
| Max connections | 6 per domain (HTTP/1.1) | No HTTP limit |
| Proxy/CDN support | Excellent (standard HTTP) | Requires configuration |
| Complexity | Simple | More complex |
| Scalability | Easier (stateless HTTP) | Harder (stateful connections) |
When to Use SSE
- Monitoring dashboards — server pushes metrics, status updates, and alerts to the browser. Enterno.io uses similar patterns for real-time uptime monitoring displays
- News feeds and notifications — server pushes new items as they arrive
- Progress updates — long-running tasks (report generation, file processing) send progress percentages
- Live logs — stream log entries to a web-based log viewer
- Stock tickers / sports scores — server-originated data that clients display
When to Use WebSockets
- Chat applications — both users send messages simultaneously
- Collaborative editing — Google Docs-style real-time co-editing
- Online gaming — low-latency bidirectional communication with binary data
- Trading platforms — rapid bidirectional order placement and market data
- Video/audio signaling — WebRTC signaling requires bidirectional messaging
Performance Considerations
- Connection limits — HTTP/1.1 limits browsers to 6 connections per domain. SSE consumes one of these slots. HTTP/2 multiplexes streams, effectively removing this limit
- Memory usage — each WebSocket connection holds state on the server. 10,000 concurrent users = 10,000 stateful connections. SSE over HTTP/2 is more memory-efficient
- Load balancing — WebSocket connections are sticky — they must route to the same backend server. This complicates scaling. SSE connections are simpler to load-balance
- Compression — SSE benefits from standard HTTP compression (gzip/Brotli). WebSocket compression (permessage-deflate) adds CPU overhead
Implementation Tips
- For SSE, disable buffering in nginx (
X-Accel-Buffering: no) and proxy settings (proxy_buffering off) - For WebSockets, configure your reverse proxy to support the Upgrade header and increase timeouts
- Both need heartbeat/Ping mechanisms to detect dead connections. SSE can use comment lines (
: ping), WebSockets have built-in ping/pong frames - Consider using a message broker (Redis Pub/Sub, Kafka) to distribute events across multiple server instances
- For PHP applications, SSE is simpler because it uses standard HTTP. WebSockets typically require a separate server process (Node.js, Go, or a PHP extension like Swoole)
Conclusion
SSE and WebSockets serve different needs. SSE is the right choice for server-to-client streaming — it is simpler, works with standard HTTP infrastructure, and handles reconnection automatically. WebSockets are necessary when you need bidirectional communication or binary data. For most web monitoring and notification use cases, SSE is the pragmatic choice. Use WebSockets when bidirectional communication is a genuine requirement, not just a perceived one.
Check your website right now
Check now →