SSE / EventSource Tester
Paste a raw text/event-stream transcript and see every event parsed by the spec grammar — then replay it with real timing, all on this device.
Parses and replays pasted event-stream text on this device — it does not and cannot subscribe to a stream from a static page.
Reads transcripts up to 2,097,152 characters (2 MB) in this tab.
- —Events
- —Comment lines
- —Last event ID
- —Reconnection time
- —Warnings
A transcript records order, not time, so replay paces events every 600 ms at 1x — the speed scales that fixed gap.
What one event block looks like
- data: — the payload; several data lines join with a single LF
- event: — names the event type; without it the type is `message`
- id: — sets the last event ID a client would send back on reconnect
- retry: — reconnection delay in ms; digits only, applied immediately
- : anything — a comment; keep-alives look like this and dispatch nothing
- A BLANK LINE dispatches the block — without one, nothing is delivered.
Build the stream to see the emitted text here.
Nothing you paste here leaves this tab. State only ever travels in links you explicitly create.
Do it offline:$ curl -N -H 'Accept: text/event-stream' https://api.example.com/stream
How to use it
- Capture a transcript: run the curl command below against your own endpoint, or copy a stream's response body out of your browser's network panel.
- Paste it and press Parse — the timeline lists every event a spec client would dispatch, with its type, joined data, id and source lines.
- Read the notices: unknown fields, NUL ids, non-digit retry values and the missing-final-blank-line trap are called out with line numbers.
- Press Replay to watch the events land in order at 0.5x, 1x, 2x or instantly — or switch to the author mode to emit a stream body of your own.
text/event-stream is the format EventSource reads: UTF-8 lines where data:, event:, id: and retry: build a block, and a blank line dispatches it. Paste a captured transcript — curl -N output, an LLM streaming log, a response body copied from your network panel — and every event is parsed by the exact WHATWG grammar, listed on a timeline you can replay at a chosen pace, entirely on this device.
Examples
event: token
data: The quick
event: token
data: brown fox
data: jumps over
event: done
data: [DONE]
#1 · token · id — · data "The quick"
#2 · token · id — · data "brown fox\njumps over"
#3 · done · id — · data "[DONE]"Two data lines in one block dispatch as ONE event: each line's value is appended with a LF, and the one trailing LF is removed at dispatch — so the second event's data is exactly "brown fox", a newline, "jumps over". This is how streaming LLM APIs send a paragraph in pieces.
retry: 3000
id: 41
data: first chunk
data: second chunk
#1 · message · id 41 · data "first chunk"
#2 · message · id 41 · data "second chunk"
reconnection time 3,000 ms · last event ID "41"The id buffer persists across dispatches, so the second event inherits 41 without carrying an id line of its own; retry took effect the moment its line was processed. Neither field needs to repeat per event.
: keep-alive
: keep-alive
data: {"ready":true}
#1 · message · id — · data "{\"ready\":true}"
1 event dispatched · 2 comment lines ignoredLines starting with a colon are comments: proxies see traffic, clients dispatch nothing, and no buffer changes. Servers send them as keep-alives, so a transcript full of them is healthy, not broken.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Nothing arrives without the final blank line
A block dispatches only when an empty line follows it, and a stream that ends mid-block is discarded at EOF — the single most common SSE bug. The parser reports the pending lines instead of silently dropping them.
Exactly one leading space is stripped
data:x and data: x both carry "x", but data: x (two spaces) carries " x". The grammar removes at most one space after the colon, so padded values keep their padding.
UTF-8 only, and one BOM at most
An event stream is always decoded as UTF-8, and exactly one leading byte-order mark is stripped. A second BOM becomes part of the first field name, which then matches nothing and is ignored — the parser points at it.
id is what Last-Event-ID will send back
An accepted id reaches the client's last event ID at dispatch, and a reconnecting client sends that value in the Last-Event-ID request header. An id parked in an undispatched tail — or one containing a NULL — never makes it there.
Replay pacing is declared, not recorded
A transcript records order, not time, so replay paces events at a fixed 600 ms gap that the speed presets scale. The page says so on the control itself rather than pretending the file carried timestamps.
Common errors
Line 1: the stream ends with buffered fields but no blank line, so nothing was dispatched — the classic missing final blank line. Add one empty line to deliver the event.- The transcript stops after its data lines. A real client would buffer them forever and deliver nothing, which is exactly what a stalled-looking SSE integration usually is.
Line 1: `retry` must be ASCII digits only, so "3000x" is ignored and the reconnection time is unchanged.- retry accepts nothing but digits — no units, no spaces, no sign. Anything else is discarded whole rather than partially parsed.
Line 1: this `id` value contains U+0000 NULL, so the whole field is ignored and the last event ID is unchanged.- A NULL anywhere in an id makes a spec client ignore the entire field — the previous id keeps standing, which surprises servers that pack binary junk into ids.
This transcript is 2,097,153 characters, past the 2,097,152-character (2 MB) limit this page parses in one tab — nothing was read. Trim the capture or split it.- Past the cap the transcript is declined whole rather than read in part: half a timeline with wrong totals would be worse than an honest refusal. Both numbers are printed.
FAQ
Can this subscribe to my SSE endpoint?
No. This is a static page: it opens no connection to any stream and has no field to put a URL in, because pretending otherwise would be a lie. It parses and replays transcripts you paste. To capture one, run the curl command below against your own endpoint and paste what it prints.
Is my transcript uploaded or stored anywhere?
No. Parsing runs in this tab, nothing is written to storage — not even as a convenience buffer — and a share link carries the view options only, never the pasted text. Transcripts often embed API keys in their data lines, so the tool treats every paste that way.
Where do I get a transcript to paste?
From the curl command below, from your browser's network panel (open the stream request and copy its response body), or from server and SDK debug logs — streaming LLM clients usually offer a way to dump the raw event stream they received.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Parse the pasted transcript.