Server-sent events and WebSockets

Updated 27 Sep 2026

Server-sent event streams and WebSockets pass through to your origin on a full site zone and a standard origin alike, with nothing to switch on. A connection stays open for as long as it carries something, however long that is, and the traffic it carries is not charged.

Server-sent events#

An answer your origin sends as Content-Type: text/event-stream reaches the viewer event by event, as your origin writes it, and is never stored, whatever the Cache Expiration Time says. Its headers are passed on at once, so the browser's EventSource opens before your first event, however long that takes. It works for a visitor with a cookie and one without. Any other answer sent in chunks with no length, a long-poll or a streamed API response, is passed on as it arrives in the same way.

When the connection drops, the browser reconnects by itself after a few seconds and sends Last-Event-ID, which reaches your origin on every zone, so your server can carry on from the last event the viewer saw rather than starting again.

WebSockets#

Connect to your own hostname as you would to your server, wss://www.example.com/socket. The handshake goes to your origin, and once your origin accepts it with 101 Switching Protocols the connection is relayed both ways, byte for byte, as each side sends. Subprotocols, compression and your own message format pass through untouched. If your origin refuses the handshake, its answer (a 403, a 404, a 426) reaches the viewer as it came, so the viewer's WebSocket library reports your reason.

The handshake reaches your origin with the viewer's Origin, Sec-WebSocket-Protocol and Sec-WebSocket-Extensions, and with the same X-CDN-Connecting-IP and X-Forwarded-For as any request. On a full site every header the viewer sent goes with it, cookies included. On a standard origin with Strip Response Cookies on, the viewer's cookie is dropped as on every request, so an application that recognises a WebSocket by its session cookie needs that switch off, or a full site zone. With Force SSL on, use wss://: a ws:// handshake is answered with the redirect to HTTPS, which WebSocket clients do not follow.

The rules still apply#

A handshake or a stream meets every rule of the zone first: signed links, blocking, maintenance mode and Block Root Path Access. While it is open it is checked again every few seconds, and it is closed when the zone is put into maintenance, paused or deleted, its hostname is removed from the zone, or a blocking rule now refuses the viewer. A signed link is checked when the connection opens and not afterwards: its expiry decides who may open one, not how long it may stay open.

How long a connection stays open#

As long as something moves. There is no limit on how long an event stream or a WebSocket stays open or on how much it carries; what closes one is silence:

WhatClosed after
An event stream your origin sends nothing on125 seconds
A WebSocket with nothing in either direction125 seconds
A handshake or a stream your origin has not started answering125 seconds; the viewer gets the 502 page
A viewer that stops taking what is sent to it60 seconds
An origin that stops taking what a viewer sends on a WebSocket60 seconds

So send something more often than every two minutes: a comment line, : keepalive, on an event stream every 30 seconds, and a ping on a WebSocket. Socket.IO, SignalR, Phoenix and Action Cable send one by default; with a plain WebSocket server, send a ping from your server every 30 seconds.

A connection also ends when the location serving it restarts, for example for an update: it closes its open connections first, and the viewer reconnects to a location that is serving. An EventSource does that by itself; a WebSocket reconnects if your client does, as the libraries above do, so write a plain WebSocket client to reconnect after a delay.

When a connection is refused#

  • 503 with Retry-After: 30: the location already holds as many open connections as it can, or your zone already holds half of them, so that no one site can take a location's connections for itself. An EventSource treats a 503 as final and does not reconnect by itself, so a page that has to stay live should listen for its error event and open a new one after a delay.
  • 429 with Retry-After: 30 and X-CDN-Limit: live: one address already holds a quarter of the open event streams and WebSockets that location can hold, so no single address can take a location's connections for itself. A client that reconnects in a loop without closing its old connections meets it first.
  • On a private bucket origin a WebSocket handshake is an ordinary GET, answered by the bucket.

What is counted and charged#

Each event stream and each WebSocket counts as one request in your statistics, fetched from your origin, and the bytes it carries are not in Bandwidth delivered and are never charged. Uploads are not charged either. An answer typed text/event-stream that carries a Content-Length is a file, and is counted and charged as one. See Billing and invoices and Statistics.

What is not supported#

  • WebSockets over HTTP/2 or HTTP/3. Browsers open WebSockets over HTTP/1.1 when a server does not offer the HTTP/2 form, which is what they do here, with no change to your code.
  • A WebSocket through the Home PoP: it goes straight from the location that accepted it to your origin.
  • Rules per path, or a limit you set on connections. They apply to the whole zone, as every setting does.

Checking it#

curl -sN -H "Accept: text/event-stream" https://www.example.com/events

Events print as your origin sends them, and the connection stays open. A WebSocket handshake by hand, over HTTP/1.1:

curl -si --http1.1 https://www.example.com/socket \
  -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="

A server that accepts it answers HTTP/1.1 101 Switching Protocols with X-CDN-Cache: BYPASS and a Sec-WebSocket-Accept of s3pPLMBiTxaQ9kYGzzhZRbK+xOo=, then holds the connection open; press Ctrl-C to end it. Any other status is your origin's own answer to the handshake.

Ask a human

To
Subject
Docs: Server-sent events and WebSockets

Read and answered by the people who build CacheGenie, seven days a week.

Write to us