Skip to content

Article · 10 min read · Oct 31, 2026

WebSockets vs SSE vs WebRTC: how to choose real-time updates for a business app

Use server-sent events (SSE) when the server only needs to push updates to the screen, WebSockets when the browser and server both send messages continuously, and WebRTC for live audio and video between people. For most internal tools and portals, SSE or plain polling is enough, and WebSockets earn their extra moving parts only for chat, collaborative editing and two-way live data. This guide is for product owners and technical leads at companies of roughly 20 to 200 people.

Farzan AnsariCofounder and CTO

Key takeaways

  • SSE is one-way, server to browser, over ordinary HTTP, and it reconnects automatically, which makes it the simplest choice for live dashboards and streamed AI answers.
  • A WebSocket is a two-way connection that suits chat, collaborative editing and live feeds, but the browser API has no backpressure, and the app needs its own reconnect and resync logic.
  • WebRTC carries live audio and video between participants and is the wrong tool for pushing business data to a dashboard.
  • Proxies and load balancers that buffer responses or close idle connections are the most common reason a working demo fails in production.
  • Uber chose SSE over WebSockets for its first push platform and built its own acknowledgement and retry protocol on top, a useful reminder that two-way is not always necessary and that delivery logic still is.

Business software used to work on a refresh cycle: you clicked, the page reloaded, you saw the new state. Users now expect a dispatch board that updates itself, a chat that shows typing, and an AI assistant that writes its answer word by word. Each of those needs the server to speak first, and the web has four ways of making that happen.

WebSockets vs SSE vs WebRTC vs long polling: which should you use?

Pick the simplest transport that moves data in the direction you need. If only the server talks, use SSE. If both sides talk constantly, use WebSockets. If people need live audio or video, use WebRTC. If none of those is available, long polling still works.

Long pollingSSEWebSocketsWebRTC
DirectionServer to client, by repeated requestsServer to clientBoth directionsBoth directions, between peers
CarriesAny HTTP responseText events over HTTPText and binary messagesAudio, video and data channels
Browser reconnects for youNo, your code re-requestsYes, with the last event IDNoNo, and a signaling step is needed first
Works through ordinary HTTP infrastructureYesYes, with buffering turned offNeeds protocol upgrade supportNeeds extra servers to connect peers
BackpressureNatural, one request at a timeLimited, the server decides what to dropNone in the browser APIHandled by the media stack
Typical business useFallback, older systemsLive dashboards, notifications, streamed AI answersChat, collaborative editing, two-way live feedsVideo calls, voice agents, screen sharing
Complexity to runLowLowMediumHigh

What is a WebSocket?

A WebSocket is a long-lived, two-way connection between a browser and a server over which either side can send a message at any time. RFC 6455 defines it as an opening handshake followed by basic message framing, layered over TCP. The handshake is an HTTP Upgrade request, so a WebSocket can share ports 80 and 443 with ordinary web traffic.

The RFC explains why it exists. Before it, applications needing two-way communication abused HTTP by polling the server and sending upstream messages as separate calls, which meant many connections per client and header overhead on every message. Its stated simpler solution was a single TCP connection for traffic in both directions.

The cost is that you give up what HTTP handled for you. MDN's documentation notes that the WebSocket interface does not support backpressure. Backpressure is a way for a slow receiver to tell a fast sender to wait. Without it, messages arriving faster than the application can process them either fill memory or pin the CPU. You also own reconnection, authentication refresh and recovery of anything missed while disconnected.

What is SSE (server-sent events)?

Server-sent events are a one-way stream of text messages from a server to a browser over a normal HTTP response that never finishes. The server sets the content type to text/event-stream, and the browser's EventSource object keeps listening. MDN describes each message as lines of fields, such as event, data, id and retry, ended by a blank line.

By default, if the connection closes, the browser restarts it. That one behavior removes a large share of the work that WebSockets leave to you. Two limits apply. SSE only carries text, and when it is not used over HTTP/2, browsers cap it at about six open connections per domain across all tabs, according to MDN. Over HTTP/2 the limit is negotiated and defaults to 100 streams.

Where do WebRTC and long polling fit?

WebRTC is for live media between participants. MDN describes it as a technology that lets applications capture and stream audio and video, and exchange arbitrary data between browsers, often without an intermediary server. It also includes a data channel, but you would choose WebRTC for a call or a voice agent, not to refresh a dashboard. Our explainer on what WebRTC is and how it works covers it in depth.

Long polling means the client sends a request and the server holds it open until there is something to say. RFC 6202 describes it, and also warns that timeouts need care: it states that 30 seconds is generally a safer value than something longer. It is the right fallback when infrastructure blocks everything else, and a reasonable choice when updates are rare.

Where are WebSockets used in real products?

WebSockets show up wherever many people need to see the same changes within a second or two. The engineering teams behind these products describe the pattern in their own documentation.

  • Team chat. Slack says every client keeps a persistent WebSocket connection to its servers, connecting to the nearest edge region, and describes delivering messages across the world in 500ms. A message goes to the server that owns the channel, which fans it out to gateway servers, which push it to connected clients. Typing indicators take a similar path and are not stored in the database.
  • Chat platforms and bots. Discord's Gateway is a WebSocket connection with required heartbeats. If a client drops, it can resume and replay lost events from the last sequence number it received. Apps in 2,500 or more guilds must shard across several connections.
  • Collaborative design tools. Figma describes clients that talk with a cluster of servers over WebSockets, with a separate server process for each multiplayer document. The server is the central authority, and after an offline stretch the client downloads a fresh copy and reapplies its edits.
  • Market data. Coinbase's exchange feed pushes real-time updates for orders and trades over a WebSocket. Its documentation warns that messages can be dropped and tells consumers to watch sequence numbers, where a jump of more than one means a message was lost.
  • Firewalled integrations. Slack's Socket Mode uses a WebSocket so apps behind a corporate firewall can receive events without exposing a public HTTP endpoint. That is the reverse of a webhook, and we compare the two in webhooks vs polling.

One well-known example is not a WebSocket at all. Uber's engineering team reports that at one point 80% of requests to its backend API gateway were polling calls. It evaluated long polling, WebSockets and SSE in 2015 and chose SSE, citing security, mobile SDK support, binary size and its simplicity on the HTTP and JSON stack it already ran. Because SSE is one-way, Uber built its own acknowledgement and retry protocol on top. Rider app updates, driver trip offers and assignment status moved from polling to push, with a one-byte heartbeat every four seconds. Uber then described a next-generation version on gRPC, chosen because new app experiences needed bidirectional transfer. If your use case is live dispatch or tracking, the lesson is that server-to-client push carried Uber for years, provided you add acknowledgement and resume logic where delivery matters.

Illustrative example: Consider a distributor with 60 dispatchers whose browser dashboard asks the server for changed delivery statuses every 5 seconds. That is 12 requests per second, roughly 350,000 requests in an 8-hour shift, and nearly all return nothing new. Moving the dashboard to SSE removes that traffic and makes status changes appear as they happen. The dispatchers still use a normal form to assign drivers, so nothing in the design needs a two-way WebSocket. A WebSocket becomes worth its cost only if the same screen adds a shared chat with drivers, or several dispatchers edit one route plan at once.

How do you build a streaming endpoint?

A streaming endpoint is an HTTP response that the server keeps open and writes to over time. The browser reads each piece as it arrives. Six details decide whether it survives production.

How does HTTP streaming and SSE framing work?

On HTTP/1.1, the server can omit the Content-Length header and send the body as chunks, a mechanism called chunked transfer encoding. MDN's reference notes that HTTP/2 disallows the Transfer-Encoding header and provides more efficient streaming mechanisms of its own. In practice your web framework handles this. You set the content type to text/event-stream, turn off response caching, and write each message as plain text, flushing after each one.

An event is a few lines of fields, and a blank line ends it. A line starting with a colon is a comment and is ignored, so it can be used as a heartbeat. The id field labels an event, the event field names its type, and the data field carries the payload.

How does reconnection with Last-Event-ID work?

When a connection drops, the browser reconnects and, per the WHATWG specification, reports its last event ID to the server in a Last-Event-ID header. Your server must keep enough history to replay what came after that ID, such as the last few minutes of events in a table or a stream. The retry field sets how long the browser waits before reconnecting. A server can stop reconnection by returning HTTP 204 No Content.

Without stored history, a reconnect silently loses events, so the reconciliation advice from webhooks applies here too: on reconnect, fetch current state rather than trusting the stream to be complete.

Why do proxies break streaming?

Reverse proxies often buffer a response until it is complete or a buffer fills, which turns a stream into a long pause followed by a burst. NGINX has response buffering on by default, and your application can switch it off per response with the X-Accel-Buffering header set to no. Content delivery networks and API gateways have their own equivalents. Test streaming through the exact production path, because a stream that works on a laptop can arrive in one lump behind a gateway.

What about timeouts?

Every hop has an idle timeout. NGINX's proxy_read_timeout defaults to 60 seconds between two successive reads, and the connection closes if the upstream sends nothing in that window. The WHATWG specification suggests authors include a comment line every 15 seconds or so to keep legacy proxies from dropping idle connections. Send a heartbeat comment well inside your shortest timeout, and set load balancer idle timeouts above the heartbeat interval.

How do you handle backpressure?

If the browser or network is slower than your event rate, the server's outgoing buffer grows. Set a cap per connection, and decide what to do at the cap. For a live price or a map position, drop stale updates and send only the latest. For an audit trail, close the connection and let the client resync from stored history. Never allow an unbounded queue per client, because one slow tablet on weak Wi-Fi can use memory that every other user needs.

How do AI tokens stream?

Large language model APIs use SSE. Anthropic's documentation says to set stream to true to receive the response incrementally using server-sent events. The stream begins with a message_start event, then content blocks made of start, delta and stop events, and the API can send ping events and errors inside the stream. Its example is an overloaded_error, which in a non-streaming call would be an HTTP 529. OpenAI's guide is similar: stream equals true returns typed events, such as response.output_text.delta, as text is generated.

Two business points follow. Call these APIs from your server, not directly from a browser, because the request carries your API key. And OpenAI warns that streaming a model's output in production makes it harder to moderate the content, so approval steps and filters need to run on the accumulated text, not only on each fragment. Your streaming endpoint therefore forwards the model's events, handles an error that appears halfway through an answer, and records the final text.

How should a 20 to 200 person company choose?

Start from what the screen needs, not from the technology.

  1. Does the data change less than once a minute? Poll, or refresh on user action. It is the cheapest thing to run.
  2. Does the server push, and the user only reads? Use SSE. Dashboards, order status, notifications and AI answers fall here.
  3. Do users send and receive continuously, or edit shared state? Use WebSockets, and budget for reconnection, resync and monitoring.
  4. Do people need to hear or see each other? Use WebRTC, usually through a managed provider.
  5. Will it sit behind a corporate proxy or a strict firewall? Plan on SSE or long polling, and test early.

Whichever you choose, set the expectation with the business: a live screen needs a defined answer for what happens when the connection drops. For planning the surrounding build, see our guide to internal tools and portals: the first release.

How Kastling approaches this

Real-time features are usually part of a larger internal tool, dashboard or portal, and Kastling would treat them that way. The work would start with how the people using the screen decide and act, then choose the least complicated transport that serves them, polling and SSE before WebSockets. Kastling would connect the systems a business already runs, agree how stale a screen may become and who is told when it does, and test the full path from real browsers through the real proxies and load balancers on AWS or Azure. This work belongs to Custom Solutions, and the team brings in specialists where a design needs them.

Questions

Is SSE old or deprecated?

No. It is defined in the living HTML standard maintained by WHATWG and is the transport that OpenAI and Anthropic use for their standard text-streaming APIs. It is simple by design, which is why it keeps showing up in new systems.

Can WebSockets and SSE sit behind the same load balancer?

Usually yes, but check three settings on every hop: whether the proxy buffers responses, how long it keeps an idle connection open, and whether it supports the protocol upgrade that WebSockets need. Test the full path from a real browser, not only from the server host.

Do we need a managed real-time service?

Often not at 20 to 200 employees and a few hundred simultaneous users, where one well-configured application server handles the load. A managed service becomes attractive when you need to push to many thousands of connections, across several regions, or when nobody on the team wants to operate the connection layer.

What does the browser do when a connection drops?

With SSE, the browser reconnects on its own and tells the server the last event ID it saw. With a WebSocket, nothing happens automatically: your code must detect the loss, reconnect, and ask the server for whatever it missed.

Sources

  1. IETF RFC 6455: The WebSocket Protocol
  2. MDN: WebSockets API
  3. MDN: Using server-sent events
  4. WHATWG HTML Standard: Server-sent events
  5. MDN: WebRTC API
  6. IETF RFC 6202: Known Issues and Best Practices for Long Polling and Streaming in Bidirectional HTTP
  7. MDN: Transfer-Encoding header
  8. NGINX: ngx_http_proxy_module
  9. Uber Engineering: Real-time push platform
  10. Slack Engineering: Real-time messaging
  11. Slack: Using Socket Mode
  12. Discord: Gateway
  13. Figma: How Figma's multiplayer technology works
  14. Coinbase Exchange: WebSocket feed overview
  15. Anthropic: Streaming messages
  16. OpenAI: Streaming API responses

Guide · 15 min read

Build, buy or integrate: deciding on custom business softwareBuy software for standard processes, integrate when your existing systems already hold the data, and build only where the process sets you apart. Companies of 20 to 200 people usually end up with a hybrid: buy the core system of record, then integrate or build the edges around it. Compare the options on 3 to 5 year total cost of ownership, not on the first invoice.Read

Article · 8 min read

Rust vs TypeScript: when to use eachTypeScript is the right default for web applications, APIs and business software because of its hiring pool, speed of change and ecosystem. Rust earns its higher cost in CPU-heavy paths, latency-critical services, embedded and edge work, and anywhere memory safety and predictable performance matter. The two are often combined, and this guide is for owners and technical leads at companies of 20 to 200 people deciding what to build in.Read

Article · 8 min read

Sentry vs PostHog: which one does your team need?Sentry is built for developers who find and fix errors and performance problems, and PostHog is built for product teams who need to understand user behavior through analytics, session replay, feature flags and experiments. Each has moved into the other's territory: PostHog now offers error tracking and Sentry offers session replay. This guide is for technical leads and product owners choosing monitoring for a web application, and for small teams deciding whether one tool is enough.Read

One useful email a month.

New guides, tools and practical notes on putting AI to work. No sales sequences.

See how an idea becomes a working solution.

Explore how we scope, build and hand over AI projects, with clear decisions at each stage.