Skip to content

Sse Auto Reconnect

DodaTech 5 min read

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

  1. What is the default reconnection time for EventSource?
  2. How does the server control reconnection timing?
  3. How does Last-Event-ID help with data recovery?
  4. How do you detect reconnection attempts in the client?
  5. 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

Does EventSource automatically reconnect?

Yes, EventSource automatically reconnects when the connection drops. You do not need to implement reconnection logic.

How long does EventSource wait before reconnecting?

The default is 3 seconds. Override with the retry: field in the server response, specified in milliseconds.

Does EventSource send headers during reconnection?

Yes, EventSource automatically sends the Last-Event-ID header with the last received event ID on reconnection.

What happens during browser offline mode?

EventSource detects the offline state and will not attempt to reconnect until the browser comes back online.

Can I disable automatic reconnection?

No, EventSource always reconnects. If you want manual control, close the connection and create a new EventSource manually.

Does reconnection affect performance?

Reconnection creates a new HTTP request. Frequent reconnections (every few seconds) can impact server performance under load.

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