Using Client Hints for Image Width and DPR
This guide extends Image CDNs and fetchpriority, part of Image & Media Optimization. Responsive images normally put the size decision in markup: srcset lists candidates and sizes describes layout, and the browser picks. Client hints flip that around. After the server opts in, the browser sends request headers describing the device — Sec-CH-DPR (device pixel ratio), Sec-CH-Viewport-Width, and for images with a sizes attribute, Sec-CH-Width (the intended display width in physical pixels) — and the server or image CDN returns an image of exactly the right size from a single URL.
Client hints can simplify markup and improve sizing accuracy, but support is limited to Chromium-based browsers, they require an explicit opt-in, and they interact with caching through Vary. They work best as an enhancement on top of correct srcset markup, or for image CDNs that already understand them.
Rapid Diagnosis
- Check whether hints arrive. Log
Sec-CH-DPRandSec-CH-Widthon image requests; absent headers mean no opt-in or an unsupported browser. - Check
Accept-CHon the HTML response, andPermissions-Policydelegation if images come from a different origin. - Check your audience's browsers. Safari and Firefox do not send these hints, so a fallback path must remain.
- Check cache keys. Responses that vary by hints must be cached separately per hint value, or normalised.
Root Cause Analysis: Why Hints Help
1. Markup complexity. Long srcset lists across many templates are tedious and error-prone.
2. Inaccurate sizes. Wrong sizes values cause over- or under-sized downloads; Sec-CH-Width is computed from the same sizes, but the server can round precisely.
3. Fixed candidate sets. srcset offers a handful of widths; hints let the server choose any width (rounded to a step for caching).
4. Unknown DPR on the server. Without hints, servers cannot tailor quality or size to pixel density.
Step-by-Step Resolution
1. Opt in on the document response
HTTP/1.1 200 OK
Accept-CH: Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width
Permissions-Policy: ch-dpr=(self "https://img.example.com"), ch-width=(self "https://img.example.com"), ch-viewport-width=(self "https://img.example.com")
The Permissions-Policy delegation lets the browser send the hints to the third-party image origin. Hints arrive from the next request after opt-in; the very first navigation's subresources may already include them when the opt-in is on that HTML response.
2. Keep sizes on the image
<img src="https://img.example.com/products/p42.jpg" sizes="(max-width: 700px) 100vw, 700px"
width="1400" height="1050" alt="Leather boot">
<!-- trade-off: without srcset, browsers that do not send hints receive one
default size; keep a srcset as fallback where Safari/Firefox share is high. -->
Sec-CH-Width is only sent for images with a sizes attribute.
3. Resize on the server and set Vary
// Edge function sketch: round hinted width to a step and select a variant.
const w = Number(request.headers.get('sec-ch-width')) || 800;
const step = Math.min(2400, Math.ceil(w / 160) * 160);
const res = await fetch(`${ORIGIN}/rs:fit:${step}:0/plain/${path}`);
const out = new Response(res.body, res);
out.headers.set('Vary', 'Sec-CH-Width, Accept');
// trade-off: Vary on raw hint values fragments the cache into many entries; round
// to steps and include the rounded step in the cache key, not the raw header.
4. Combine with srcset for full coverage
A robust pattern keeps srcset + sizes for all browsers, with an image CDN that also honours hints when present, so Chromium users get tighter sizing and others get the markup's choice.
Verification
In Chrome DevTools, select an image request and confirm the Sec-CH-Width and Sec-CH-DPR request headers. The response should be close to the hinted width, carry Vary (or a cache key that includes the rounded width), and differ between a phone emulation at DPR 3 and a desktop at DPR 1. In Safari, confirm the fallback path still delivers a reasonable size.
Worked Example: A Travel Booking Site
A travel site had 40 templates, each with hand-written srcset lists that had drifted from the actual layouts; audits found images 1.6x larger than needed on average. The team kept sizes in all templates (fixed against the real layouts), opted in to Sec-CH-DPR and Sec-CH-Width with delegation to their image CDN, and kept a short three-candidate srcset as a fallback. Chromium users (about 64% of traffic) received images rounded to 160px steps of their exact display width. Average image transfer per page view fell by 31% for Chromium sessions and 12% for others (thanks to the corrected sizes), and LCP p75 on Android improved by 280ms.
Caching Hint-Based Responses Safely
Every distinct value of a varied header creates a new cache entry. Raw Sec-CH-Width values can be any integer, so Vary: Sec-CH-Width on its own can make the CDN hit rate collapse. The solution is to normalise before caching: compute a rounded width step (and a format from Accept) at the edge, put those into the cache key, and strip Vary from the response cached at the edge, or keep a Vary that the CDN treats with normalisation. Choose steps that keep the number of variants per image small — 10 to 15 widths across the range is usually plenty. Browsers' own caches respect Vary as well, but they only ever see one device's hints, so this matters mostly for shared caches.
Common Mistakes
- Omitting
sizes.Sec-CH-Widthis not sent without it. - Forgetting delegation. Third-party image origins receive no hints without
Permissions-Policy. - Raw
Varyon hints. Cache fragmentation and low hit rates. - Dropping srcset entirely. Non-Chromium browsers get one size for every device.
Edge Cases
Legacy hint names. Older DPR, Width and Viewport-Width headers without the Sec-CH- prefix are deprecated; use the prefixed versions.
Critical-CH. The Critical-CH response header asks the browser to retry the request with hints if they were missing; it costs a round trip and is mostly useful for documents, not images.
Privacy budgets. Browsers limit high-entropy hints; DPR and width hints are low-entropy, but treat future changes as possible.
Preloads. <link rel="preload" as="image"> with imagesizes sends hints too; keep preload and image consistent so the same variant is used.
FAQ
Which browsers send image client hints?
Chromium-based browsers (Chrome, Edge, Opera, Samsung Internet). Safari and Firefox do not send them, so a fallback is required.
Do hints work on the first page load?
The opt-in comes from the HTML response, so subresources on that same page can include hints in supporting browsers. The very first HTML request itself does not include them unless Critical-CH triggers a retry.
Can I use hints without an image CDN?
Yes, with an edge function or server that reads the headers and serves resized images. Image CDNs and proxies like imgproxy often support them directly.
Should I still write srcset?
Yes, as long as a significant share of users have browsers without hint support. Hints then refine sizing in supporting browsers.
What is Content-DPR?
A response header that told the browser the served image's density for intrinsic sizing. It has been deprecated in browsers; set explicit width and height attributes on images instead.
Do client hints help LCP?
Indirectly — smaller, correctly sized LCP images download faster. Priority and discovery still matter more, so keep fetchpriority on the LCP image.
Related
- Self-hosting an image proxy with imgproxy — a server that can honour hints.
- Caching transformed images at the edge — cache keys for variants.
- Vary header pitfalls that destroy CDN hit rate — why raw Vary hurts.