SSE vs WebSockets vs Webhooks vs Polling
Four ways to move a message when it is ready rather than when someone asks. What each one costs at your load, and the decision rule that picks between them.
The short version
- Polling is the boring answer that is correct far more often than engineers like to admit. Start here and justify moving away.
- Server-sent events give you server-to-browser push over plain HTTP, with automatic reconnection built into the browser. Badly underused.
- WebSockets are the right answer when you genuinely need low-latency messages in both directions.
- Webhooks are for server-to-server delivery and are a different category entirely — they solve integration, not user interface freshness.
Four technologies, one apparent job: get a message to somebody when it is ready rather than when they ask. They are not interchangeable, they fail in different ways, and choosing wrong is expensive in a way that is not obvious until you are at scale.
This is a comparison you can decide from.
Polling
The client asks the server, on a timer, whether anything has changed.
It is dismissed as primitive, and it has genuine merits that get overlooked. It uses ordinary HTTP, so every proxy, load balancer, CDN and corporate firewall handles it correctly. It is stateless, so any server can answer and scaling is trivial. It fails in the most benign way available: a failed poll simply means the next one runs. And it is testable with the tooling you already have.
The cost is wasted requests. At a five-second interval, a thousand users generate 200 requests per second whether or not anything has changed, and the overwhelming majority of those return nothing.
Two refinements substantially improve the economics:
- Conditional requests. With
ETagorLast-Modified, an unchanged resource returns a 304 with no body. The request still happens, but it becomes cheap. - Long polling. The server holds the request open until there is something to say or a timeout expires. This gets you push-like latency over ordinary HTTP, at the cost of holding a connection per waiting client — which is most of the operational burden of WebSockets without the benefits.
Choose polling when
- Latency of several seconds is acceptable.
- Concurrent user counts are modest, or updates are frequent enough that most polls return data.
- You value operational simplicity, which you should more than you probably do.
Server-sent events
The client opens one HTTP connection and the server streams events down it indefinitely. It is a one-way channel: server to client only.
SSE is the most underrated option of the four. It runs over ordinary HTTP, so infrastructure treats it normally. The EventSource API handles reconnection automatically, and it does so correctly — including replaying from a last event ID that the browser tracks for you. Getting that right by hand on top of WebSockets is a meaningful chunk of work that teams routinely underestimate.
The limitations are real but narrower than people assume. It is text-only, which matters rarely. Client-to-server messages need a separate ordinary HTTP request, which is fine for the common case where those are infrequent. And under HTTP/1.1 browsers cap connections per domain at six, which HTTP/2 removes; in 2025 this is mostly a non-issue.
Choose SSE when
- Data flows predominantly from server to client: notifications, live dashboards, activity feeds, streamed AI responses.
- You want push latency without operating a second protocol.
- You would rather inherit correct reconnection behaviour than implement it.
The default most teams should reach for. If your realtime requirement is “the interface should update when something happens on the server”, that is SSE, and choosing WebSockets instead buys you bidirectionality you will not use in exchange for reconnection logic you now have to write.
WebSockets
A single TCP connection, upgraded from HTTP, carrying framed messages in both directions with minimal per-message overhead.
When you need genuine bidirectional low latency, nothing else comes close. Chat, collaborative editing, multiplayer interaction, trading interfaces — these are WebSocket problems and no amount of cleverness makes polling adequate for them.
What you take on in exchange:
- Reconnection is yours to write — backoff, jitter, re-authentication, re-subscription, state reconciliation. All of it, correctly, including the parts that only fail on flaky mobile networks.
- Infrastructure needs configuration. Load balancers must be told to support the upgrade and given generous idle timeouts. Some corporate proxies still interfere.
- Statefulness. The connection lives on one specific server, which introduces the fan-out problem and everything that follows from it.
- Authorisation is checked at connect time, so you need a deliberate strategy for revocation on long-lived connections.
- Different tooling. Your existing HTTP logging, tracing and load-testing setup does not cover it.
Choose WebSockets when
- Both directions genuinely need low latency, not just the server-to-client one.
- Message frequency is high enough that per-message HTTP overhead would actually matter.
- You are prepared to own the connection lifecycle properly, or to pay a managed provider to own it for you.
Webhooks
Webhooks belong in a different category, and conflating them with the other three causes real confusion. The others deliver to a browser. A webhook delivers to another server: your system makes an outbound HTTP request to a URL the integrator registered, when an event occurs.
This is the standard mechanism for server-to-server integration — how Stripe tells you a payment succeeded, how GitHub tells your CI a commit landed. It cannot update a user interface, because browsers do not have public URLs.
What building a webhook system correctly requires:
- Retries with exponential backoff. The receiver will be down sometimes. This is a certainty, not a risk.
- Signature verification, so the receiver can confirm the request genuinely came from you. An unsigned webhook endpoint is an unauthenticated write API.
- Idempotency keys, because at-least-once delivery means duplicates will arrive and the receiver needs to deduplicate safely.
- A dead letter queue and visibility into failures, so a receiver that has been broken for two days is discovered by you rather than by them.
- Timeouts and circuit breaking, so one slow receiver cannot degrade delivery for everyone else.
Side by side
| Polling | SSE | WebSockets | Webhooks | |
|---|---|---|---|---|
| Direction | Client pulls | Server to client | Both | Server to server |
| Latency | Half the interval | Near immediate | Near immediate | Near immediate |
| Protocol | HTTP | HTTP | Upgraded TCP | HTTP |
| Server state | None | Connection held | Connection held | None |
| Reconnection | Not applicable | Automatic in browser | You implement it | Retry queue |
| Main cost | Wasted requests | Open connections | Operational complexity | Delivery guarantees |
A decision rule
Work through these in order and stop at the first yes.
- Is the recipient another server rather than a browser? Use webhooks.
- Is a delay of several seconds acceptable? Use polling with conditional requests.
- Does data flow essentially one way, server to client? Use SSE.
- Do you need low latency in both directions? Use WebSockets, and budget properly for the connection lifecycle.
Most teams that end up on WebSockets arrived there by reflex rather than by working through this list, and are paying for capability they do not use.
Boolean Solutions experience with these choices
We have implemented all four in production and, more usefully, migrated between them when the original choice stopped fitting. The most common migration we perform is WebSockets back to server-sent events, after a team discovers that everything they actually send goes one direction and they are maintaining reconnection logic for no benefit.
If you are choosing a transport or suspect you chose the wrong one, talk to us.
Further reading
- MDN: Using server-sent events — the clearest practical introduction to SSE
- MDN: WebSockets API — protocol and API reference
- Stripe: webhooks — the reference implementation everyone else copies, and worth reading even if you never touch Stripe
- Realtime Applications: What They Actually Require — the architectural consequences of any of these choices
