# Express SSE relay for the Responses API
The Node SDK's `client.responses.create({ stream: true })` returns an async
iterator of typed events. Your Express route re-frames the deltas as SSE.
## Route shape (order matters)
1. `res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control":
"no-cache", "Connection": "keep-alive" })`.
2. `res.flushHeaders()` immediately, so the browser starts the EventSource before
the first model token arrives.
3. `for await (const event of stream)`: on events with
`event.type === "response.output_text.delta"`, do
`res.write("data: " + JSON.stringify({ delta: event.delta }) + "\n\n")`.
On `response.completed`, break and `res.end()`.
## The compression trap
If the app uses the `compression` middleware, it buffers SSE chunks to compress
them, which defeats streaming. Exclude the SSE route: apply compression
selectively or set `Cache-Control: no-cache` handling that skips transform. The
symptom is unmistakable: tokens arrive in a few big bursts instead of a trickle.
## The client-disconnect trap
- On `req.on("close")`, break out of the loop. Otherwise the upstream OpenAI
stream keeps generating (and billing) for a user who left.
- Do not `await` anything slow between events; backpressure from a slow client
is handled by the socket, not by your loop.
## Check before you ship
- curl -N the route: frames must arrive incrementally from the first seconds.
- Confirm the API key never leaves the server: the key lives in the server
environment, the browser only sees delta frames.