SSE (Server-Sent Events) for AI streaming UX
The pattern
When generating or fetching data from AI (or a slow paginated upstream), stream the progress to the browser via SSE rather than making the user wait for a single big response. Users see cards/progress/chunks as they're produced.
Projects exemplifying this
- amboras —
/api/generateopens an SSE stream. Progress events + generatedStoreConfig+ Shopify sync status flow to the browser as each step completes. Same pattern reused for the AI editor (/api/stores/[id]/edit). - synapse (repo flavor, Follower Intel) —
/api/followers/allstreams each paginated batch of ~20 followers from RapidAPI as an SSE event. Cards appear in the grid in real time as data arrives.
Why SSE over alternatives
- vs WebSockets: SSE is one-way server→client, which is exactly what progress/generation streaming needs. Simpler protocol, works over plain HTTP, and — the load-bearing reason in both projects here — works with Vercel's serverless streaming response model without needing a persistent connection.
- vs polling: no wasted requests, real-time updates, smaller overhead.
- vs one big response: user doesn't wait for the slowest thing. Perceived latency is "first event" not "last event."
Implementation shape (consistent across both)
POST /api/... (SSE response)
event: progress → { step, message }
event: <typed> → { ...payload } // e.g., "followers", "storeConfig", "shopifyProduct"
event: done → { total, final }
event: error → { message } // rare — usually surface gracefully
The frontend opens an EventSource, listens for events, and updates UI incrementally. Errors inside the stream are sent as event: error rather than HTTP status codes (the outer HTTP status is already 200 once the stream opens).
When this playbook misleads
- Don't SSE for small/fast responses — overhead isn't justified.
- Don't SSE for two-way interaction — use WebSockets.
- Don't forget the reconnection story —
EventSourceauto-reconnects but your backend needs to handle "resume from cursor" if that matters.
Related
- ai-model-choice (SSE pairs naturally with hosted AI calls that take 1-10s)
- compress-mechanical-labor (SSE makes a "5-minute generation" feel like "5-minute watching it happen")