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

data

The payload of the event. Multi-line payloads use multiple data: lines; they are concatenated with newline characters.

event

An optional event type. The client can listen for specific event types. Defaults to "message" if omitted.

id

An optional event ID. The browser stores the last received ID and sends it as Last-Event-ID on reconnect, allowing the server to resume from the correct point.

retry

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 EventSource API

Native WebSocket API

fetch / XMLHttpRequest

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-stream format 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