Short answer
Design for a first screen under roughly 200 KB, stream long answers instead of waiting for them, and cache anything that does not change per user. Assume the connection will drop mid-request, and make that a handled case rather than an error screen.
The constraint that shapes everything
Latency, not bandwidth, is what makes a connection feel broken. A page that needs six sequential round trips before it shows anything will feel slow on mobile data no matter how small the files are. Every dependency that must resolve before first paint costs a full round trip.
So the first question about any screen is not "how big is it" but "how many things must happen in order before the user sees something".
Payload budgets we work to
| Asset | Budget | Why |
|---|---|---|
| First screen, total | ≈ 200 KB | Roughly one second of usable content on a weak connection |
| Fonts | 1 family, 2 weights | Each extra weight is a separate blocking download |
| Hero image | < 120 KB | Served responsively; phones should never fetch desktop sizes |
| Video | Not on first load | Poster image first; fetch video only if the connection allows |
These are budgets, not laws. The point is that someone decided a number in advance, so exceeding it is a conscious trade rather than an accident.
Stream, do not wait
AI responses are slow by nature, a long answer can take several seconds to generate. Waiting for the whole thing before showing anything turns a five second generation into a five second blank screen. Streaming tokens as they arrive turns it into an answer that starts in under a second and finishes at the same time.
Nothing about the total duration changed. The experience is completely different.
Respect the signals the browser gives you
Browsers expose more than most sites use:
navigator.connection.saveData: the user has explicitly asked for less data. Honour it.effectiveType, reports2g,3g,4g. Enough to decide whether to auto-load heavy media.prefers-reduced-motion, an accessibility setting, and conveniently also a reason to skip decorative video.
On this site the hero video is attached only after those checks pass. Users on Save-Data or a 2G/3G connection get a poster image and download none of it.
Assume the connection drops
On mobile data, requests fail routinely, a tunnel, a lift, a cell handover. The difference between a tool people trust and one they abandon is what happens next. Keep the user's input if a submit fails. Make retry the obvious action. Never clear a form because the network blinked.
What this is not
This is not an argument for ugly, minimal websites. It is an argument for deciding what loads first. A heavy page that shows useful content immediately and loads the rest afterwards is fine. A light page that shows nothing for four seconds is not.
Frequently asked questions
How do you optimise a web app for slow mobile data?
Budget the first screen to around 200 KB, minimise the number of sequential requests before first paint, stream long responses instead of buffering them, serve responsive images, and defer video behind a connection check.
What is a good page weight for a first load?
Around 200 KB for everything needed to show useful content. Beyond raw size, the number of round trips that must complete before first paint usually matters more on high-latency connections.
Should a website autoplay video on mobile data?
Not without checking. Read navigator.connection.saveData and effectiveType, and respect prefers-reduced-motion. Users on constrained connections should get a poster image and download nothing further.