Server-Sent Events
Server-Sent Events (SSE) let the server push data to the client over a single HTTP connection. Simpler than WebSocket โ one-directional (server โ client) over standard HTTP.
How SSE Works
Client Server
โ โ
โโโ GET /events โโโโโโโโโโโโโโโถ โ (standard HTTP)
โ โ
โโโโ event: message โโโโโโโโโโโโ
โโโโ data: {"msg":"Hello"} โโโโโ
โโโโ โ
โโโโ event: update โโโโโโโโโโโโโ
โโโโ data: ... โโโโโโโโโโโโโโโโโ
โ โ
โโโโ (connection stays open) โโโ (auto-reconnect)
Basic Usage
const source = new EventSource('/api/events');
source.onmessage = function(event) {
console.log('Received:', event.data);
};
source.onopen = function() {
console.log('Connection opened');
};
source.onerror = function() {
console.error('Connection error');
};
Demo: Server-Sent Events Demo
HTML
<div>
<p>Simulated server sends events at random intervals.</p>
<div style='display:flex;gap:8px;margin-bottom:8px;'>
<button id='sse-start'>Start SSE</button>
<button id='sse-stop' disabled>Stop</button>
</div>
<div style='max-height:180px;overflow-y:auto;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:8px;'>
<div id='sse-messages' style='font-family:monospace;font-size:0.85rem;'></div>
</div>
<pre id='sse-status' style='background:#f1f5f9;padding:8px;border-radius:4px;margin-top:8px;'></pre>
</div> JavaScript
const messages = document.getElementById('sse-messages');
const status = document.getElementById('sse-status');
let eventCount = 0;
let intervalId = null;
document.getElementById('sse-start').onclick = function() {
this.disabled = true;
document.getElementById('sse-stop').disabled = false;
status.textContent = '๐ SSE connected โ waiting for events...';
// Simulate server-sent events
intervalId = setInterval(() => {
eventCount++;
const types = ['update', 'notification', 'alert', 'status'];
const type = types[Math.floor(Math.random() * types.length)];
const data = {
id: eventCount,
type: type,
message: type + ' event #' + eventCount,
timestamp: new Date().toLocaleTimeString()
};
const div = document.createElement('div');
div.textContent = '๐ฉ ' + type + ': ' + data.message;
messages.insertBefore(div, messages.firstChild);
status.textContent = 'โ
Received event #' + eventCount + ' (' + type + ')';
// Limit messages shown
while (messages.children.length > 20) {
messages.removeChild(messages.lastChild);
}
}, 1000 + Math.random() * 3000);
};
document.getElementById('sse-stop').onclick = function() {
clearInterval(intervalId);
intervalId = null;
this.disabled = true;
document.getElementById('sse-start').disabled = false;
status.textContent = 'โน๏ธ SSE disconnected (' + eventCount + ' events received)';
}; Live Output Window
Server Format
The server sends a special text format:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Data lines:
data: {"message": "Hello"}\n\n
event: update\ndata: {"id": 1}\n\n
event: custom\ndata: line1\ndata: line2\n\n
id: 42\ndata: message\n\n
retry: 5000\n\n
Event Fields
| Field | Description |
|---|---|
data: | The message payload (can be multiple lines) |
event: | Custom event type (defaults to message) |
id: | Last event ID (for reconnection resume) |
retry: | Reconnection time in milliseconds |
Listening to Named Events
const source = new EventSource('/events');
source.addEventListener('userConnected', function(event) {
console.log('User connected:', event.data);
});
source.addEventListener('newMessage', function(event) {
console.log('New message:', JSON.parse(event.data));
});
// Default listener for unnamed events
source.onmessage = function(event) {
console.log('Generic event:', event.data);
};
The server sends:
event: userConnected
data: {"userId": 42}
event: newMessage
data: {"text": "Hello"}
SSE vs WebSocket
| Feature | SSE | WebSocket |
|---|---|---|
| Direction | Server โ Client only | Bidirectional |
| Protocol | HTTP | WebSocket |
| Auto-reconnect | โ Built-in | โ Manual |
| Binary data | โ Text only | โ Both |
| Browser support | Most modern | All modern |
| Simplicity | Very simple | Moderate |
| Max connections | 6 per browser | Unlimited |
Auto-Reconnection
SSE automatically reconnects when the connection drops. If the server sends an id field, the browser sends Last-Event-ID header on reconnect:
// Browser sends:
// GET /events
// Last-Event-ID: 42
// Server can resume from event 43
Connection Management
// Close connection
source.close();
// Check state
source.readyState // 0=CONNECTING, 1=OPEN, 2=CLOSED
Practical: Live Notifications
SSE is ideal for:
- Live notifications (new messages, friend requests)
- Stock tickers (price updates)
- News feeds (new articles)
- Log streaming (server logs in real-time)
- Progress updates (build/deploy status)
Key Takeaways
- SSE is server โ client only โ simpler than WebSocket for push notifications
- Use
new EventSource(url)to connect - Listen with
onmessagefor generic events,addEventListenerfor named events - Auto-reconnects built-in โ includes
Last-Event-IDfor resume - Server format is
text/event-streamwithdata:,event:,id:,retry:fields - SSE works over standard HTTP โ no special server required
- Use WebSocket when you need bidirectional communication; use SSE for server push