Server Push Doesn't Exist: Polling, SSE, WebSockets

For direct browser-to-application live updates, “server push” ordinarily starts with a request or handshake from the browser. The server then responds over that path, holds it open, or reuses it. The server may send the first application message once the channel exists, but it generally does not establish an unsolicited inbound connection to a browser behind NAT and stateful firewalls.
That distinction gives polling, long polling, Server-Sent Events (SSE), and WebSockets a common mental model: the client opens the door; the implementation determines how long the channel remains available and who can speak through it.
The server does not dial the browser
A misleading diagram of server push puts the server on the left, the browser on the right, and an arrow pointing from server to browser. It suggests that the server learns about an event, finds the browser on the network, and opens a new connection to deliver the message.
A browser can connect to a publicly reachable application endpoint because DNS and routing identify that endpoint, and the server or its edge proxy listens for connections. Its local address may not be globally routable, no browser API is listening for arbitrary inbound TCP connections, and network policy may reject traffic that does not belong to an established flow.
“Server-initiated” is still useful application-level language. It means the server decides when to send an application message. It does not mean the server initiated the underlying network path.
NAT and firewalls make the opening direction matter
With IPv4 NAT, outbound traffic commonly causes a gateway to create or reuse a mapping between an internal endpoint and an external address and port. Filtering rules then determine which return traffic can cross that mapping. An arbitrary server cannot assume a suitable mapping already exists or create one by sending packets at a private browser address.
NAT is not the whole explanation. A device may have a globally routable IPv6 address and still sit behind a stateful firewall. The operating principle described in RFC 6092 is that inbound traffic is allowed when it matches a flow solicited by an internal endpoint or an explicit administrative exception. Other inbound traffic is normally discarded or rejected.
There are topologies and configured exceptions that permit inbound connectivity. Port mappings, peer-to-peer traversal mechanisms, private networks, and explicitly exposed services exist. They do not change the ordinary browser-to-web-application model: the browser initiates an HTTP request or WebSocket handshake to a reachable server endpoint.
Web Push uses a push service: the user agent maintains the receiving path, and a service worker handles messages. HTTP/2 server push is no longer generally available in mainstream browsers; when supported, it used a browser-opened connection. Neither creates an unsolicited application-server connection directly to the browser.
A client-originated channel can carry server-to-client messages, client-to-server messages, or both.
State sequences for four communication patterns
The panels summarize each logical delivery request or channel by sequence, lifetime, and message direction. This can differ from TCP-connection lifetime because polling and long polling may reuse persistent HTTP connections, as RFC 6202 notes.
flowchart TB
subgraph P["Polling: short-lived request; server-to-client response"]
direction LR
P1["Client request"] --> P2["Immediate response"] --> P3["Client waits, then requests again"]
end
subgraph LP["Long polling: held request; server-to-client response"]
direction LR
L1["Client request"] --> L2["Open request"] --> L3["Server response"] --> L4["Client reconnects"]
end
subgraph S["SSE: long-lived channel; server-to-client messages"]
direction LR
S1["Client request"] --> S2["Open event stream"] --> S3["Server events over time"]
end
subgraph W["WebSockets: long-lived channel; bidirectional messages"]
direction LR
W1["Client handshake"] --> W2["Open WebSocket"] --> W3["Either side sends messages"]
end
The meaningful differences are how often the application creates a delivery opportunity, whether one response ends that opportunity, and whether the resulting channel supports one-way or two-way application messages.
Polling The client requests the latest state, the server responds immediately, and the client waits before asking again. Update latency is bounded partly by the polling interval. Shorter intervals reduce that delay but increase request volume, including responses that contain no new information. Polling remains reasonable when updates are infrequent, some delay is acceptable, and ordinary request-response handling is operationally valuable.
Long polling holds a request until an event is available or a timeout occurs, then the client opens another. Each completed response or timeout ends the outstanding request, although one response may batch multiple events. This can reduce delay for infrequent events compared with periodic polling. Gateways, server timeouts, reconnect behavior, and gaps between requests remain design concerns.
SSE begins when the browser creates an EventSource and requests an event stream. The server leaves the HTTP response open and sends UTF-8 text events over time. The HTML Standard defines connection state, event parsing, event IDs, and browser reconnection behavior. The stream is server-to-client. Client commands still use another mechanism, commonly ordinary HTTP requests.
WebSockets begin with a client opening a connection and sending an opening handshake. After the handshake completes, either endpoint can send frames until the connection closes, as defined by RFC 6455. WebSockets provide a bidirectional channel, but they do not let the server bypass connection establishment or network reachability. The browser still knocks first.
Choose based on the workload and operating model
These mechanisms are not a progression in which the newest option replaces the others.
- Message frequency and latency: Periodic polling can fit occasional updates with a tolerant latency target. Long polling or SSE can reduce delivery delay for server-originated events. WebSockets become more relevant when both sides exchange frequent messages over the live channel.
- Concurrent clients: Long-lived channels create state where they terminate. Plan for connections, outstanding requests, buffers, timeout work, and subscriptions. Test edge-proxy capacity and state ownership separately from backend worker capacity. Configured maxima are risk envelopes; validate safe capacity against latency and resource thresholds under load. Under HTTP/1.1, a browser commonly limits an origin to about six connections. SSE streams or long-poll requests can then contend with page traffic; avoiding that separate-connection bottleneck requires HTTP/2 or HTTP/3 multiplexing and browser and intermediary support.
- Payload size and format: SSE carries text events. WebSockets support text and binary messages. For large objects, a small event that tells the browser what changed may be preferable to transferring the object through the live channel.
- Operational complexity: Handle disconnects, stale clients, backpressure, deployments, and intermediary timeouts explicitly. Reconcile proxy idle limits with quiet periods using reconnects or protocol-appropriate keepalives, and define deployment drain or reconnect behavior. Limit reconnect rate and resource use through exponential backoff, jitter, and retry-delay caps, not an attempt limit. SSE provides browser reconnection mechanics and event-ID support, not reliable delivery. If required, replay retention, gap recovery, deduplication, acknowledgements, and loss policy remain application and server concerns; WebSocket protocols likewise need recovery semantics. Apply these controls only where needed, and test and observe them.
The browser can open an SSE stream for new-notification events while marking notifications as read through regular HTTP requests. Polling can serve as a simpler fallback when delayed updates are acceptable. A WebSocket may be appropriate if the feature grows into frequent bidirectional interaction, but two directions of traffic alone do not require one connection for both.
The next problem is client targeting
An outstanding long-poll request, SSE stream, or WebSocket may terminate at an edge proxy or dedicated gateway, while application work runs in another process or container. A subscription registry may live elsewhere, and the event producer may publish through a broker or fanout router. These are separate deployment and failure boundaries. Keeping a request or channel open does not imply that the worker producing an event has direct access to it.
Periodic polling has a different boundary. No outstanding delivery request exists between polls, even if the underlying HTTP connection is reused. The application can make current state or stored events available for the browser to retrieve on a later request.
Once the transport model is clear, the next practical question differs by pattern. For long polling, SSE, and WebSockets, the system may need to identify the relevant connected clients and route each event to the processes that own their outstanding requests or channels. For periodic polling, targeting means making the relevant state or events available to the next authorized request. All four require a precise definition of which client should receive which data, but only the live-request and live-channel mechanisms may require connection ownership and real-time fanout routing.