Custom Event Types
§9.2.5 / §9.2.6event: typename
SSE supports named custom event types via the event: field. Any valid string can be used as an event type (except 'message', 'open', 'error' which are reserved). The browser fires a MessageEvent with event.type set to the custom name. Clients subscribe with addEventListener('typename', handler). Custom types are essential for multiplexing multiple data streams on a single SSE connection.
Details
The event: field in an SSE stream sets the event type for the next dispatched event. When the blank-line terminator is reached, a MessageEvent is created with the type property set to the event: value.
Default behavior: if no event: field is present, type is 'message'. If event: is empty string (''), type is also 'message'.
Use cases for custom event types: 1. Multiplexing – send 'price', 'news', 'alert' events on the same connection 2. Protocol versioning – 'v2.update' vs 'v1.update' 3. LLM streaming – 'content_block_delta', 'message_stop' (Anthropic Claude uses this) 4. Progress events – 'progress', 'complete', 'error'
The three built-in event names (message, open, error) cannot be used as custom types without conflicting with the browser's built-in handlers. Use onmessage for 'message' events, not addEventListener.
Multiple event types on one connection: the browser processes each event independently based on its type. You can have multiple addEventListener calls on a single EventSource for different types.
Examples
# Server sends named events:
event: price
data: {"symbol": "BTC", "price": 67432.10}
event: news
data: {"headline": "Bitcoin ETF approved"}
event: alert
data: {"severity": "high", "message": "Threshold exceeded"}
# Each blank line dispatches one eventconst source = new EventSource('/market-stream');
source.addEventListener('price', (e) => {
const tick = JSON.parse(e.data);
updateChart(tick.symbol, tick.price);
});
source.addEventListener('news', (e) => {
showBanner(JSON.parse(e.data).headline);
});
source.addEventListener('alert', (e) => {
triggerAlert(JSON.parse(e.data));
});# Anthropic API uses named SSE events:
event: message_start
data: {"type":"message_start","message":{...}}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"text":"Hello"}}
event: message_stop
data: {"type":"message_stop"}Gotchas
Custom events are not caught by onmessage – use addEventListener('typename', handler) or onmessage only catches 'message' type
Event type 'message', 'error', 'open' should not be used as custom event: field values to avoid confusion with native EventSource events
The event: field must come before the data: field in the event block for correct parsing in all browsers
Event type names are case-sensitive – 'Price' and 'price' are different event types