Contact

What is Server-Sent Events (SSE)?

Definition

Server-Sent Events (SSE) is a web standard that lets a server push a continuous stream of events to the browser over a single, long-lived HTTP response. The response uses the text/event-stream content type and is consumed in the browser through the EventSource interface. Communication is one-way, from server to client; if the connection drops, the browser reconnects automatically and can report the last event ID it received.

Also known as: SSE, EventSource, event stream, text/event-stream

Timeline of one HTTP connection where the server pushes events in order and the client reconnects with Last-Event-ID

A response that never finishes

SSE adds no new protocol. It is an ordinary HTTP request and response where the server answers with Content-Type: text/event-stream and simply never closes the response. Whenever something happens, it writes a few lines to the stream and the browser turns them into events immediately. The format is defined in the WHATWG HTML Living Standard, and browsers expose it through the EventSource interface.

The channel is one-way: the server talks, the client listens. When the client needs to send something, it uses separate, regular HTTP requests. A surprising share of “real-time” features fit this shape perfectly.

The wire format

Each event is a block of field: value lines terminated by a blank line:

: comment line, used as a keep-alive

retry: 5000

id: 41
event: order
data: {"number": "S-1042", "status": "shipped"}

id: 42
data: Building report: 60%
  • data carries the payload; consecutive data lines are joined with newlines.
  • event names the event type; without it the event is a plain message.
  • id sets the last event ID the browser remembers.
  • retry tells the browser how many milliseconds to wait before reconnecting.
  • Lines starting with a colon are comments and are ignored.

Listening, and resuming after a drop

const source = new EventSource("/api/events");
source.addEventListener("order", (e) => updateOrder(JSON.parse(e.data)));
source.onmessage = (e) => showProgress(e.data);

The standout feature is that reconnection is the browser's job. When the connection breaks, EventSource reconnects on its own and sends the last ID it saw in a Last-Event-ID header. A server that keeps a short buffer of recent events can use it to replay exactly what the client missed.

When SSE beats WebSocket

For one-way flows such as notifications, progress of a long-running job, live scores or log tailing, SSE needs fewer moving parts than WebSocket: no protocol upgrade, no custom framing, and existing HTTP infrastructure, cookies and authentication all keep working. Most large language model APIs stream generated text token by token over SSE for the same reason. If the client also needs to send frequent, low-latency messages, WebSocket is the better fit. SSE carries UTF-8 text only, so binary data is out.

Pitfalls you will meet in production

  • Connection limits: as MDN points out, without HTTP/2 browsers allow only six concurrent connections per domain, shared across all tabs. A few tabs with open streams can starve the site's other requests. Over HTTP/2, many streams share one connection.
  • Buffering: reverse proxies and compression layers may hold the response and flush it in batches, so events arrive late or all at once. Disable proxy buffering for the streaming endpoint.
  • Idle timeouts: the specification suggests sending a comment line roughly every 15 seconds to keep legacy proxies from dropping quiet connections.
  • No custom headers: EventSource cannot add headers such as Authorization. Authenticate with cookies, or read the stream with fetch instead.

Related terms

← Back to the glossary