Back to the notebook
Oct 01, 20263 min read

Offline Is a Product State, Not an Error

MobileProductEngineering

An application can be beautifully responsive on a fast connection and deeply frustrating when the network disappears. A spinner keeps turning. A form clears itself. A person repeats an action because they cannot tell whether it worked.

I prefer to think of offline use as a product state with its own promises. The question is not simply whether a screen loads. It is what someone can safely do, what the application remembers, and what still needs the server.

Begin with one complete task

Take a municipal service request. A resident chooses a service, writes a description, and adds a location. If the connection fails before submission, the useful outcome is a recoverable draft with a clear explanation of what happened.

I would define that journey before selecting a caching strategy. Which fields can be edited locally? Does the request need current server data? Can an attachment be kept on the device? What happens if the resident signs out before synchronisation?

An offline fallback page can provide an intentional response when navigation fails. The web.dev guide shows how a service worker can serve a previously cached fallback. That is a useful starting point for a web application; a complete editing and synchronisation workflow requires additional design.

Give each state an honest name

Saved on this device, waiting to send, and received by the service are three different states. I would avoid using a single reassuring checkmark for all of them.

A local draft should say it is local. A queued request should say that it is waiting for a connection. Confirmation of receipt should follow an acknowledgement from the server.

That distinction matters because people make decisions based on interface language. If the screen says a request was submitted, they may stop trying to submit it.

Decide how conflicts will work

Suppose someone edits the same draft on two devices. When both reconnect, which version should survive?

There is no universal answer. For a simple personal note, an explicit overwrite rule might be acceptable. For a service record, preserving both changes and asking for review may be preferable. The choice belongs to the meaning of the data, not just the convenience of the synchronisation code.

I would also separate a draft identifier from a server record identifier. That makes it easier to track a piece of work while it moves between local editing, submission, and confirmation.

Test the interruption, not just the recovery

A useful test session includes a connection lost halfway through editing, a request whose response never arrives, an application restarted with pending work, and a device that reconnects after the underlying service data has changed.

Each case asks a concrete question: does the person know where their work is, and what they need to do next?

Local storage also needs deliberate retention rules. On a shared device, keeping every completed request forever may be the wrong product choice. Decide what to retain, when to remove it, and how to explain that behaviour.

A good offline experience protects the effort someone has already made. It does not promise that a remote action has happened until the application has evidence that it has.