Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

WebSockets vs Server-Sent Events vs Polling: Choosing Real-Time Without Regret

About Post

Someone in the planning meeting says "it should update live". Ten minutes later, the ticket says "add WebSockets", and nobody has asked the more useful question: how live, and in which direction?

A maintenance request changing from "open" to "in progress" doesn't need the same machinery as a multiplayer game. Real-time on the web comes in four flavours, and the cheapest one that does the job is usually the right one. Let's compare them honestly.

The restaurant version

You're waiting for your food. There are four ways to find out when it's ready:

  • Polling: you walk to the counter every two minutes and ask. Simple, but mostly the answer is "not yet".
  • Long polling: you ask once, and the waiter stands next to you until it's ready, then tells you. You ask again for the next thing.
  • Server-Sent Events (SSE): there's a screen on the wall that shows order numbers as they're ready. Information flows one way, to you, as it happens.
  • WebSockets: you and the kitchen have a phone line that stays open. Either side can talk at any time.

Keep that picture in mind. Now the details.

Polling: boring, and often enough

The client asks the server for the latest state on a timer. That's it: normal HTTP requests, normal caching, normal authentication, works through every proxy and firewall on earth.

The cost is wasted requests and delay. Polling every 10 seconds means updates can be up to 10 seconds late, and every open tab is making requests even when nothing has changed. For a dashboard that a handful of staff keep open, or a "your report is being generated" screen, that's completely fine.

Long polling improves the delay: the server holds the request open until there's news (or a timeout), then the client immediately asks again. It was the standard trick before WebSockets were widely supported. Today it mostly survives as a fallback.

Server-Sent Events: the underrated one

SSE is a long-lived HTTP response that the server keeps writing to. The format is plain text:

event: status
id: 17
data: {"status":"in_progress"}

And the browser has a built-in client, EventSource, that parses it and reconnects automatically, sending the last event ID it saw so the server can resume:

const source = new EventSource('/requests/42/stream');

source.addEventListener('status', (event) => {
  const { status } = JSON.parse(event.data);
  showStatus(status);
});

It's one-way: server to client. But that covers a lot of "live" features: notifications, progress bars, status changes, activity feeds. If you've watched an AI chat answer appear word by word, you've seen SSE-style streaming; the major LLM APIs stream their responses this way.

Watch out for two things. Over HTTP/1.1, browsers limit how many connections a page can open to one domain, and each SSE stream uses one, so many tabs can starve each other (HTTP/2 largely removes this). And proxies that buffer responses will hold your events back; with Nginx, the X-Accel-Buffering: no header or turning off proxy buffering fixes it.

WebSockets: a real two-way channel

A WebSocket starts as an HTTP request that asks to "upgrade", then becomes a persistent, two-way connection. Both sides can send messages at any moment with very little overhead per message.

That's what you want for chat, collaborative editing, live cursors, games, or anything where the client sends frequent small messages too. It's also the most demanding option to run: a server that holds many open connections, load balancers configured for long-lived connections, and a way to fan messages out across multiple servers.

In Laravel, you rarely write raw WebSocket code. You fire a broadcast event on the server and listen with Laravel Echo on the client:

window.Echo.private(`requests.${requestId}`)
  .listen('RequestStatusUpdated', (e) => showStatus(e.status));

The WebSocket server itself can be a hosted service like Pusher or Ably, or Laravel Reverb, Laravel's own first-party WebSocket server, which you run yourself and which speaks the Pusher protocol, so Echo works with it unchanged. php artisan install:broadcasting sets the pieces up. See the Reverb docs for running and scaling it.

Side by side

PollingSSEWebSockets
DirectionClient asksServer to clientBoth ways
LatencyUp to the intervalNear instantNear instant
TransportPlain HTTPOne long HTTP responseUpgraded connection
ReconnectNot neededBuilt inYou (or your library) handle it
InfrastructureNothing newLong-lived responsesA WebSocket server
Best forSlow-changing data, few usersFeeds, progress, notifications, AI streamingChat, collaboration, games

The PHP gotcha

Here's the thing that surprises PHP developers. In a classic PHP-FPM setup, each request occupies a worker process until it finishes. A long-lived SSE stream or long poll holds that worker the whole time. A few hundred open tabs can exhaust your worker pool, and then normal page loads start queueing.

That's exactly why Reverb runs as its own long-running process rather than inside your FPM workers. If you want SSE at scale from a PHP app, think about where those connections will live before you ship it.

Whatever you pick: real-time is a hint, not the truth

Connections drop. Phones go into tunnels, laptops sleep, mobile apps get suspended in the background. Messages sent while the client was away are simply missed.

Design rule: treat real-time messages as "something changed, here's the gist", and keep your normal API as the source of truth. On reconnect, refetch the current state. Then a missed message costs a refresh, not a wrong screen.

For mobile apps, remember that a backgrounded app usually can't hold a socket open at all. If the user must know about something while the app is closed, that's a push notification's job, not a WebSocket's.

How I'd choose

  1. Does the client need to send frequent messages back? Yes: WebSockets.
  2. Does the server need to push updates as they happen? Yes: SSE (or broadcasting, if you already run a WebSocket server).
  3. Is a delay of several seconds fine, with modest traffic? Polling, and move on to the next ticket.

Which one do you reach for by default, and has it ever turned out to be overkill (or not enough)?

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close