Developer Toolbox

text/event-stream

A text/event-stream response stays open, and the server writes events into it as they happen: lines starting with data:, each event ended by a blank line. The browser's EventSource reads the stream and reconnects on its own when it drops.

Open in cURL Builder A request with this type is filled in.

Header

Content-Type: text/event-stream

At a glance

Extensions
None: it describes a body, not a file
Kind
Text
Parameters
None
In a browser
Read with new EventSource(url), which fires a message event for each event without an event: field, and an event of that name for the others.

With curl

curl -N -H 'Accept: text/event-stream' https://api.example.com/events

With fetch

const res = await fetch('https://api.example.com/events', { headers: { Accept: 'text/event-stream' } });
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(value);
}

Common mistakes

  • Proxies that buffer

    nginx buffers proxied responses by default and holds events back until a buffer fills. Send X-Accel-Buffering: no from the app, or set proxy_buffering off for that location.

  • Compression holds events too

    A gzip layer that waits for a full block delays small events. Leave event streams uncompressed, or flush after every event.

  • Connection limits on HTTP/1.1

    Browsers open about six connections per host over HTTP/1.1, and each open EventSource keeps one busy. Over HTTP/2 the streams share one connection.