Server-Sent Events (SSE)
Server-Sent Events (SSE) is a server push technology built on HTTP that allows a server to stream a sequence of events to a client over a single, long-lived HTTP connection. Once the connection is established, the server can push data to the client at any time without the client needing to poll.
SSE is a W3C standard, natively supported in all modern browsers through the EventSource API. Unlike WebSockets, which are bidirectional, SSE is unidirectional: data flows only from server to client.
How SSE works
The client opens a connection by making a regular HTTP GET request with the Accept: text/event-stream header. The server responds with Content-Type: text/event-stream and keeps the connection open, writing events to the response body as they occur.
Each event is a block of plain-text lines terminated by a blank line:
data: Hello, world!\n \n
A complete event with optional fields looks like:
id: 42\n
event: price-update\n
data: {"symbol":"AAPL","price":172.34}\n
\n
| Field | Meaning |
|---|---|
|
The payload of the event. Multi-line payloads use multiple |
|
An optional event type. The client can listen for specific event types. Defaults to |
|
An optional event ID. The browser stores the last received ID and sends it as |
|
An optional reconnection delay in milliseconds. The browser uses this value when it reconnects after a dropped connection. |
Browser API
The browser EventSource API is simple:
const source = new EventSource('/events');
// Listen for the default "message" event type.
source.addEventListener('message', (event) => {
console.log(event.data);
});
// Listen for a custom event type.
source.addEventListener('price-update', (event) => {
const { symbol, price } = JSON.parse(event.data);
console.log(`${symbol}: ${price}`);
});
source.addEventListener('error', () => {
source.close();
});
The browser automatically reconnects after a dropped connection, sending the Last-Event-ID header so the server can resume the stream from the last acknowledged event.
Automatic reconnection
Automatic reconnection is built into the SSE specification. When the connection drops (network error, server restart), the browser waits for the reconnection delay (default 3 seconds, configurable via the retry field) and reopens the connection. If the server tracks event IDs persistently (e.g. in a database or message queue), it can use the Last-Event-ID to replay missed events, providing at-least-once delivery semantics.
Comparison with WebSockets and long polling
| Aspect | SSE | WebSockets | Long polling |
|---|---|---|---|
Direction |
One-way (server → client) |
Two-way (full-duplex) |
Simulated server push via repeated client requests |
Protocol |
Plain HTTP |
WebSocket protocol (upgraded from HTTP) |
Plain HTTP |
Browser support |
Native |
Native |
|
Automatic reconnection |
Yes — built into the spec |
No — must be implemented manually |
Implicit (client re-polls) |
HTTP/2 support |
Yes — HTTP/2 multiplexing removes the 6-connection-per-host limit |
Not applicable (WebSocket upgrade bypasses HTTP/2) |
Yes |
Overhead per message |
Low — plain text, no framing overhead |
Low — WebSocket frames are small |
High — full HTTP request/response headers for each message |
Proxies and firewalls |
Generally transparent — uses standard HTTP |
Some corporate proxies block WebSocket upgrades |
Generally transparent |
Use case fit |
Server-to-client push; news feeds, dashboards, notifications |
Interactive bidirectional: chat, games, collaborative editing |
Fallback for environments where SSE or WebSocket is unavailable |
Use cases
SSE is the right choice when the communication is inherently one-directional — the server produces a stream of events and the client only needs to consume them:
-
Live dashboards and monitoring — Metrics, server health, or deployment status streamed in real time.
-
News feeds and social timelines — New posts or updates pushed as they are published.
-
Notifications — Alerts, messages, or system events pushed immediately to users.
-
Progress updates — Long-running background jobs (file processing, report generation) streaming progress to the UI.
-
Financial data — Stock prices, exchange rates, or order book updates streamed continuously.
-
AI response streaming — Large Language Model (LLM) APIs stream token-by-token output to the client using SSE (this is how ChatGPT and similar tools display responses incrementally).
Limitations
-
Unidirectional — The client cannot send data back over the SSE connection. Client-to-server messages require a separate HTTP request.
-
Text only — The
text/event-streamformat is plain text. Binary data must be base64-encoded or sent as JSON, adding overhead. -
HTTP/1.1 connection limit — Browsers limit HTTP/1.1 connections per domain (typically six). Multiple SSE tabs to the same origin can exhaust this limit. HTTP/2 multiplexing eliminates the issue since all SSE streams share one TCP connection.
-
No built-in backpressure — If the server sends events faster than the client can process them, the client’s buffer grows unboundedly. Applications must implement their own rate control.
See also
-
WebSockets — For full-duplex, bidirectional real-time communication.
-
Long polling — A simpler, less efficient server push technique.
-
HyperText Transfer Protocol (HTTP) — SSE is built on standard HTTP.
-
Push architecture — The broader pattern of server-initiated data delivery.