News
Development8 min read

Real-time features in a web application: notifications and live data

When it makes sense to build a real-time web application and when simply fetching data more often is enough. An overview of the options — polling, server-sent events and WebSockets — and what each one costs in operations, scaling and testing.

The requirement almost always arrives in the same shape: "we want it to update live, without refreshing the page." It sounds like a detail — all we want is for a number on screen not to lag behind reality. In practice it is one of the decisions that most changes the architecture of the application, the cost of running it, and everything the team has to watch after launch.

The difference is fundamental. An ordinary web application answers questions: a request comes in, a response goes out, the connection closes and the server forgets the client. A real-time web application has to maintain a relationship with every open browser — knowing who is connected, what they care about, what it has already sent them and what it failed to send. This article is about approaching that requirement soberly: when it makes sense, what the options are, what each one costs, and what traps wait for you the moment a connection drops or two people edit the same record.

Do you really need real-time, or just fresher data?

The first question is not technical but product-level: what actually goes wrong if a user sees a value that is fifteen seconds old? For a large share of business applications the answer is "nothing". A manager looking at an overview does not need the numbers to change before their eyes — they need them not to be yesterday's. A dispatcher assigning vehicles, or two people in the same form, are a different case; there, delay directly causes collisions and duplicated work.

It helps to sort your screens into three groups:

  • Genuine real-time (sub-second). The decision is made immediately and several people work on the same object: chat, concurrent editing, dispatching, monitoring with alarms.
  • Fresh data (seconds to tens of seconds). Order lists, task statuses, operational overviews. The user tolerates a short delay, they just do not want to click refresh.
  • Batch views. Reports, closings, period summaries. Here "liveness" is a drawback — numbers that change while you read them are hard to interpret and even harder to compare.

The second group is by far the most common in practice, and periodic fetching is almost always enough for it. The client asks the server every few seconds whether anything is new; with conditional requests (ETag, If-Modified-Since) the answer is usually empty and cheap. When the tab is in the background, the interval stretches or stops. No new infrastructure appears, it passes through every corporate proxy, failures are debugged with ordinary tools, and retrying is built into the principle itself. If the goal is mainly for management to see current figures without a manual export, we cover that in more depth in the piece on real-time reporting for company management.

In short: Until you can name a specific decision that breaks with a ten-second delay, build polling and spend the saved money on something the user actually feels.

Polling, SSE and WebSockets: what each option costs

If you have passed the filter above and genuinely need real-time, choosing the transport layer is mostly an operational decision, not a speed one. All of the options deliver data fast enough; they differ in what they ask of you every day afterwards.

ApproachData flowTypical latencyOperational burdenWhen it is a good fit
Periodic pollingclient asksthe interval (e.g. 5–30 s)lowestoverviews, lists, task statuses
Long pollingclient asks, server holdsnear-instantmediumwhen you need speed but not two-way traffic
Server-sent events (SSE)server → clientnear-instantmediumnotifications, live charts, streamed responses
WebSocketstwo-waylowesthighestchat, concurrent editing, games, dispatching
Hosted real-time serviceprovider-dependentnear-instantlow in development, higher in costa small team that does not want to run its own layer

Server-sent events are the most consistently underrated option in the projects we see. It is a plain HTTP connection that the server keeps open and writes lines of text into. Automatic reconnection and message numbering are part of the standard, it works over ordinary HTTP infrastructure, and no separate protocol appears on the server side. If you only need the "server to user" direction — and for notifications and live charts that is exactly the case — WebSockets are often needlessly heavy.

Choose WebSockets when the client genuinely sends a lot of messages back and the ordering and latency of both directions matter. The price is your own protocol on top of the connection, your own authentication and authorisation for every message, and having to solve what HTTP solves for you. Ultimately the difference between the technologies is smaller than the difference between "we have it switched on" and "we know how to run it", a topic we also address when designing custom web applications.

Every open connection is a small piece of state you have to hold somewhere, pay for, and eventually close properly.

State that falls apart: why real-time UI needs reconciliation

This is where most first implementations fail. A developer tests the feature on office wi-fi, sees the messages arriving and considers the job done. Reality is different: the mobile network switches over, the laptop goes to sleep, the corporate proxy kills an idle connection after a minute, a new deployment disconnects everyone at once. And the user gets no warning — the screen simply stops being alive while pretending to be current.

Hence a simple rule: the message stream is not the source of truth, it is only an optimisation. The server remains the source of truth, and the interface must have a way to align with it at any moment. In practice that means three things:

  • Detection. A regular heartbeat in both directions and a visible connection indicator. If the user sees "reconnecting", they will not make a decision on top of dead data.
  • Recovery. After reconnecting, either fetch the missing events from the last known sequence number, or — simpler and entirely sufficient for most applications — reload the whole screen state and only then start applying the stream again.
  • Idempotency. Assume a message will arrive twice or out of order. Handling an event must be safe to repeat, otherwise duplicates appear in your lists that nobody can explain.

Optimistic updates and conflicts during concurrent editing

Optimistic UI — showing the change immediately, before the server confirms it — is what makes an application feel responsive. It is also the most common source of silent inconsistency. Every optimistic change needs three states: pending, confirmed, rejected. A rejection has to be able to roll the change back and say so clearly, not quietly overwrite it.

For concurrent editing you choose between three modes. The simplest is a lock on the record — while someone is working on it, everyone else sees read-only; inconvenient, but predictable. The second option is record-level versioning: the client sends the version it saw and the server refuses a write over a newer version. The third and most expensive option is field-level merging or data structures designed for automatic merging, which you realistically need only for collaborative text.

Caution: A "last write wins" model without versioning does not produce an error you would see in the logs — it produces silently lost changes that surface as a user complaint a week later.

Scaling the real-time layer

As long as a single application server is running, everything is simple: an event occurs and the server pushes it to its connected clients. The moment you add a second server, this stops working — a user connected to server A never hears about an event created on server B. The solution is a distribution layer through which the servers relay events to each other: a message broker or a publish/subscribe channel.

Three more things come with it, and they need solving before production rather than after:

  • Sticky sessions and timeouts. The load balancer has to know the connection must stay on the same node, and its idle timeout must be longer than the heartbeat interval.
  • Connection limits. Each connection consumes memory and a system descriptor. Node capacity is therefore planned by the number of people signed in at once, not by requests per second.
  • The post-deployment surge. A restart disconnects everyone at once and everyone tries to reconnect at once. Without exponential backoff with random jitter, the application takes down its own startup.

Do not forget authorisation either. With classic HTTP, permissions are checked on every request; with a long-lived connection they are checked once at connect time, after which a person can lose access and still keep receiving data. The check has to happen when each message is sent. We cover the broader context of growing load in the article on scaling a web application as the company grows.

Notification design: channel, batching and attention

The technical side of notifications is easier than the product side. The decision that determines success is this: which event deserves to interrupt a person, and which should quietly wait inside the application.

ChannelSuited toMain risk
In-app listroutine events, work contextthe user may never open it
Browser pushtime-sensitive eventspermission is asked once, a refusal is permanent
Emaildigests, things for latereasily ends up in a forgotten folder
SMS and callscritical failures, on-callexpensive and intrusive; for a narrow group only

A few principles that hold regardless of industry: never notify a person about their own action; merge related events into one message after a few minutes instead of sending five separate ones; offer settings per event type, not a single switch for everything; and sync "read" state across devices, or the user deals with the same thing twice. If you are considering push notifications without a native app, that is in practice the topic of progressive web applications — and be aware that support still differs across platforms.

The operational tax: what real-time adds to monitoring and testing

Real-time features bring a class of failure that classic monitoring never catches. The server responds, the error rate is zero, the page loads fast — and yet half the users are looking at stale data because their connection dropped an hour ago and never came back. So you need to measure different things: the number of active connections, the reconnection rate, the delay between an event being created and delivered, the number of undelivered messages, and the queue depth in the broker.

Testing is a similar chapter. Automated tests must be able to open two sessions at once and verify that an action in one shows up in the other; they must be able to sever the connection artificially and check that state was reconciled. A load test has to simulate a thousand simultaneously open connections, not a thousand requests per second — those are entirely different scenarios. How such scenarios fit into the overall quality process is described in the piece on the QA process before a software launch.

Count on the real-time layer being a source of cost that does not disappear once the project is handed over. Open connections are paid for in time, not requests, so the monthly bill grows with the number of signed-in people even when nobody is doing anything.

Summary

A real-time web application is not a feature you "add at the end" — it is a decision about architecture, operations and budget for years to come. The approach that works is boring: first name the specific decision that delay would ruin; if there is none, use polling and be done. If there is one, pick the simplest layer that suffices — for server-to-user traffic that is usually server-sent events. Then, before the first line of UI, design how state gets reconciled after an outage, and only at the end deal with optimistic updates and conflicts.

Design notifications as a product, not as a technical by-product: fewer messages in the right channel are always worth more than everything instantly everywhere. And expect monitoring and testing to cost more than in an ordinary application — that is the tax you pay for a screen that stays alive.

If you are weighing whether real-time makes sense in your application and to what extent, we are happy to go through it screen by screen — get in touch and we will start with what genuinely has to happen immediately.

INTERFASE