PerformanceDesigning for the device you don't own

100%

Designing for the device you don't own.

Your laptop has a fast processor, plenty of memory and a cable to the office router. Most of the people paying for your product have none of those. A speed target only means something once it names the phone and the connection it is judged on, and a well-built page notices when it is running on something weaker still and quietly asks it for less.

Intermediate31 minUpdated 2 Oct 2026

Builds on Core Web Vitals as requirements.

The idea.

The page you test is not the page your users get. The difference is the hardware and the radio between them and you.

Cobbleway's front-end team works on recent laptops wired to the office network. When one of them opens the product page for a gravel wheelset, the main photo is up before they have let go of the trackpad. Meanwhile a rider standing at a trailhead with a two-year-old Android phone and two bars of signal opens the same URL and stares at a grey box for three and a half seconds. Both people loaded identical HTML, identical scripts and an identical photo. Only the machine and the connection changed.

Two different things went slower. The network part grows with the distance in time between the phone and the server: every round trip a cellular link takes is paid again for the connection, the HTML, then the files the HTML asks for. The processor part grows with how much script the page runs: a phone's cores are slower, it has less cache, and it turns its clock down when it gets warm, so the same JavaScript takes several times longer to parse and run. A laptop on fibre hides both bills at once.

So a performance requirement needs two more words than most teams write: on what, over what. The device and the network are picked from your own traffic, stand in for the slower part of it, get reproduced in the lab with throttling, and appear in the requirement itself. And because no single target device covers everyone, the page can also read a few hints at runtime (a data-saving preference, a rough memory size, a connection estimate) and ask a weak phone for less.

The same product page on three setups

  • Waiting on the network
  • Waiting on the CPU
The same product page on three setupsThe developer's laptop paints the wheelset photo in 0.8 s while the phone at Cobbleway's p75 needs 3.4 s, and the CPU share grows faster than the network share as the device gets weaker.01 s2 s3 s4 s5 sLaptop, fibreMid-range, 4GLow-end, weak 4G800 ms3.4 s5.9 sLCP good thresholdSetupTime to the main photo (LCP) (s)The same product page on three setupsThe developer's laptop paints the wheelset photo in 0.8 s while the phone at Cobbleway's p75 needs 3.4 s, and the CPU share grows faster than the network share as the device gets weaker.01 s2 s3 s4 s5 sLaptop, fibreMid-range, 4GLow-end, weak 4G800 ms3.4 s5.9 sLCP good thresholdSetupTime to the main photo (LCP) (s)
Cobbleway's illustrative numbers for one product page. The middle bar is the field p75 for phones (the figure Core Web Vitals as requirements works with); the outer bars are lab runs. The CPU gap between the two phones is in line with V8's published gap between median and low-end phones; the laptop's share is a lab run, not a V8 figure.
Data
SetupWaiting on the network (s)Waiting on the CPU (s)
Laptop, fibre0.60.2
Mid-range, 4G2.11.3
Low-end, weak 4G3.42.5
  • LCP good threshold: Time to the main photo (LCP) (s) = 2.5

Where the laptop lies

Phone share of Cobbleway visits
71%
28 days of the shop's own field data (illustrative)
Script time, median phone vs high-end
3-4x
V8's measurement on one large site; over 6x on a low-end phone
Round trip, office fibre vs the phone p75
~10 ms vs 160 ms
Cobbleway's lab baseline vs its CrUX phone RTT (illustrative)
No.AreaRequirementTarget / measure
01Metric and thresholdWhat is measured and the line it must stay under.
LCP ≤ 2.5 s
Thresholds come from Core Web Vitals as requirements.
02Percentile and segmentWhich share of which visits must meet it.
p75phones
Phones and desktops are judged apart; the phone segment is the hard one.
03Reference deviceThe phone the lab reproduces and the team owns physically.
4 GB mid-range Android
Chosen from traffic so the slowest quarter of visits is covered (in practice, below).
04Reference networkThe connection the lab reproduces.
Slow 4G150 ms RTT1.6 Mbps
Close to the field p75 round trip; Lighthouse's default mobile profile.
Was this section helpful?

How it works.

Two bills that grow on weaker hardware, where to find out what your users really hold, how the lab imitates it, and what a page can learn about the device at runtime.

1

The processor bill

Everything a page does after the bytes arrive runs on the device: parsing HTML and CSS, compiling and running JavaScript, working out layout, decoding images and painting. A recent laptop has a few large, fast cores, generous cache, and a fan. A mid-range phone has a mix of big and small cores, much less cache, and a thermal limit, so after a few seconds of heavy work it slows itself down. None of this shows up in a bundle size, which is why two pages with the same byte count can feel completely different on a phone.

Script is where the gap bites hardest, because a byte of JavaScript costs CPU time to compile and run on top of its download (the full pipeline is in What a byte of JavaScript costs). When the V8 team ran one large site's script on phones of three price levels, the median phone needed three to four times as long as the high-end one and the cheapest phone more than six times. Treat those ratios as an order of magnitude, not a constant: your own trace on your own reference phone is the number to plan with.

Memory matters in a quieter way. A phone with 2 or 3 GB of RAM keeps fewer tabs and decoded images alive, so a heavy page is more likely to be evicted and reloaded from scratch when the rider switches to the maps app and back. That is one reason a memory reading is useful as a hint even though it says nothing about clock speed.

2

The network bill is two numbers

A connection has a round-trip time (how long a tiny packet takes to get to the server and back) and a bandwidth (how many bytes per second flow once data is moving). Speed tests advertise bandwidth, but the start of a page load is dominated by round trips: looking up the name, opening TCP, agreeing TLS keys, asking for the HTML, then asking for whatever the HTML points to. Each step waits a full round trip before the next can begin. On office fibre that is about 10 ms per step; on a phone in a valley it is 150 ms or more, and a weak signal adds retransmissions on top.

The first five steps of a load, on 4G and on fibre

Scenario 1 of 2: As described.

Timeline as a list

The first five steps of a load, on 4G and on fibre: 3 lanes, from 0 ms to 1,500 ms.

  1. 0–150 ms · Connection (DNS, TCP, TLS) · DNS
  2. 0–450 ms · all lanes · window: 3 round trips before any request
  3. 150–300 ms · Connection (DNS, TCP, TLS) · TCP
  4. 300–450 ms · Connection (DNS, TCP, TLS) · TLS
  5. 450–700 ms · HTML document · GET + server
  6. 700–800 ms · HTML document · 20 KB
  7. 700 ms · HTML document · first byte
  8. 800–950 ms · CSS and the wheelset photo · request
  9. 950–1,380 ms · CSS and the wheelset photo · 86 KB (CSS 16 + photo 70)
  10. 1,380 ms · CSS and the wheelset photo · photo bytes in (ok)
Same page, same server, drawn on one 1.5 s axis. On Slow 4G (150 ms round trip, about 200 KB/s) the photo's bytes are in at about 1.38 s, and about half of that passes before the first byte of HTML arrives. Switch to the fibre tab: the same steps finish in about 0.16 s, so a developer never sees the waiting. Where each request spends its time is in Where a request's time goes.
3

Where the real distribution comes from

You cannot pick a reference device from a guess about "typical users". Two sources tell you what your visitors actually hold. Your own field data (real-user monitoring, covered in Measuring real users) can record the user agent, a memory reading, a core count and a connection estimate next to every timing, so you can sort visits from slowest to fastest setup. The Chrome UX Report (CrUX) gives the same view for any public origin, but only for eligible Chrome users and only along a few dimensions.

The rule for choosing is the percentile rule turned around. A target judged at p75 is decided by the slowest quarter of visits, so the reference device and network should sit at about the 25th percentile of capability: weaker than most of your traffic, not the median phone and certainly not the median laptop. Percentile maths in general is in Latency and percentiles.

What each source can tell you about devices and networks

SourceDevice informationNetwork informationBlind spots
Your own RUMUser agent, navigator.deviceMemory and hardwareConcurrency where the browser exposes themnavigator.connection (effectiveType, rtt, downlink) in Chromium; the timings themselves everywhereMemory and connection are missing on Safari and Firefox; you only see users who stayed long enough to send a beacon
CrUXForm factor only: phone, tablet or desktop, inferred from the user agentRound trip time, binned low (0-74 ms), medium (75-274 ms) and high (275 ms and above); the old effective connection type dimension was retired in February 2025Chrome users who opted in, not iOS or WebView; no device model or memory
Analytics and app-store statsDevice models and OS versions by shareUsually noneCounts users, not page loads; says nothing about speed
4

Lab profiles are approximations

Nobody can run every pull request on a drawer of real phones, so the lab imitates the reference setup on a fast machine. Network throttling adds latency and caps bandwidth; CPU throttling slows the page's processes by a multiplier. Both are approximations. A 4x slowdown on a fast laptop and a 4x slowdown on an older desktop end up at different places, and a request-level latency rule does not reproduce how a real radio wakes up, loses packets or switches cells.

Three habits fix most of this. Calibrate the CPU multiplier against your own machine instead of guessing: Lighthouse lets you derive it from its benchmark index, and since Chrome 134 DevTools can run a short benchmark and create low-tier and mid-tier mobile presets for that computer. Keep the network profile close to your field round trip (Lighthouse's default mobile profile, now called Slow 4G, is 150 ms and 1.6 Mbps). And check the lab against the field now and then on one real reference phone, because the field p75 is what the requirement is judged on.

Ways to imitate the reference setup

OptionWhat it doesGood forWatch out
Lighthouse simulated (default)Loads the page unthrottled, then models the load on 150 ms RTT, 1.6 Mbps down, 750 Kbps up and a 4x CPUFast, repeatable CI runsA model: it can be wrong for pages with unusual request chains
DevTools network presetsAdds latency and caps throughput per request in the browserSeeing the waterfall by hand while debuggingRequest-level, so it misses packet loss and connection effects
DevTools calibrated CPU presetsA one-off benchmark of your machine produces low-tier and mid-tier mobile multipliersProfiling script and rendering cost as a phone would feel itSpecific to the machine that ran the calibration
Packet-level throttlingShapes traffic at the OS or network levelThe most faithful network imitationMore set-up, more run-to-run variance
A real reference phoneThe actual device over a real or shaped connectionCalibrating everything above; spot checks before a launchSlow to run, hard to automate at scale
5

Signals a page can read at runtime

A reference device fixes what you design and test for. It does not stop a rider with a 2 GB phone from showing up. Adaptive loading closes that gap: the page, or the server, reads a few coarse hints about this particular visit and leaves out or postpones the heaviest optional parts. Every hint is deliberately vague, and most exist only in Chromium-based browsers, so each one is something to act on when present, never something to require.

The hints, what they mean and where they exist (October 2026)

SignalWhat it tells youWhere it worksPrivacy and accuracy
Save-Data: on (request header)The user switched on a reduced-data setting in the browser or the systemChromium-based browsers, on the first request without the server asking; not Safari or FirefoxLow entropy. An explicit choice, so honour it; add Vary: Save-Data to responses that change
navigator.connection.saveDataThe same preference, readable from scriptChromium onlySame as the header
navigator.connection.effectiveTypeslow-2g, 2g, 3g or 4g, estimated from recently observed round trips and throughputChromium only, in windows and workers, with a change event4g covers every link under a 270 ms round trip with more than 700 kbps down, so it cannot tell good 4G from fibre
navigator.connection.rtt / downlinkThe estimates behind effectiveType, in ms and MbpsChromium onlyRounded (25 ms, 25 kbps steps) to blunt fingerprinting
navigator.deviceMemoryApproximate RAM in GiB, as a power of twoChromium only, HTTPS onlyClamped to bounds each browser sets and has changed over time; never an exact size
navigator.hardwareConcurrencyLogical processors available for threadsEvery major browserMay be lower than the real count; says nothing about how fast each core is
ECT, RTT, Downlink, Sec-CH-Device-Memory (client hints)The values above, sent as request headersChromium only, after the server asks with Accept-CHNot on the very first request unless Critical-CH triggers a retry; varying on them hurts caching
@media (prefers-reduced-data: reduce)A data-saving preference for CSSSpecified but shipped in no browserDo not rely on it yet

Reading the hints with safe defaults

// Cobbleway decides once per page view how much optional weight to load.
// Every signal can be missing; missing means "no evidence", not "weak".
export function readLoadHints() {
  const conn = navigator.connection;           // undefined in Safari and Firefox
  const memory = navigator.deviceMemory;       // undefined outside Chromium or over HTTP
  const cores = navigator.hardwareConcurrency || 0;

  const saveData = conn?.saveData === true;
  const slowNetwork = conn !== undefined &&
    ['slow-2g', '2g', '3g'].includes(conn.effectiveType);
  const weakDevice = (memory !== undefined && memory <= 2) ||
    (cores > 0 && cores <= 2);

  return {
    saveData,                                  // a choice: always honour it
    lite: saveData || slowNetwork || weakDevice,
    reported: conn !== undefined || memory !== undefined,
  };
}

let hints = readLoadHints();
navigator.connection?.addEventListener('change', () => {
  hints = readLoadHints();                     // affects what has not started yet
});
# First response: ask for the hints on later requests
HTTP/1.1 200 OK
Accept-CH: ECT, Sec-CH-Device-Memory
Vary: Save-Data
Content-Type: text/html

# A later image request from a phone with data saving on
GET /img/wheelset-hero.avif HTTP/1.1
Host: shop.cobbleway.example
Save-Data: on
ECT: 3g
Sec-CH-Device-Memory: 2

The hints feed a decision about optional weight, never about what a visitor is allowed to do. The rule that keeps adaptive loading honest is to degrade a feature, not remove it: a lighter version stays one tap away, a preference the user stated wins over any guess, and a change of connection halfway through only affects work that has not started. The machine below is the life of one heavy feature on a page under that rule.

One optional heavy feature during a page view

One optional heavy feature during a page view. 5 states, 7 transitions. The table below lists them.
One optional heavy feature during a page view5 states, 7 transitions. The table below lists them.

hints read [no saving or weak signal]

hints read [saveData or slow net or ≤ 2 GB]

connection change [now 2g and not started]

near viewport / fetch script and assets

rider taps the button / fetch script and assets

loaded / swap stand-in for feature

error or timeout / keep stand-in, offer retry

Reading hints

Full

Lite (light stand-in shown)

Loading the feature

Ready

3 steps. Nothing is reported as weak, so the page behaves as designed.

Notice that every path from Lite can still reach Ready: the rider can always ask for the full version. A failure falls back to the light version rather than to an empty box.

Transitions of One optional heavy feature during a page view
From → ToEventGuardAction
Reading hints → Fullhints readno saving or weak signal
Reading hints → Lite (light stand-in shown)hints readsaveData or slow net or ≤ 2 GB
Full → Lite (light stand-in shown)connection changenow 2g and not started
Full → Loading the featurenear viewportfetch script and assets
Lite (light stand-in shown) → Loading the featurerider taps the buttonfetch script and assets
Loading the feature → Readyloadedswap stand-in for feature
Loading the feature → Lite (light stand-in shown)error or timeoutkeep stand-in, offer retry
Reading hintsstart
Runs once, before any optional request
Full
The feature will load when it scrolls near the viewport
Lite (light stand-in shown)
A static stand-in plus a button that names the cost
Readyend
Was this section helpful?

In practice.

Cobbleway picks its reference phone from its own traffic, writes it into the requirement, and builds a lighter wheelset page for riders who save data or carry a weak phone.

1

Picking Cobbleway's reference phone

The team starts from 28 days of its own field data. Seven visits in ten come from phones, so the phone segment is the one the requirement must hold for. Safari does not report memory, so iPhone visits are placed using the model mix from the shop's analytics; every iPhone model Cobbleway sees is faster than its 4 GB Android tier, which puts them all on the fast side of the line. Then the Android visits are sorted by reported memory, slowest first, until a quarter of phone visits is covered.

Where the slowest quarter of phone visits ends

Assumptions
Android share of phone visits
62%The other 38% are iPhones; illustrative
Android visits reporting 2 GB or less
9%
Android visits reporting 4 GB
34%
CrUX phone round trip at p75
160 msIn the medium bin (75-274 ms); illustrative
Lighthouse Slow 4G round trip
150 msCited
Working
  1. Phone visits on 2 GB or less62% × 9%5.6%from Android share of phone visits and Android visits reporting 2 GB or less
  2. Phone visits on 4 GB62% × 34%21.1%from Android share of phone visits and Android visits reporting 4 GB
  3. Slowest tiers together5.6% + 21.1%26.7%from Phone visits on 2 GB or less and Phone visits on 4 GB · The 25th percentile of capability falls inside the 4 GB tier
  4. Lab round trip vs field p75150 ÷ 160within 7%from CrUX phone round trip at p75 and Lighthouse Slow 4G round trip · Slow 4G is a fair lab stand-in
What it means
  • The reference phone is a 4 GB, 8-core Android from 2022, the most common model in that tier. The team buys two and keeps them charged in the office.
  • The 2 GB phones (5.6% of phone visits) are the floor: the shop must work on them, and adaptive loading is aimed at them, but the p75 target is not set by them.
  • Lighthouse's default mobile profile already matches the field round trip, so the CI profile stays as it is; only the CPU multiplier is recalibrated on the CI machine.
No.AreaRequirementTarget / measure
01Reference deviceLab runs, profiling and pre-launch checks use this phone or a calibrated imitation of it.
4 GB8-core Android (2022)
Re-checked every quarter against the field mix; the slowest-quarter line moves as riders upgrade.
02Reference networkCI and manual tests run on this profile.
Slow 4G150 ms RTT1.6 Mbps down
Field phone RTT p75 is 160 ms.
03Lab CPUThe CI machine's CPU is slowed to the reference phone's speed.
calibrated mid-tier preset
Recalibrated whenever the CI hardware changes.
04Floor deviceEvery task (browse, filter, add to basket, pay) works; speed targets do not apply.
2 GB Android3g effective type
Adaptive loading exists for this group.
05Judged onThe field p75 for phone visits, from RUM and CrUX.
field p75phones
Lab results warn early; the field decides. Thresholds live in Core Web Vitals as requirements.
2

A lighter wheelset page

Cobbleway's wheelset pages carry the heaviest optional feature in the shop: a 3D viewer that lets a rider turn the wheel and inspect the hub. Its script and model weigh 4.2 MB, and on a 2 GB phone it competes for memory with everything else. The six gallery photos add about 1.1 MB more at full quality. None of that is needed to choose a hub fitting and add the wheels to the basket.

So the page has two weights. The full page is what the reference phone gets. The light page swaps the viewer for its first photo and a button that says what pressing it will cost, and serves three gallery photos at lower quality. Everything a rider can do on one, they can do on the other.

The same product page for two riders

Same HTML route, same prices, same buttons. The 8 GB phone queues the viewer for when the gallery is in view and loads six photos at full quality (about 5.3 MB in all); the data-saving phone loads three lighter photos (about 210 KB) and no viewer.

Two riders, one URL. 8 GB phone on 4G, no data saving: Store “Cobbleway”, showing the product view. Cart button “Basket” with badge 0 (its accessible name says “Cart, 0 items”, not the number alone). Product (showing) “Ridgeline G30 gravel wheelset” by “700c · tubeless ready · 1,540 g the pair”: rating 4.6 (“212 reviews”); price £389.00. Gallery: image 1 of 6 (“3D view: drag to turn the wheel”); thumbnails beside it. Hub fitting (tiles, a radio group): Shimano HG, SRAM XDR, Campagnolo N3W. Buttons: “Add to basket”. Delivery: “Free delivery over £50 · arrives Thu 8 Oct”. Folded sections: Specs, Fitting guide, Reviews. Note on gallery: 3D viewer + 6 photos ≈ 5.3 MB 2 GB phone, data saving on: Store “Cobbleway”, showing the product view. Cart button “Basket” with badge 0 (its accessible name says “Cart, 0 items”, not the number alone). Product (showing) “Ridgeline G30 gravel wheelset” by “700c · tubeless ready · 1,540 g the pair”: rating 4.6 (“212 reviews”); price £389.00. Gallery: image 1 of 3 (“Side view of the wheel (lighter photo)”); thumbnails beside it. Hub fitting (tiles, a radio group): Shimano HG, SRAM XDR, Campagnolo N3W. Buttons: “Add to basket”, “3D view · 4.2 MB”. Delivery: “Free delivery over £50 · arrives Thu 8 Oct”. Folded sections: Specs, Fitting guide, Reviews. Note on gallery: saveData: true · 3 photos ≈ 210 KB

  1. Heavy on capable phones, light under data saving
  2. Same buttons; the light page adds an opt-in with its size
3

Who decides, the server or the page

Some choices have to be made before the page's script runs. The HTML decides which image URLs the browser starts fetching, and by the time JavaScript could change them the full-quality photos are already on the way. In the Chromium-based browsers that send it, Save-Data is the one hint that arrives on the very first request without being asked for, so Cobbleway's server uses it for the HTML and the images. The other hints reach the server only after it has asked for them with Accept-CH, and only from Chromium browsers, so decisions about optional features stay in the page, where load-hints.js reads them.

A data-saving visit to the wheelset page

A data-saving visit to the wheelset page, as an ordered list of steps:
A data-saving visit to the wheelset page8 steps between Rider's phone, Cobbleway server, Image service (same origin). The steps are listed as text after the diagram.Image service (same origin)Cobbleway serverRider's phoneOnly Save-Data is known on this first request; memory and connection hints come later, if at allload-hints.js: saveData true, so the 3D viewer is not requestedGET /p/ridgeline-g30 · Save-Data: on1light HTML (3 photo URLs, no viewer tag) · Accept-CH: ECT, Sec-CH-Device-Memory · Vary: Save-Data2GET /img/wheelset-1.avif · Save-Data: on · ECT: 3g · Sec-CH-Device-Memory: 2370 KB lower-quality photo · Vary: Save-Data4Rider taps the 3D view button: GET /3d/ridgeline-g30.glb54.2 MB model and viewer script6
  1. Rider's phone → Cobbleway server: GET /p/ridgeline-g30 · Save-Data: on
  2. Note over Cobbleway server: Only Save-Data is known on this first request; memory and connection hints come later, if at all
  3. Cobbleway server → Rider's phone (reply): light HTML (3 photo URLs, no viewer tag) · Accept-CH: ECT, Sec-CH-Device-Memory · Vary: Save-Data
  4. Rider's phone → Image service (same origin): GET /img/wheelset-1.avif · Save-Data: on · ECT: 3g · Sec-CH-Device-Memory: 2
  5. Image service (same origin) → Rider's phone (reply): 70 KB lower-quality photo · Vary: Save-Data
  6. Note over Rider's phone: load-hints.js: saveData true, so the 3D viewer is not requested
  7. Rider's phone → Cobbleway server: Rider taps the 3D view button: GET /3d/ridgeline-g30.glb
  8. Cobbleway server → Rider's phone (reply): 4.2 MB model and viewer script
01
Where Cobbleway makes the adaptive choice
Chosen:Both: the server on Save-Data for HTML and images, the page on script hints for optional features
  • Pro:The first response is already light for riders who asked for it
  • Pro:Optional features use every hint the browser offers, including the change event
  • Pro:Only one cache dimension (Save-Data), which has two values
Downside we accept:
  • Con:Two places hold adaptive logic and must agree
  • Con:The server only sees the explicit preference, not a weak device
Ruled out:Server only, on client hints (ECT, memory) as well

Hints other than Save-Data are missing on the first request unless Critical-CH forces a retry; Varying on fast-changing network hints splits the cache into many copies; Chromium only, so every other browser gets the default anyway

Ruled out:Page only, in JavaScript

Images named in the HTML are already downloading before script runs; The decision waits for the script, which is slowest on exactly the phones it is meant to help

4

Saying it in an interview

Q1
ClarifyThe interviewer says: the product page must be fast. What do you ask before anything else?
Fast for whom: which share of traffic is on phones, which markets, and what connection those users typically have. Then propose the shape of the target: a Core Web Vital at p75 for the phone segment, judged in the field, with a named reference phone and network for the lab. Say out loud that your laptop is not the target.
Q2
RequirementHow do you write the non-functional requirement for the device and network?
Name a reference device picked so the slowest quarter of visits is covered (for example a 4 GB mid-range Android), a lab network close to the field round trip (Slow 4G, 150 ms), a calibrated CPU slowdown, and a floor device on which every task must still work even if speed targets do not apply.
Q3
DesignWhere does this show up in the design, beyond the requirement line?
Optional heavy features (3D viewers, autoplaying video, big carousels) load on demand or near the viewport, and under Save-Data or weak-device hints they become a stand-in plus an opt-in button. Images come in sizes the device needs. The server honours Save-Data with Vary: Save-Data; the page reads the script hints. The default path, with no hints, must already meet the target on the reference phone.
Q4
Follow-up"Most of our users are on iPhones, which report none of these hints. Is adaptive loading pointless?"
No, but it is a bonus, not the plan. The plan is a default page that meets the target on the reference device, plus user-visible choices (a data-saving toggle in the shop's settings, opt-in buttons) that work in every browser. The hints only move Chromium visitors to the lighter path sooner.

System flows that use a reference device and adaptive loading

FlowWhere it mattersWhat our design for it adapts
amazon/product-detail-pageA large image gallery, zoom and spin views on a phone over mobile dataGallery image quality and count; zoom and 360 views load on request
amazon/product-listingDozens of thumbnails in a grid on a mid-range phoneThumbnail quality and how far ahead the next page is prefetched
airbnb/listing-pageA photo tour and a map above the foldPhoto sizes; the interactive map waits for a tap on weak devices
netflix/resume-and-previewsAutoplaying previews on a TV-like home screen in a browserPreviews stay as still artwork under data saving or a slow connection
instagram/infinite-photo-feedEndless images and video in a feedPrefetch depth and video autoplay under data saving
facebook/news-feedA long feed mixing text, images and videoAutoplay off and lighter media under data saving; same posts either way
Was this section helpful?

Trade-offs.

A reference device is cheap to adopt and easy to forget; adaptive loading is powerful and easy to overdo.

What adaptive loading buys and what it costs

It buys
Riders who asked to save data get a page that respects it from the first byte
Weak phones skip the features most likely to freeze or crash themMemory-heavy viewers, autoplaying video, large carousels
The reference-phone target stays reachable without removing features for everyone
It costs
Two versions of each adapted feature to build, test and keep in stepThe light path is the one nobody on the team sees by default
Most hints exist only in Chromium, so Safari and Firefox always get the default
Each hint is another bit of identifying informationThe specs round and clamp values for this reason
Responses that vary on hints are harder to cache

How it goes wrong

PitfallWhat happensInstead
The reference device driftsThe phone chosen two years ago is now faster than most of the slowest quarter, so the lab passes while the field p75 slipsRe-derive it from field data on a schedule (Cobbleway: every quarter) and when the field and lab disagree
Missing hint read as weakEvery iPhone and Firefox user gets the light page, including the fastest phones in your trafficTreat a missing value as unknown and take the default path
The light page becomes a lesser productLow-end users lose search filters, reviews or checkout options and convert worse, which looks like proof they are less valuableAdapt only optional weight; keep every task, and offer an opt-in to the heavy version
Logging raw hints for analyticsMemory, cores, connection and user agent together narrow a visitor downRecord coarse buckets next to timings; never combine them into an identifier
Varying the cache on network hintsA response stored per ECT and RTT value is close to uncacheable at the CDNVary on Save-Data only (two values) and adapt the rest in the page
Trusting effectiveType for the fast end4g covers everything below a 270 ms round trip and above 700 kbps, so a slow 4G link and fibre look the sameUse it to spot weak connections; measure fast ones in the field instead
A light path nobody testsA bug in the data-saving branch ships unnoticed for weeksRun CI on both paths, and give the team a toggle to force the light page
01
What the page does when the browser reports nothing
Chosen:The default page, already fast on the reference phone, with heavy extras loaded on demand or near the viewport
  • Pro:Works the same in every browser
  • Pro:The requirement is met without any hint
  • Pro:Hints only make Chromium's weakest visits lighter still
Downside we accept:
  • Con:The default must be disciplined; adaptive loading cannot rescue a heavy default
Ruled out:The light page for everyone the browser does not describe

Downgrades every Safari and Firefox visitor, including the fastest phones; Makes the light path the main path by accident

Ruled out:Guess the device from the user agent string

Reduced user agents no longer name the model reliably; A model list goes stale and needs constant upkeep

What this topic owns

This topic
Naming the device and network in a performance requirement
Choosing the reference from field data, and the floor device
Lab throttling profiles and their limits
Runtime hints (Save-Data, Network Information, deviceMemory, hardwareConcurrency, client hints) and adaptive loading
Elsewhere
The thresholds and the p75 ruleCore Web Vitals as requirements
Turning targets into byte and time limits in CIPerformance budgets
Why script costs more on a slow CPUWhat a byte of JavaScript costs
Image sizes per screen and video behaviour under data savingmedia-rendering topics
Collecting field data and dashboardsMeasuring real users
Screen sizes, input types and browser supportBrowser and device support
Was this section helpful?
Builds on this
Performance budgets
Read next