Sse Auto Reconnect
title: "SSE Auto-Reconnection" description: "Learn how Server-Sent Events handle automatic reconnection, configure retry intervals, and implement custom reconnection strategies." weight: 19 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "sse"]
One of SSE's greatest features is built-in automatic reconnection. When a connection drops, the browser automatically attempts to reconnect. Understanding and configuring this behavior is essential for reliable real-time applications.
## What You'll Learn
- Default reconnection behavior
- The retry field
- Last-Event-ID for state recovery
- Custom reconnection strategies
- Detecting reconnection events
## Why It Matters
Automatic reconnection ensures your application recovers from network interruptions without user intervention. Proper configuration prevents unnecessary reconnection attempts and enables seamless data recovery.
## Real-World Use
A live news ticker uses SSE with a 5-second retry interval. When a reader's network briefly drops, the ticker automatically reconnects and resumes streaming headlines without any visible interruption.
## Flow Chart
```mermaid
sequenceDiagram
participant C as Browser
participant S as Server
C->>S: GET /events
S-->>C: Stream data
Note over C,S: Connection Drops
C->>C: Wait 3 seconds (default)
C->>S: GET /events (reconnect)
C->>S: Last-Event-ID: event-42
S-->>C: Resume from event-43
Code Examples
Example 1: Configuring Retry Interval
// Server sends retry interval
const http = require('http');
let eventId = 0;
http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
});
// Set custom reconnection time to 5 seconds
res.write('retry: 5000\n\n');
// Send events with IDs
const interval = setInterval(() => {
eventId++;
res.write(
`id: event-${eventId}\n` +
`data: ${JSON.stringify({ count: eventId, time: Date.now() })}\n` +
'\n'
);
}, 1000);
req.on('close', () => clearInterval(interval));
}).listen(3000);
// Client reads retry value
const source = new EventSource('/events');
source.onmessage = (event) => {
console.log('Received:', event.data);
console.log('Last ID:', event.lastEventId);
};
// Access retry value (not directly available in API)
// The retry is handled automatically by the browser
Expected output: Server sets retry to 5000ms, browser uses this for reconnection timing instead of the default 3000ms.
Example 2: Tracking Reconnection Events
class SSEReconnectManager {
constructor(url) {
this.url = url;
this.retryCount = 0;
this.maxRetries = 10;
this.listeners = new Map();
this.connect();
}
connect() {
this.source = new EventSource(this.url);
this.source._manager = this;
this.source.onopen = () => {
this.retryCount = 0;
this.emit('connected');
};
this.source.onmessage = (event) => {
this.emit('message', event);
};
this.source.onerror = () => {
// EventSource will try to reconnect automatically
this.retryCount++;
this.emit('reconnecting', this.retryCount);
if (this.retryCount >= this.maxRetries) {
this.emit('max-retries', this.maxRetries);
this.source.close();
}
};
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(callback);
}
emit(event, data) {
this.listeners.get(event)?.forEach(cb => cb(data));
}
close() {
this.source.close();
this.emit('disconnected');
}
}
// Usage with UI feedback
const sse = new SSEReconnectManager('/events');
sse.on('connected', () => {
updateConnectionStatus('connected');
hideReconnectBanner();
});
sse.on('reconnecting', (attempt) => {
updateConnectionStatus('reconnecting');
showReconnectBanner(`Reconnecting (attempt ${attempt})...`);
});
sse.on('max-retries', (max) => {
updateConnectionStatus('failed');
showReconnectBanner(`Connection failed after ${max} attempts`);
showManualReconnectButton();
});
sse.on('message', (event) => {
processEvent(JSON.parse(event.data));
});
Expected output: Manager tracks reconnection attempts, provides callbacks for UI updates, and gives up after max retries.
Example 3: Custom Reconnection with Server-State Recovery
// Server that resumes from last event ID
const http = require('http');
const events = [];
let eventId = 0;
// Generate events
setInterval(() => {
eventId++;
const event = {
id: eventId,
data: { id: eventId, value: Math.random(), time: Date.now() },
};
events.push(event);
if (events.length > 1000) events.shift(); // Keep last 1000
}, 1000);
http.createServer((req, res) => {
// Check for Last-Event-ID
const lastEventId = parseInt(req.headers['last-event-id']?.replace('event-', '')) || 0;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
});
// Send missed events first
const missedEvents = events.filter(e => e.id > lastEventId);
missedEvents.forEach(event => {
res.write(
`id: event-${event.id}\n` +
`data: ${JSON.stringify(event.data)}\n` +
'\n'
);
});
// Continue with new events
const interval = setInterval(() => {
eventId++;
const data = { id: eventId, value: Math.random(), time: Date.now() };
res.write(
`id: event-${eventId}\n` +
`data: ${JSON.stringify(data)}\n` +
'\n'
);
}, 1000);
req.on('close', () => clearInterval(interval));
}).listen(3000);
// Client with manual reconnection
function connectWithRecovery() {
const eventSource = new EventSource('/events');
let lastProcessedId = null;
eventSource.onmessage = (event) => {
lastProcessedId = event.lastEventId;
processEvent(JSON.parse(event.data));
};
eventSource.onerror = () => {
eventSource.close();
if (lastProcessedId) {
// Custom reconnect with last ID
const url = `/events?since=${lastProcessedId}`;
const newSource = new EventSource(url);
// Re-bind handlers...
} else {
setTimeout(connectWithRecovery, 3000);
}
};
}
Expected output: Server sends missed events on reconnection based on Last-Event-ID, ensuring no data is lost.
Common Mistakes
| Mistake | Explanation |
|---|---|
| Not setting retry field | Browser default of 3 seconds may be too aggressive for production |
| Ignoring Last-Event-ID | Without IDs, clients receive events from the current time, missing events during disconnect |
| Not limiting reconnection attempts | Infinite reconnection attempts waste bandwidth; set a maximum |
| Forgetting to clean up on max retries | Show a meaningful UI state when reconnection finally fails |
| Confusing retry with self-reconnect | The retry: field is server-controlled; the browser handles reconnection timing automatically |
Practice Questions
- What is the default reconnection time for EventSource?
- How does the server control reconnection timing?
- How does Last-Event-ID help with data recovery?
- How do you detect reconnection attempts in the client?
- When should you stop trying to reconnect?
Challenge
Build an SSE application with a robust reconnection strategy: exponential backoff starting at 1 second, max 30-second delay, max 20 attempts, data recovery using Last-Event-ID, and a UI that shows connection status with reconnection countdown.
FAQ
Mini Project
Build an SSE connection monitor widget that displays connection status, retry count, last event timestamp, and a manual reconnection button. Include a server that supports event recovery via Last-Event-ID.
What's Next
Learn about the Last-Event-ID header in SSE
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro