Skip to main content

message

§9.2.6

event: message (default)

The default SSE event type. Fired when the server sends a data: field without an explicit event: field, or when event: message is set explicitly. Handled by the EventSource onmessage handler or addEventListener('message', handler). The most commonly used event type for LLM token streaming.

Details

Every SSE event has an event type. When no event: field is present in the event, the type defaults to 'message'. This fires the onmessage event handler on the EventSource object.

An SSE event is terminated by a blank line (two consecutive newlines). Multiple data: lines are concatenated with a newline character between them.

For LLM streaming: each token or chunk is a separate message event. The OpenAI API sends data: {"choices":[{"delta":{"content":"token"}}]} for each chunk, then data: [DONE] as a sentinel to signal completion.

The event.data property on the MessageEvent contains the concatenated data lines as a string. Parse JSON with JSON.parse(event.data).

For a stream that sends binary data: SSE is UTF-8 only. Binary content must be base64-encoded in the data: field. For binary streaming, use WebSocket or WebTransport instead.

Examples

Simple text message
# Server sends:
data: Hello, world!

# Client receives MessageEvent:
# event.type = "message"
# event.data = "Hello, world!"
JSON payload
# Server sends:
data: {"userId": "usr_1", "score": 42}

# Client:
source.onmessage = (e) => {
  const payload = JSON.parse(e.data);
  console.log(payload.userId); // "usr_1"
};
Multi-line data (concatenated with \n)
# Server sends:
data: line one
data: line two
data: line three

# Client receives:
# event.data = "line one\nline two\nline three"
LLM token streaming (OpenAI pattern)
data: {"choices":[{"delta":{"content":"Hello"}}]}

data: {"choices":[{"delta":{"content":" world"}}]}

data: [DONE]

# Client:
source.onmessage = (e) => {
  if (e.data === '[DONE]') { source.close(); return; }
  const chunk = JSON.parse(e.data);
  output += chunk.choices[0].delta.content ?? '';
};

Gotchas

!

data: lines with a leading space have the space stripped – data: hello becomes 'hello' not ' hello'

!

An event with no data: lines is discarded even if it has an id: or event: field

!

The [DONE] sentinel used by LLM APIs is not part of the SSE spec – it is an application-level convention

!

JSON.parse will throw if the server sends malformed JSON – always wrap in try/catch

!

SSE is UTF-8 only – binary data requires base64 encoding in the data: field

See Also