id and retry Fields
§9.2.5 / §9.2.6id: / retry:
The id: field sets the Last-Event-ID – a cursor the browser sends on reconnect so the server can resume from the right position. The retry: field (milliseconds integer) sets the reconnect delay. Both are set by the server; the browser tracks id: automatically and sends it as a request header on reconnect. These two fields enable resumable SSE streams without application logic.
Details
The id: field is the SSE resumption mechanism. When set, the browser stores the value as the 'last event ID string'. On any reconnect, the browser sends this value as the Last-Event-ID HTTP request header. The server reads this header and resumes the stream from after that ID.
id: field rules: - Any UTF-8 string (except NUL, U+0000) is a valid event ID - id: with no value (empty) clears the last event ID – next reconnect sends no Last-Event-ID header - The id: field persists across events until updated – it is not per-event, it is a session cursor - Setting id: to the same value as the previous event is valid and common for heartbeat events
retry: field rules: - Value must be a decimal integer (milliseconds) with no other characters - If the value cannot be parsed as an integer, the retry: field is ignored - The retry: field can be sent in any event, not just the first - Default reconnect time is implementation-defined (typically 1–3 seconds in browsers)
Implementation pattern: 1. Server assigns a sequential ID to each event 2. Server stores events in a ring buffer or database 3. On reconnect with Last-Event-ID, server replays events with ID > lastEventId 4. This gives at-least-once delivery semantics
Examples
# Set retry and first event ID
retry: 3000
id: 1
data: {"msg": "first event"}
id: 2
data: {"msg": "second event"}
id: 3
event: update
data: {"msg": "third event"}# After disconnect, browser sends:
GET /stream HTTP/1.1
Last-Event-ID: 2
# Server resumes from ID > 2:
id: 3
data: {"msg": "third event"}
id: 4
data: {"msg": "fourth event"}# Server clears the last event ID: id: data: this event resets the ID to empty # Next reconnect will NOT send Last-Event-ID header
Gotchas
The id: field is per-stream, not per-event – it persists until changed. Setting id: 5 means all subsequent events until the next id: field also use ID 5
retry: value must be an integer in milliseconds with no suffix – retry: 3s is invalid and silently ignored
Last-Event-ID is sent as a request header, not a query parameter – ensure your server reads headers, not query strings
An id: field with a NUL character (U+0000) is silently ignored per spec
The browser may send Last-Event-ID as an empty string if id: with no value was received – distinguish this from a missing header