Solution
How to build for connections that drop, on devices that are old
The people most in need of a service are frequently the ones on the worst connection to reach it. Designing as though everybody has fibre is not an oversight, it is excluding the users who need you most.
The short answer
Serve the primary answer as HTML in one request, before any script runs. Budget total page weight rather than optimising individual assets. Make every write idempotent so a retry on a dropped connection cannot duplicate. And test on a throttled connection before deciding what the first screen contains.
Who you are actually building for
Somebody on a mid range Android phone, on a mobile connection that varies between adequate and nothing, possibly paying for data by the megabyte, in a place where the connection drops when they walk into a building.
That is not an edge case in most of the world. And there is a specific irony worth naming: for a service that improves connectivity, or that people need in an emergency, the users in the worst conditions are the ones who need you most.
Step 1. Order the page by what the visitor came for
Every page has one primary answer. Identify it, then make sure it arrives in the first response.
For a coverage checker it is whether the service reaches the visitor. For a listing it is the price and the specification. For a balance it is the number.
That answer must be in the HTML of the first response, before any script executes, before any font loads, before any image decodes.
Everything else is an enhancement layered on afterwards.
I have got this wrong in a way worth repeating. On a provider site I built the interactive coverage map first, because it was the interesting problem and it demonstrated the network beautifully. Throttled, it took nine seconds before a visitor could learn anything at all, on exactly the connection quality of the people most likely to be looking for better internet.
The rebuild made the primary answer a text input answered by the server in one request, and demoted the map to a lazy enhancement. Same information. One round trip instead of a large download.
Step 2. Budget the whole page, not the pieces
Per asset limits fail because each individual addition is defensible. One more font weight. One more small library. A slightly larger hero image. Each is fine, and the sum is not.
Set a total, enforce it in CI, and let additions compete with each other.
HTML under 14KB for the primary answer, so it fits the first round trip
CSS one file, inlined critical or a single request
JS on content under 20KB, ideally zero
Images above fold one, modern format, explicit dimensions
Fonts one family, one or two weights, self hosted, subset
Total, first view under 200KB
The fourteen kilobyte figure is not arbitrary. It approximates what arrives in the first congestion window, before the connection has ramped up. Content inside it arrives roughly one round trip after the request. Content after it waits for another.
Self host fonts and subset them. A third party font is a separate DNS lookup, connection, and TLS handshake before a single glyph. On a high latency connection that is often over a second of nothing.
Step 3. Make every write survivable
On an unreliable connection, requests fail after the server has already processed them. The user has no way to tell the difference between “it did not send” and “the response did not come back”.
They will press the button again. Design for that as the normal case, not the exception.
- Every write is idempotent, keyed on something the client generates once and reuses on retry. A double submit is then harmless rather than a duplicate record.
- Never clear a form on failure. Losing somebody’s input on a dropped connection is the single most hostile thing a form can do, and it is the default behaviour of a naive implementation.
- Say what happened. “Saved” or “not saved, retry” are useful. “Something went wrong” leaves them guessing whether pressing again will duplicate, and most people guess wrong.
- Time out generously. An aggressive timeout on a slow connection converts working submissions into lost ones.
Step 4. Choose SMS honestly where it is the reachable channel
In markets where data is expensive or intermittent, SMS is not a legacy fallback, it is often the only channel that reliably arrives.
That has design consequences. Messages cost money per unit, so waste is measurable. There is no delivery guarantee worth trusting, so record what you attempted. And the message has to be complete in itself, because a link to a page the recipient cannot load is not a message.
Push notifications and email are cheaper and they only reach people already connected and already holding an account. Those are different populations, and assuming they are the same is how a system concludes it notified everybody.
Step 5. Test on the real thing
Throttle the network in the browser, then verify on an actual mid range device rather than a development machine.
Latency matters more than raw bandwidth for perceived speed, and most default throttling profiles under model it. A connection with three hundred milliseconds of round trip time makes every additional request expensive regardless of how much bandwidth is available, which is why request count is the number to reduce first.
The test that matters: how long until the visitor learns the one thing they came for. Not first paint, not load complete. Time to answer.
The checklist
- Name the primary answer for the page.
- Confirm it is in the HTML of the first response, with scripting disabled.
- Keep that answer inside roughly fourteen kilobytes.
- Self host and subset one font family.
- Every image has dimensions and a modern format, and only one loads eagerly.
- Every write is idempotent and never clears input on failure.
- Test throttled, on a mid range device, and measure time to answer.
- Enforce a total page budget in CI so it cannot creep back.
What good looks like
The page is useful before it is finished loading. A dropped connection mid form costs a retry rather than the work. And the people on the worst connections get the same answer as everybody else, just with fewer pictures.
Questions people actually ask
- What is a realistic budget?
- Aim for the primary answer inside the first fourteen kilobytes of HTML, because that is roughly what arrives in the first round trip. Then a total page weight budget rather than per asset limits, because per asset limits are always individually defensible and collectively fatal.
- Does this mean no JavaScript?
- It means the first useful answer must not depend on it. After that, enhance freely for the people who can afford it. A page that works without script and improves with it serves everybody.
- How do you test this properly?
- Throttle to a slow connection with high latency, and use a mid range device rather than a development machine. Latency matters more than bandwidth for perceived speed, and most throttling profiles under model it.