Server-Sent Events in JavaScript Using EventSource

The EventSource interface is a built-in browser API that enables web applications to receive real-time, unidirectional data streams from a server over a standard HTTP connection using Server-Sent Events (SSE). Unlike WebSockets, which are bidirectional, EventSource is designed specifically for scenarios where the client only needs to listen for continuous updates from the server, such as live score updates, stock tickers, or notifications. This article explains how EventSource works, how to initialize and handle SSE connections in JavaScript, and how to manage stream events effectively.

What is Server-Sent Events (SSE)?

Server-Sent Events allow a server to push data to a web client asynchronously once an initial connection is established. It runs over standard HTTP or HTTPS, utilizing the text/event-stream MIME type. Because it operates over standard HTTP, SSE works natively with HTTP/2 and existing network infrastructure, including firewalls and load balancers, without requiring specialized protocols.

Initializing the EventSource Connection

To initiate an SSE connection in JavaScript, instantiate the EventSource object by passing the target server endpoint URL:

const eventSource = new EventSource('/api/stream-endpoint');

If the connection requires credentials such as cookies or authorization headers in cross-origin requests, you can provide an options object:

const eventSource = new EventSource('https://example.com/api/stream', {
  withCredentials: true
});

Once instantiated, the browser opens a persistent HTTP connection to the server and begins listening for incoming data.

Listening for Stream Events

The EventSource interface provides built-in event handlers to manage connection states and receive incoming messages.

1. The onopen Event

Fired when the connection to the server is successfully established.

eventSource.onopen = (event) => {
  console.log('SSE connection successfully opened.');
};

2. The onmessage Event

Fired when the server sends a generic, unnamed message (messages without a custom event field).

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('New message received:', data);
};

3. Custom Named Events

Servers can send custom event types. To handle these, use standard addEventListener calls matching the event name defined by the server.

eventSource.addEventListener('priceUpdate', (event) => {
  const priceData = JSON.parse(event.data);
  console.log('Custom event (priceUpdate):', priceData);
});

4. The onerror Event

Fired when a network error occurs or the connection is lost.

eventSource.onerror = (error) => {
  if (eventSource.readyState === EventSource.CLOSED) {
    console.log('Connection was closed.');
  } else {
    console.error('An error occurred with the stream:', error);
  }
};

Server-Side Data Format

For EventSource to interpret messages correctly, the server must format its HTTP response body as plain text conforming to the SSE specification:

Example server response payload:

event: priceUpdate
id: 101
data: {"symbol": "AAPL", "price": 175.50}

Connection Management and Auto-Reconnection

EventSource provides automatic reconnection out of the box:

// Terminate the connection
eventSource.close();
console.log('Connection permanently closed.');