Webhook vs WebSocket vs SSE: which real-time option to use

Webhooks push events from one server to another with a single HTTP POST; WebSockets keep a two-way connection open, and server-sent events (SSE) stream one way from server to browser. Without HTTP/2, browsers allow only 6 SSE connections per domain; WebSockets use ports 80 and 443.

Webhooks push an event from one server to another with a one-off HTTP POST, while a WebSocket keeps one connection open so a server and a client, usually a browser, can send messages both ways at any time. Server-sent events (SSE) are the one-way middle ground, a long-lived HTTP response the browser reads as a stream, and long polling is the old fallback. Below is a comparison table of all four, followed by SSE vs WebSocket, webhook vs WebSocket, webhook vs SSE, and where long polling still fits.

Webhooks, WebSockets, SSE and long polling compared

The first question to settle is who needs the update: another server, or a person looking at a screen.

In practice, these often work together rather than as rivals, since a typical setup has a webhook from Stripe or GitHub land on your backend, which then pushes the news out to open browser tabs over SSE or a WebSocket.

WebhooksWebSocketsServer-sent eventsLong polling
DirectionServer to serverBoth waysServer to browserServer to client, one response at a time
Who connectsThe sender, once per eventThe client, once (HTTP Upgrade, then 101)The browser, with EventSourceThe client, again after every response
ConnectionA new HTTP POST per eventOne long-lived TCP connectionOne long-lived HTTP responseRequests held open until there is news
DataJSON or form body plus headersText or binary framesUTF-8 text, text/event-streamAny HTTP response
When the link failsThe sender may retry (Stripe for up to 3 days)You write the reconnect logicBrowser reconnects and sends Last-Event-IDClient sends the next request
Limit to knowAnswer fast: Slack 3 seconds, GitHub 10No backpressure in the browser API6 connections per browser and domain without HTTP/2Full HTTP headers on every message

SSE vs WebSocket: one-way stream or two-way channel

When you're weighing SSE vs WebSocket, look at whether the client needs to talk back. With SSE, the browser opens the stream using new EventSource(url), and your server responds with status 200 and Content-Type set to text/event-stream, then keeps writing events made of event, data, id, and retry lines, with each event ending in a blank line. Event streams are always UTF-8. If the connection drops, the browser reconnects on its own and sends a Last-Event-ID header so the server can resume where it left off, and to keep old proxies from dropping an idle connection, the HTML standard suggests sending a comment line starting with a colon about every 15 seconds. Without HTTP/2, browsers allow only 6 open SSE connections per browser and domain across all open tabs, though over HTTP/2 that limit is negotiated between server and client and defaults to 100 streams.

A WebSocket (RFC 6455, December 2011) starts as a single HTTP request that upgrades to a two-way connection (ws:// on port 80 or wss:// over TLS on port 443) carrying text and binary frames along with ping and pong control frames. You have to write reconnection logic yourself, and the browser WebSocket API doesn't support backpressure, so if messages arrive faster than your app can process them, it can buffer them in memory or stop responding.

As a rule of thumb, pick SSE for feeds, notifications, and progress updates, and use WebSockets for chat, games, and collaborative editing where the client talks back a lot.

SSE response (example)

HTTP/1.1 200 OK
Content-Type: text/event-stream

id: 7
event: build
data: {"status":"passed"}

: keep-alive

WebSocket handshake (RFC 6455, trimmed)

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Webhook vs WebSocket

The difference in webhook vs WebSocket comes down to one-off requests between servers versus an open session with a client. A webhook sends one HTTPS request per event from a provider to your server, which must be reachable from the public internet and return a 2xx status within a few seconds (GitHub gives you 10 seconds, Shopify gives 5, Slack gives 3) or the delivery counts as failed and the provider may retry it later. Nothing stays connected between events.

A WebSocket is a session where the client dials out once and both sides talk over that same connection for as long as it stays open, which fits a browser or mobile app that can't accept incoming connections. Use webhooks for payment, repository, and order events between backends, and a WebSocket or SSE for a live dashboard or chat in a browser. A browser tab can't receive a webhook on its own because it doesn't have a public URL, so your backend has to receive the webhook first and forward it.

Webhook vs SSE

When comparing webhook vs SSE, you're looking at the same push idea built for two different audiences. A webhook makes one HTTP request per event to a server, while SSE holds one HTTP response open to a browser and carries many events over it.

Recovery works differently too: a webhook sender decides whether and when to retry a failed delivery, whereas an SSE client reconnects on its own and passes Last-Event-ID to pick up missed events. If a provider only sends webhooks, receive them on your backend and stream them to the browser over SSE.

Where long polling still fits

Under RFC 6202 (April 2011), HTTP long polling works by having the client send a request that the server holds open until an event happens or a timeout hits, at which point the server sends a complete response and the client immediately sends a new request. Every response is a full HTTP message with all its headers, and while the average delay is close to one network transit, the worst case is over three network transits (long poll response, next request, second response).

The RFC notes a default browser timeout of 300 seconds and successful experiments up to 120 seconds, though 30 seconds is generally a safer server value. Use long polling only where SSE and WebSockets are blocked.

Watch webhooks arrive in your browser

If you want to watch incoming webhooks the way you'd watch a live feed, a free bin on webhooks.sh handles the receiving-server part for you. Create a bin at view.webhooks.page or run curl -X POST https://webhooks.sh/v1/bins, point your provider at the ingest URL or test it with curl, and every request shows up live in your browser with its method, path, headers, and body.

A free bin lasts 48 hours, takes up to 100 requests per day with bodies up to 100KB, and displays the latest 10 requests in the viewer. You can claim the bin with a free Google sign-in before it expires to keep the same URL and hold onto new requests for 30 days. When you're ready to forward events to code running on your own machine, read our guide on how to test webhooks locally.

# 1. Create a free bin (or open view.webhooks.page)
curl -X POST https://webhooks.sh/v1/bins

# 2. Send it a webhook the way a provider would
curl -X POST https://<bin>.webhooks.page/build \
  -H "Content-Type: application/json" \
  -d '{"event":"build.finished","status":"passed"}'

FAQ

Is a webhook the same as a WebSocket?

No. A webhook is a single HTTP POST sent per event from one server to another, while a WebSocket is a long-lived, two-way connection that's usually opened by a browser or app.

Should I use SSE or WebSockets?

Use SSE if only the server needs to send updates like feeds, notifications, or progress, especially since SSE reconnects on its own. Pick WebSockets if the client talks back often, such as in chat or games.

Can a browser receive a webhook?

Not directly, because receiving a webhook requires a public URL that the sender can reach. You have to receive the webhook on your server and push the update to the browser over SSE or a WebSocket.

Does SSE work over HTTP/2?

Yes. Running SSE over HTTP/2 removes the old limit of 6 open connections per browser and domain, and the stream limit is negotiated between the server and client with a default of 100.

Is long polling worse than WebSockets?

For frequent messages, yes, because every response carries full HTTP headers and the worst-case delay is over three network transits. Keep long polling as a fallback for networks that block WebSockets and SSE.

When should I use webhooks instead of WebSockets?

Use webhooks when an update goes from one server to another and you run an HTTPS endpoint that can accept incoming requests, such as for payment, repository, or order events.

Last updated

Try it in 10 seconds.

Create a free bin at view.webhooks.page — no signup, no install. Point your sender at the URL and watch requests land live. Bins expire after 48 hours.