Does SSE work over HTTP?
Yes. Server-sent events are ordinary HTTP. The client makes a normal GET request, the server replies 200 OK with a Content-Type of text/event-stream, and then keeps the response body open, writing events into it as they happen. There is no protocol upgrade and no separate port, so SSE works over HTTP/1.1, HTTP/2, HTTP/3, and HTTPS.
What an SSE exchange looks like on the wire
The request and response are both things any HTTP client would recognize:
GET /events HTTP/1.1
Accept: text/event-stream
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
The only unusual part is that the response never finishes. The server writes a block of data: lines, flushes, and waits for the next event, so the body arrives in pieces over minutes or hours rather than all at once. Under HTTP/1.1 that means chunked transfer encoding; under HTTP/2 and HTTP/3 it is a stream that stays open.
This is the practical difference between SSE and WebSockets. A WebSocket starts as an HTTP request and then leaves HTTP entirely with a 101 Switching Protocols response, which is exactly the step that corporate proxies, older load balancers, and some CDNs refuse. An SSE stream is a slow response, so anything that can serve HTTP can carry it. WebSocket vs SSE works through the rest of that tradeoff.
SSE over HTTP/1.1 versus HTTP/2
The protocol version does not change whether SSE works, but it changes how many streams you can hold at once. Browsers allow six concurrent connections per origin over HTTP/1.1, and an open SSE stream occupies one of them for the life of the page. Two or three tabs of your own app and the user has spent their entire budget, so images and API calls queue behind streams that are deliberately never going to close.
HTTP/2 removes the problem by multiplexing: every stream shares one TCP connection, and browsers allow roughly a hundred concurrent streams on it. Since browsers only negotiate HTTP/2 over TLS, serving your site over HTTPS is what unlocks that in practice. HTTPS is fine for SSE generally, with one rule to remember: an EventSource opened from an HTTPS page to an http:// URL is blocked as mixed content, the same as any other subresource.
What breaks an SSE stream
When SSE fails in production, the protocol is almost never the reason. Four pieces of HTTP infrastructure account for most of it.
- Proxy buffering. A reverse proxy that buffers the response holds your events until the buffer fills, turning a live stream into batches. In nginx that is
proxy_buffering off, or send anX-Accel-Buffering: noresponse header from the application. - Idle timeouts. Load balancers and CDNs close connections that look idle. Send a comment line, a bare
:followed by a blank line, every fifteen to thirty seconds as a keepalive. - Compression. gzip on a streaming response buffers to fill its window, with the same batching effect. Disable it for
text/event-stream. - Response transformation. Anything that wants to read the whole body before passing it on, including some serverless gateways and WAF rules, will hold the stream open and deliver nothing.
Getting these right is configuration work rather than code, which is a fair summary of what running SSE costs you.
Where plain HTTP limits SSE
Because it is an HTTP response, the channel only goes one way. Anything the client needs to send travels as a separate request, which is usually fine: a chat UI streams tokens down over SSE and posts the next prompt over a normal POST. That is the shape ChatGPT uses.
The browser's EventSource API is also stricter than HTTP itself. It only issues GET requests and cannot set custom headers, so bearer-token authentication means either falling back to cookies or reading the stream through fetch and parsing the event format yourself. The payload is UTF-8 text as well, so binary data has to be base64-encoded and pays about a third in size for it.
When a short HTTP request beats a held-open one
SSE assumes a client that is present and waiting. That describes a browser, and it does not describe another company's backend, which may be mid-deploy when your event fires. Holding a stream open to every integrator, and dropping events for whoever happened to be restarting, is a poor trade against sending one HTTP request per event and retrying it if it fails.
That is what webhooks are: the same HTTP, used in short bursts, pointed the other direction. Webhooks vs server-sent events compares the two directly. If you are the one sending events out to customers, Svix handles the delivery side, including retries, signature verification, and delivery logs.
Ready to send webhooks?
Svix handles signing, retries, rate limiting, and delivery observability for the webhooks you send to your users, so your team can stay focused on your product.
Start sending webhooks with Svix or read the build vs. buy analysis