Server-Sent Events and JavaScript EventSource
Server-Sent Events (SSE) enable a web server to push real-time data
updates to a client over a standard, long-lived HTTP connection. This
article explains the fundamentals of Server-Sent Events, how the
underlying communication protocol works, and how to use the native
JavaScript EventSource API to establish a connection,
handle incoming data streams, manage custom event types, and handle
connection errors.
What Are Server-Sent Events?
Server-Sent Events (SSE) is a standardized web technology defined under HTML5 that allows servers to stream real-time text data to web browsers asynchronously. Unlike traditional polling, where the client repeatedly asks the server for new information, SSE establishes a persistent connection where the server pushes updates automatically whenever new data is available.
SSE provides unidirectional (one-way) communication from the server to the client. This makes it a lightweight alternative to WebSockets for use cases that only require incoming updates, such as live sports scores, stock tickers, system monitoring dashboards, news feeds, and social media notifications.
How Server-Sent Events Work
SSE operates over standard HTTP or HTTP/2 transport. To start an SSE stream, the server responds to an incoming HTTP GET request with specific headers:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
The payload is sent as plain text formatted into fields separated by
newlines. A double newline (\n\n) marks the end of a single
event message.
A typical stream message can contain the following fields:
data: The message payload. Multiple consecutivedata:lines are concatenated with a newline.event: A custom event name that the client can listen to specifically.id: A unique identifier for the event. If the connection drops, the browser automatically sends this ID via theLast-Event-IDheader upon reconnecting to resume the stream.retry: The time in milliseconds the browser should wait before attempting to reconnect if the connection drops.
Example Server Payload
id: 1
event: priceUpdate
data: {"symbol": "AAPL", "price": 185.50}
id: 2
data: This is a standard unnamed message.
Consuming SSE in JavaScript with EventSource
Browsers provide a built-in EventSource interface that
manages the SSE connection lifecycle, including automatic reconnections
and event parsing.
1. Opening a Connection
To open an SSE connection, instantiate the EventSource
class with the target server URL:
const eventSource = new EventSource('/api/stream');If your endpoint requires authentication cookies or credentials across domains, pass a configuration object:
const eventSource = new EventSource('https://api.example.com/stream', {
withCredentials: true
});2. Listening for Messages
To handle default messages (messages sent without a specific
event: field), use the onmessage event
handler:
eventSource.onmessage = (event) => {
console.log('New message received:', event.data);
// Parse JSON if the server sends serialized data
try {
const parsedData = JSON.parse(event.data);
console.log('Parsed data:', parsedData);
} catch (err) {
console.log('Raw text:', event.data);
}
};3. Listening for Named Custom Events
When the server specifies an event: name, you must
attach an event listener matching that specific event name:
eventSource.addEventListener('priceUpdate', (event) => {
const stock = JSON.parse(event.data);
console.log(`Stock: ${stock.symbol}, New Price: ${stock.price}`);
});4. Handling Connection Lifecycle and Errors
EventSource provides onopen and
onerror handlers to monitor connection status:
eventSource.onopen = () => {
console.log('SSE connection successfully established.');
};
eventSource.onerror = (error) => {
if (eventSource.readyState === EventSource.CONNECTING) {
console.log('Connection lost. Attempting to reconnect...');
} else if (eventSource.readyState === EventSource.CLOSED) {
console.error('Connection closed permanently.', error);
}
};5. Closing the Connection
When data is no longer needed, close the connection to free up server and network resources:
eventSource.close();
console.log('SSE connection closed by the client.');Key Advantages of Using SSE
- Built-in Reconnection: The browser automatically
attempts to reconnect if the connection drops, sending the
Last-Event-IDheader to resume data streams without duplicate processing. - Simple Transport: Because it uses standard HTTP, SSE works seamlessly through corporate proxies, firewalls, and existing load balancers without requiring protocol upgrades.
- Low Overhead: SSE uses plain text over existing HTTP connections, requiring significantly less overhead and configuration than WebSockets for unidirectional workflows.