Decide whether live updates earn their cost
A live order page is useful when a customer is waiting for a short, meaningful change, such as confirmation that a payment provider has returned a final result or that a counter pickup is ready. It is less useful when the next carrier scan may take many hours. Before opening a persistent connection, define which status changes customers need immediately and which can appear after a normal page refresh. The business source of truth remains the order and payment records; the WebSocket is only a delivery channel for news about those records.
Write a vocabulary that separates the channel from the order. 'Connected' means the page can receive new messages; it does not mean the payment succeeded. 'Reconnecting' says the channel is recovering; it does not mean the order is being processed again. If the channel fails, keep the last verified order state visible with its last-checked time and say that updates are temporarily delayed. Avoid replacing a confirmed state with a spinner that implies the order disappeared, and avoid a green success banner simply because the socket reopened.
Compare three implementation choices before committing. A manual refresh or occasional HTTPS fetch is often enough for infrequent changes. Server-sent events can suit one-way updates where your stack supports them. WebSocket earns its operational complexity when the journey needs timely bidirectional communication or the existing platform already runs it reliably. Whichever transport is chosen, a successful network message is not an order-state transition until the server has recorded and authorized that transition. The acceptance test should be written around that invariant.
Start from a trusted snapshot
On opening the page, fetch an authorized order snapshot over the normal application route. It should include the order identifier, a current state, a server-generated version or sequence, and the time that state was recorded. Then subscribe to updates for that order only. If your system cannot make the snapshot and subscription gap-free, connect first and buffer events while obtaining the snapshot, or perform a second reconciliation fetch after subscribing. This is an application design choice; the WebSocket protocol itself does not supply a complete order history.
Treat incoming messages as hints to reconcile, not as permission to overwrite any visible value. Include a version or monotonically increasing sequence so the client can ignore a duplicate or older message. If it sees a gap, an unknown state, or an event for another order, it should fetch the authoritative snapshot and log a sanitized diagnostic. Do not assume delivery is exactly once. A reconnect may cause the same event to arrive again, while a disconnected interval may hide events altogether unless your server explicitly offers replay.
A worked example makes the distinction clear. At page load the server snapshot says order A is 'payment pending', version 8. The socket then carries version 9, 'payment confirmed', and the page updates. After a train tunnel interrupts the phone, a delayed version 8 message arrives on reconnection. The client must not move backwards to pending. It asks the server for the latest authorized snapshot; if that is version 10, 'packing', it displays packing. These version numbers illustrate a design, not measured shop data.
Recover without duplicate effects
The browser WebSocket interface exposes open, message, close and error events. A client should react to the actual connection state, but an error event alone does not tell the customer the order failed. Reconnect with bounded backoff and variation so many tabs do not retry at the same instant after a network incident. Stop retrying when the page is closed, the order is no longer relevant, or authentication is no longer valid. A visible manual refresh remains useful when automatic recovery takes longer than expected.
Reconnect is for receiving information, not resubmitting a purchase. Never make the order button fire again merely because the socket reopened. If a payment or cancellation command had an uncertain response, handle it through the transaction's own idempotency and server-side outcome lookup; do not infer success from the connection. The live page should show the latest known outcome and offer a safe next action. This preserves a clear boundary between displaying state and causing state changes.
Browser navigation adds another edge case. MDN advises closing an open WebSocket on pagehide because it can affect back-forward cache eligibility, and reconnecting on a pageshow restoration when appropriate. A restored page may contain an old DOM snapshot, so fetch fresh order state before treating its visible labels as current. Test a customer who opens the order page, visits the account page, then presses Back after dispatch. The restored page should not revive a pre-dispatch label merely because its old JavaScript state survived.
Authorize every subscription
A socket that can receive order updates is a private data channel. Authenticate the handshake or an immediately following protocol step under your chosen design, check that the customer may access the requested order, and repeat authorization when the subscription changes. Do not let the browser choose an arbitrary order ID and rely only on a hidden UI link. If the session expires or the customer loses access, end or restrict the connection and make the next snapshot request fail safely. Avoid embedding reusable credentials in a WebSocket URL.
RFC 6455 explains that the browser sends an Origin header and that a server intended for particular sites should verify expected origins. This helps resist unwanted browser cross-origin use, but it is not customer authentication: a non-browser client can supply its own Origin value. Use a secure transport appropriate to the page, validate the origin where expected, and still enforce session and order-level authorization on the server. Also limit message size and accepted message types, since a persistent channel does not make incoming data trustworthy.
Keep operational logs useful without logging every private event payload. Record connection attempts, authorization failures, unexpected sequence gaps, and reconciliation outcomes with a short correlation ID and order reference that staff are entitled to see. If a queue or node fails, the support team should be able to tell whether the underlying order state changed and whether the customer page caught up. Avoid promising 'real time' as an absolute guarantee in marketing copy; the customer needs a truthful last-updated indicator and an alternative route to check.
Test interruptions as normal use
Acceptance should include Wi-Fi loss, a phone changing networks, a laptop sleeping, two open tabs, browser Back restoration, a server restart, a stale cookie and a customer who opens an old bookmarked order page. For every case, check the visible connection message separately from the order state. Confirm that an old event cannot reverse a newer state, a gap triggers reconciliation, and a completed payment is neither hidden nor invented. Run these checks with a controlled test order so real customers are not used as test data.
Ask a tester to walk through the example with versioned events and record what they see: the last verified state, its time, the temporary interruption message, and the final reconciled state. Then inspect server records to prove the displayed account and order match the authenticated customer. A test that merely observes the socket's 'open' event misses the decision that matters. If the page stays disconnected, it should still explain how to refresh, seek help, or check the order through the ordinary account route.
Finally, define who can turn the live feature off if it becomes noisy or inaccurate. A fallback snapshot route should remain operational, and the page should degrade to a clear delayed-update message. Review support tickets for cases where the displayed time and actual server state diverged; use that evidence to improve the system rather than claiming an unmeasured reliability gain. The goal is a page that stays honest through interruption, not a permanent green connection dot.
Before you proceed
- Does the page distinguish a lost connection from an order or payment outcome?
- Can it reconcile after a missed or duplicate event without moving state backwards?
- Is each order subscription authorized and is the fallback snapshot usable?


