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.

Client hints opt-in and image request Sequence showing a server opting in to client hints and the browser sending width and DPR on later image requests. Client hints opt-in and image request Browser Site Image CDN GET /page Accept-CH: Sec-CH-DPR, Sec-CH-Width GET /img/a.jpg + DPR 3, Width 1080 1080px AVIF + Content-DPR, Vary

Rapid Diagnosis

  • Check whether hints arrive. Log Sec-CH-DPR and Sec-CH-Width on image requests; absent headers mean no opt-in or an unsupported browser.
  • Check Accept-CH on the HTML response, and Permissions-Policy delegation 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
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

html
<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

javascript
// 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.

Client hints vs srcset for image sizing Comparison of srcset markup and client hints on support, accuracy, markup and caching. Client hints vs srcset for image sizing Aspect srcset + sizes Client hints Browser support universal Chromium-based Markup long candidate lists one URL Width precision nearest candidate any step Caching one URL per size needs Vary or keyed steps First visit works immediately needs prior opt-in

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.

CDN hit ratio by caching strategy for hinted images Bar chart comparing CDN cache hit ratio for raw Vary on hint headers versus normalised width steps in the cache key. CDN hit ratio by caching strategy for hinted images Vary: Sec-CH-Width (raw) 41% 320px steps in cache key 95% 160px steps in cache key 92%

Common Mistakes

  • Omitting sizes. Sec-CH-Width is not sent without it.
  • Forgetting delegation. Third-party image origins receive no hints without Permissions-Policy.
  • Raw Vary on 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.