[{"data":1,"prerenderedAt":1148},["ShallowReactive",2],{"content:\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr":3,"surroundings:\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr":1139},{"id":4,"title":5,"body":6,"description":1120,"extension":1121,"meta":1122,"navigation":1132,"path":1133,"seo":1134,"stem":1137,"__hash__":1138},"content\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr\u002Findex.md","Using Client Hints for Image Width and DPR",{"type":7,"value":8,"toc":1103},"minimark",[9,13,52,62,199,204,246,250,259,277,285,291,295,300,328,334,338,414,422,426,616,620,629,764,768,779,783,803,807,830,894,898,933,937,957,967,973,986,990,1002,1014,1023,1032,1048,1061,1065,1088,1093,1096,1099],[10,11,5],"h1",{"id":12},"using-client-hints-for-image-width-and-dpr",[14,15,16,17,22,23,27,28,32,33,36,37,40,41,44,45,47,48,51],"p",{},"This guide extends ",[18,19,21],"a",{"href":20},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002F","Image CDNs and fetchpriority",", part of ",[18,24,26],{"href":25},"\u002Fimage-media-optimization\u002F","Image & Media Optimization",". Responsive images normally put the size decision in markup: ",[29,30,31],"code",{},"srcset"," lists candidates and ",[29,34,35],{},"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 — ",[29,38,39],{},"Sec-CH-DPR"," (device pixel ratio), ",[29,42,43],{},"Sec-CH-Viewport-Width",", and for images with a ",[29,46,35],{}," attribute, ",[29,49,50],{},"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.",[14,53,54,55,58,59,61],{},"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 ",[29,56,57],{},"Vary",". They work best as an enhancement on top of correct ",[29,60,31],{}," markup, or for image CDNs that already understand them.",[14,63,64],{},[65,66,72,73,72,80,72,84,72,87,72,105,72,113,72,119,72,126,72,133,72,136,72,140,72,143,72,147,72,156,72,159,72,162,72,168,72,174,72,179,72,183,72,187,72,191,72,195,72],"svg",{"viewBox":67,"width":68,"role":69,"ariaLabel":70,"style":71},"0 0 760 290","100%","img","Sequence showing a server opting in to client hints and the browser sending width and DPR on later image requests.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[74,75],"rect",{"className":76,"x":78,"y":78,"width":68,"height":68,"fill":79},[77],"svg-canvas","0","#ffffff",[81,82,83],"title",{},"Client hints opt-in and image request",[85,86,70],"desc",{},[88,89,90],"defs",{},[91,92,99],"marker",{"id":93,"viewBox":94,"refX":95,"refY":96,"markerWidth":97,"markerHeight":97,"orient":98},"fa77cfc6af","0 0 10 10","9","5","7","auto-start-reverse",[100,101],"path",{"d":102,"fill":103,"style":104},"M0 0 L10 5 L0 10 z","currentColor","fill-opacity:0.7",[74,106],{"x":107,"y":107,"width":108,"height":109,"rx":110,"fill":111,"stroke":103,"style":112},"1","758","288","10","none","stroke-opacity:0.18",[114,115,83],"text",{"x":116,"y":117,"fill":103,"style":118},"28.0","34.0","font-size:16px;font-weight:700",[74,120],{"x":121,"y":122,"width":123,"height":117,"rx":124,"fill":103,"stroke":103,"style":125},"70.3","56.0","150.0","6","fill-opacity:0.06;stroke-opacity:0.4",[114,127,132],{"x":128,"y":129,"fill":103,"style":130,"textAnchor":131},"145.3","78.0","font-size:13px;font-weight:700","middle","Browser",[74,134],{"x":135,"y":122,"width":123,"height":117,"rx":124,"fill":103,"stroke":103,"style":125},"305.0",[114,137,139],{"x":138,"y":129,"fill":103,"style":130,"textAnchor":131},"380.0","Site",[74,141],{"x":142,"y":122,"width":123,"height":117,"rx":124,"fill":103,"stroke":103,"style":125},"539.7",[114,144,146],{"x":145,"y":129,"fill":103,"style":130,"textAnchor":131},"614.7","Image CDN",[148,149],"line",{"x1":128,"y1":150,"x2":128,"y2":151,"stroke":103,"strokeWidth":152,"strokeDashArray":153,"style":155},"90.0","268.0","1.5",[154,154],"4","stroke-opacity:0.35",[148,157],{"x1":138,"y1":150,"x2":138,"y2":151,"stroke":103,"strokeWidth":152,"strokeDashArray":158,"style":155},[154,154],[148,160],{"x1":145,"y1":150,"x2":145,"y2":151,"stroke":103,"strokeWidth":152,"strokeDashArray":161,"style":155},[154,154],[148,163],{"x1":128,"y1":164,"x2":165,"y2":164,"stroke":103,"strokeWidth":152,"style":166,"markerEnd":167},"124.0","378.0","stroke-opacity:0.6","url(#fa77cfc6af)",[114,169,173],{"x":170,"y":171,"fill":103,"style":172,"textAnchor":131},"262.7","117.0","font-size:12px","GET \u002Fpage",[148,175],{"x1":138,"y1":176,"x2":177,"y2":176,"stroke":103,"strokeWidth":152,"strokeDashArray":178,"style":166,"markerEnd":167},"164.0","147.3",[96,154],[114,180,182],{"x":170,"y":181,"fill":103,"style":172,"textAnchor":131},"157.0","Accept-CH: Sec-CH-DPR, Sec-CH-Width",[148,184],{"x1":128,"y1":185,"x2":186,"y2":185,"stroke":103,"strokeWidth":152,"style":166,"markerEnd":167},"204.0","612.7",[114,188,190],{"x":138,"y":189,"fill":103,"style":172,"textAnchor":131},"197.0","GET \u002Fimg\u002Fa.jpg + DPR 3, Width 1080",[148,192],{"x1":145,"y1":193,"x2":177,"y2":193,"stroke":103,"strokeWidth":152,"strokeDashArray":194,"style":166,"markerEnd":167},"244.0",[96,154],[114,196,198],{"x":138,"y":197,"fill":103,"style":172,"textAnchor":131},"237.0","1080px AVIF + Content-DPR, Vary",[200,201,203],"h2",{"id":202},"rapid-diagnosis","Rapid Diagnosis",[205,206,207,221,234,240],"ul",{},[208,209,210,214,215,217,218,220],"li",{},[211,212,213],"strong",{},"Check whether hints arrive."," Log ",[29,216,39],{}," and ",[29,219,50],{}," on image requests; absent headers mean no opt-in or an unsupported browser.",[208,222,223,229,230,233],{},[211,224,225,226],{},"Check ",[29,227,228],{},"Accept-CH"," on the HTML response, and ",[29,231,232],{},"Permissions-Policy"," delegation if images come from a different origin.",[208,235,236,239],{},[211,237,238],{},"Check your audience's browsers."," Safari and Firefox do not send these hints, so a fallback path must remain.",[208,241,242,245],{},[211,243,244],{},"Check cache keys."," Responses that vary by hints must be cached separately per hint value, or normalised.",[200,247,249],{"id":248},"root-cause-analysis-why-hints-help","Root Cause Analysis: Why Hints Help",[14,251,252,255,256,258],{},[211,253,254],{},"1. Markup complexity."," Long ",[29,257,31],{}," lists across many templates are tedious and error-prone.",[14,260,261,267,268,270,271,273,274,276],{},[211,262,263,264,266],{},"2. Inaccurate ",[29,265,35],{},"."," Wrong ",[29,269,35],{}," values cause over- or under-sized downloads; ",[29,272,50],{}," is computed from the same ",[29,275,35],{},", but the server can round precisely.",[14,278,279,72,282,284],{},[211,280,281],{},"3. Fixed candidate sets.",[29,283,31],{}," offers a handful of widths; hints let the server choose any width (rounded to a step for caching).",[14,286,287,290],{},[211,288,289],{},"4. Unknown DPR on the server."," Without hints, servers cannot tailor quality or size to pixel density.",[200,292,294],{"id":293},"step-by-step-resolution","Step-by-Step Resolution",[296,297,299],"h3",{"id":298},"_1-opt-in-on-the-document-response","1. Opt in on the document response",[301,302,307],"pre",{"className":303,"code":304,"language":305,"meta":306,"style":306},"language-http shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","HTTP\u002F1.1 200 OK\nAccept-CH: Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width\nPermissions-Policy: ch-dpr=(self \"https:\u002F\u002Fimg.example.com\"), ch-width=(self \"https:\u002F\u002Fimg.example.com\"), ch-viewport-width=(self \"https:\u002F\u002Fimg.example.com\")\n","http","",[29,308,309,316,322],{"__ignoreMap":306},[310,311,313],"span",{"class":148,"line":312},1,[310,314,315],{},"HTTP\u002F1.1 200 OK\n",[310,317,319],{"class":148,"line":318},2,[310,320,321],{},"Accept-CH: Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width\n",[310,323,325],{"class":148,"line":324},3,[310,326,327],{},"Permissions-Policy: ch-dpr=(self \"https:\u002F\u002Fimg.example.com\"), ch-width=(self \"https:\u002F\u002Fimg.example.com\"), ch-viewport-width=(self \"https:\u002F\u002Fimg.example.com\")\n",[14,329,330,331,333],{},"The ",[29,332,232],{}," 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.",[296,335,337],{"id":336},"_2-keep-sizes-on-the-image","2. Keep sizes on the image",[301,339,343],{"className":340,"code":341,"language":342,"meta":306,"style":306},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u003Cimg src=\"https:\u002F\u002Fimg.example.com\u002Fproducts\u002Fp42.jpg\" sizes=\"(max-width: 700px) 100vw, 700px\"\n     width=\"1400\" height=\"1050\" alt=\"Leather boot\">\n\u003C!-- trade-off: without srcset, browsers that do not send hints receive one\n     default size; keep a srcset as fallback where Safari\u002FFirefox share is high. -->\n","html",[29,344,345,373,402,408],{"__ignoreMap":306},[310,346,347,351,354,358,361,365,368,370],{"class":148,"line":312},[310,348,350],{"class":349},"saISM","\u003C",[310,352,69],{"class":353},"sZBmE",[310,355,357],{"class":356},"sPXB4"," src",[310,359,360],{"class":349},"=",[310,362,364],{"class":363},"sZ8jY","\"https:\u002F\u002Fimg.example.com\u002Fproducts\u002Fp42.jpg\"",[310,366,367],{"class":356}," sizes",[310,369,360],{"class":349},[310,371,372],{"class":363},"\"(max-width: 700px) 100vw, 700px\"\n",[310,374,375,378,380,383,386,388,391,394,396,399],{"class":148,"line":318},[310,376,377],{"class":356},"     width",[310,379,360],{"class":349},[310,381,382],{"class":363},"\"1400\"",[310,384,385],{"class":356}," height",[310,387,360],{"class":349},[310,389,390],{"class":363},"\"1050\"",[310,392,393],{"class":356}," alt",[310,395,360],{"class":349},[310,397,398],{"class":363},"\"Leather boot\"",[310,400,401],{"class":349},">\n",[310,403,404],{"class":148,"line":324},[310,405,407],{"class":406},"sjfSM","\u003C!-- trade-off: without srcset, browsers that do not send hints receive one\n",[310,409,411],{"class":148,"line":410},4,[310,412,413],{"class":406},"     default size; keep a srcset as fallback where Safari\u002FFirefox share is high. -->\n",[14,415,416,418,419,421],{},[29,417,50],{}," is only sent for images with a ",[29,420,35],{}," attribute.",[296,423,425],{"id":424},"_3-resize-on-the-server-and-set-vary","3. Resize on the server and set Vary",[301,427,431],{"className":428,"code":429,"language":430,"meta":306,"style":306},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Edge function sketch: round hinted width to a step and select a variant.\nconst w = Number(request.headers.get('sec-ch-width')) || 800;\nconst step = Math.min(2400, Math.ceil(w \u002F 160) * 160);\nconst res = await fetch(`${ORIGIN}\u002Frs:fit:${step}:0\u002Fplain\u002F${path}`);\nconst out = new Response(res.body, res);\nout.headers.set('Vary', 'Sec-CH-Width, Accept');\n\u002F\u002F trade-off: Vary on raw hint values fragments the cache into many entries; round\n\u002F\u002F to steps and include the rounded step in the cache key, not the raw header.\n","javascript",[29,432,433,438,478,524,563,582,604,610],{"__ignoreMap":306},[310,434,435],{"class":148,"line":312},[310,436,437],{"class":406},"\u002F\u002F Edge function sketch: round hinted width to a step and select a variant.\n",[310,439,440,444,447,450,454,457,460,463,466,469,472,475],{"class":148,"line":318},[310,441,443],{"class":442},"sPARh","const",[310,445,446],{"class":356}," w",[310,448,449],{"class":442}," =",[310,451,453],{"class":452},"smZ65"," Number",[310,455,456],{"class":349},"(request.headers.",[310,458,459],{"class":452},"get",[310,461,462],{"class":349},"(",[310,464,465],{"class":363},"'sec-ch-width'",[310,467,468],{"class":349},")) ",[310,470,471],{"class":442},"||",[310,473,474],{"class":356}," 800",[310,476,477],{"class":349},";\n",[310,479,480,482,485,487,490,493,495,498,501,504,507,510,513,516,519,521],{"class":148,"line":324},[310,481,443],{"class":442},[310,483,484],{"class":356}," step",[310,486,449],{"class":442},[310,488,489],{"class":349}," Math.",[310,491,492],{"class":452},"min",[310,494,462],{"class":349},[310,496,497],{"class":356},"2400",[310,499,500],{"class":349},", Math.",[310,502,503],{"class":452},"ceil",[310,505,506],{"class":349},"(w ",[310,508,509],{"class":442},"\u002F",[310,511,512],{"class":356}," 160",[310,514,515],{"class":349},") ",[310,517,518],{"class":442},"*",[310,520,512],{"class":356},[310,522,523],{"class":349},");\n",[310,525,526,528,531,533,536,539,541,544,547,550,553,556,558,561],{"class":148,"line":410},[310,527,443],{"class":442},[310,529,530],{"class":356}," res",[310,532,449],{"class":442},[310,534,535],{"class":442}," await",[310,537,538],{"class":452}," fetch",[310,540,462],{"class":349},[310,542,543],{"class":363},"`${",[310,545,546],{"class":356},"ORIGIN",[310,548,549],{"class":363},"}\u002Frs:fit:${",[310,551,552],{"class":349},"step",[310,554,555],{"class":363},"}:0\u002Fplain\u002F${",[310,557,100],{"class":349},[310,559,560],{"class":363},"}`",[310,562,523],{"class":349},[310,564,566,568,571,573,576,579],{"class":148,"line":565},5,[310,567,443],{"class":442},[310,569,570],{"class":356}," out",[310,572,449],{"class":442},[310,574,575],{"class":442}," new",[310,577,578],{"class":452}," Response",[310,580,581],{"class":349},"(res.body, res);\n",[310,583,585,588,591,593,596,599,602],{"class":148,"line":584},6,[310,586,587],{"class":349},"out.headers.",[310,589,590],{"class":452},"set",[310,592,462],{"class":349},[310,594,595],{"class":363},"'Vary'",[310,597,598],{"class":349},", ",[310,600,601],{"class":363},"'Sec-CH-Width, Accept'",[310,603,523],{"class":349},[310,605,607],{"class":148,"line":606},7,[310,608,609],{"class":406},"\u002F\u002F trade-off: Vary on raw hint values fragments the cache into many entries; round\n",[310,611,613],{"class":148,"line":612},8,[310,614,615],{"class":406},"\u002F\u002F to steps and include the rounded step in the cache key, not the raw header.\n",[296,617,619],{"id":618},"_4-combine-with-srcset-for-full-coverage","4. Combine with srcset for full coverage",[14,621,622,623,625,626,628],{},"A robust pattern keeps ",[29,624,31],{}," + ",[29,627,35],{}," 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.",[14,630,631],{},[65,632,72,635,72,638,72,641,72,643,72,646,72,648,72,652,72,659,72,663,72,667,72,670,72,674,72,677,72,681,72,685,72,688,72,693,72,696,72,699,72,703,72,705,72,708,72,710,72,713,72,716,72,720,72,722,72,725,72,727,72,730,72,733,72,737,72,739,72,742,72,744,72,747,72,750,72,754,72,756,72,759,72,761,72],{"viewBox":633,"width":68,"role":69,"ariaLabel":634,"style":71},"0 0 760 258","Comparison of srcset markup and client hints on support, accuracy, markup and caching.",[74,636],{"className":637,"x":78,"y":78,"width":68,"height":68,"fill":79},[77],[81,639,640],{},"Client hints vs srcset for image sizing",[85,642,634],{},[74,644],{"x":107,"y":107,"width":108,"height":645,"rx":110,"fill":111,"stroke":103,"style":112},"256",[114,647,640],{"x":116,"y":117,"fill":103,"style":118},[74,649],{"x":116,"y":122,"width":650,"height":651,"rx":78,"fill":103,"stroke":103,"style":125},"116.2","30.0",[114,653,658],{"x":654,"y":655,"fill":103,"style":656,"textAnchor":657},"38.0","75.5","font-size:12.5px;font-weight:700","start","Aspect",[74,660],{"x":661,"y":122,"width":662,"height":651,"rx":78,"fill":103,"stroke":103,"style":125},"144.2","293.9",[114,664,666],{"x":665,"y":655,"fill":103,"style":656,"textAnchor":131},"291.2","srcset + sizes",[74,668],{"x":669,"y":122,"width":662,"height":651,"rx":78,"fill":103,"stroke":103,"style":125},"438.1",[114,671,673],{"x":672,"y":655,"fill":103,"style":656,"textAnchor":131},"585.1","Client hints",[74,675],{"x":116,"y":676,"width":650,"height":651,"rx":78,"fill":111,"stroke":103,"style":155},"86.0",[114,678,680],{"x":654,"y":679,"fill":103,"style":656,"textAnchor":657},"105.5","Browser support",[74,682],{"x":661,"y":676,"width":662,"height":651,"rx":78,"fill":683,"stroke":683,"style":684},"#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[114,686,687],{"x":665,"y":679,"fill":103,"style":172,"textAnchor":131},"universal",[74,689],{"x":669,"y":676,"width":662,"height":651,"rx":78,"fill":690,"stroke":691,"style":692},"#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[114,694,695],{"x":672,"y":679,"fill":103,"style":172,"textAnchor":131},"Chromium-based",[74,697],{"x":116,"y":698,"width":650,"height":651,"rx":78,"fill":111,"stroke":103,"style":155},"116.0",[114,700,702],{"x":654,"y":701,"fill":103,"style":656,"textAnchor":657},"135.5","Markup",[74,704],{"x":661,"y":698,"width":662,"height":651,"rx":78,"fill":690,"stroke":691,"style":692},[114,706,707],{"x":665,"y":701,"fill":103,"style":172,"textAnchor":131},"long candidate lists",[74,709],{"x":669,"y":698,"width":662,"height":651,"rx":78,"fill":683,"stroke":683,"style":684},[114,711,712],{"x":672,"y":701,"fill":103,"style":172,"textAnchor":131},"one URL",[74,714],{"x":116,"y":715,"width":650,"height":651,"rx":78,"fill":111,"stroke":103,"style":155},"146.0",[114,717,719],{"x":654,"y":718,"fill":103,"style":656,"textAnchor":657},"165.5","Width precision",[74,721],{"x":661,"y":715,"width":662,"height":651,"rx":78,"fill":103,"stroke":103,"style":125},[114,723,724],{"x":665,"y":718,"fill":103,"style":172,"textAnchor":131},"nearest candidate",[74,726],{"x":669,"y":715,"width":662,"height":651,"rx":78,"fill":683,"stroke":683,"style":684},[114,728,729],{"x":672,"y":718,"fill":103,"style":172,"textAnchor":131},"any step",[74,731],{"x":116,"y":732,"width":650,"height":651,"rx":78,"fill":111,"stroke":103,"style":155},"176.0",[114,734,736],{"x":654,"y":735,"fill":103,"style":656,"textAnchor":657},"195.5","Caching",[74,738],{"x":661,"y":732,"width":662,"height":651,"rx":78,"fill":683,"stroke":683,"style":684},[114,740,741],{"x":665,"y":735,"fill":103,"style":172,"textAnchor":131},"one URL per size",[74,743],{"x":669,"y":732,"width":662,"height":651,"rx":78,"fill":103,"stroke":103,"style":125},[114,745,746],{"x":672,"y":735,"fill":103,"style":172,"textAnchor":131},"needs Vary or keyed steps",[74,748],{"x":116,"y":749,"width":650,"height":651,"rx":78,"fill":111,"stroke":103,"style":155},"206.0",[114,751,753],{"x":654,"y":752,"fill":103,"style":656,"textAnchor":657},"225.5","First visit",[74,755],{"x":661,"y":749,"width":662,"height":651,"rx":78,"fill":683,"stroke":683,"style":684},[114,757,758],{"x":665,"y":752,"fill":103,"style":172,"textAnchor":131},"works immediately",[74,760],{"x":669,"y":749,"width":662,"height":651,"rx":78,"fill":103,"stroke":103,"style":125},[114,762,763],{"x":672,"y":752,"fill":103,"style":172,"textAnchor":131},"needs prior opt-in",[200,765,767],{"id":766},"verification","Verification",[14,769,770,771,217,773,775,776,778],{},"In Chrome DevTools, select an image request and confirm the ",[29,772,50],{},[29,774,39],{}," request headers. The response should be close to the hinted width, carry ",[29,777,57],{}," (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.",[200,780,782],{"id":781},"worked-example-a-travel-booking-site","Worked Example: A Travel Booking Site",[14,784,785,786,788,789,791,792,217,794,796,797,799,800,802],{},"A travel site had 40 templates, each with hand-written ",[29,787,31],{}," lists that had drifted from the actual layouts; audits found images 1.6x larger than needed on average. The team kept ",[29,790,35],{}," in all templates (fixed against the real layouts), opted in to ",[29,793,39],{},[29,795,50],{}," with delegation to their image CDN, and kept a short three-candidate ",[29,798,31],{}," 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 ",[29,801,35],{},"), and LCP p75 on Android improved by 280ms.",[200,804,806],{"id":805},"caching-hint-based-responses-safely","Caching Hint-Based Responses Safely",[14,808,809,810,812,813,816,817,820,821,823,824,826,827,829],{},"Every distinct value of a varied header creates a new cache entry. Raw ",[29,811,50],{}," values can be any integer, so ",[29,814,815],{},"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 ",[29,818,819],{},"Accept",") at the edge, put those into the cache key, and strip ",[29,822,57],{}," from the response cached at the edge, or keep a ",[29,825,57],{}," 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 ",[29,828,57],{}," as well, but they only ever see one device's hints, so this matters mostly for shared caches.",[14,831,832],{},[65,833,72,836,72,839,72,842,72,844,72,847,72,849,72,856,72,863,72,868,72,872,72,877,72,881,72,885,72,890,72],{"viewBox":834,"width":68,"role":69,"ariaLabel":835,"style":71},"0 0 760 163","Bar chart comparing CDN cache hit ratio for raw Vary on hint headers versus normalised width steps in the cache key.",[74,837],{"className":838,"x":78,"y":78,"width":68,"height":68,"fill":79},[77],[81,840,841],{},"CDN hit ratio by caching strategy for hinted images",[85,843,835],{},[74,845],{"x":107,"y":107,"width":108,"height":846,"rx":110,"fill":111,"stroke":103,"style":112},"161",[114,848,841],{"x":116,"y":117,"fill":103,"style":118},[114,850,855],{"x":851,"y":852,"fill":103,"style":853,"textAnchor":854},"177.5","70.0","font-size:13px","end","Vary: Sec-CH-Width (raw)",[74,857],{"x":858,"y":122,"width":859,"height":860,"rx":861,"fill":111,"stroke":103,"style":862},"189.5","206.5","19","3","fill-opacity:0.7;stroke-opacity:0.35",[114,864,867],{"x":865,"y":852,"fill":103,"style":866},"402.0","font-size:12px;font-weight:600","41%",[114,869,871],{"x":851,"y":870,"fill":103,"style":853,"textAnchor":854},"101.0","320px steps in cache key",[74,873],{"x":858,"y":874,"width":875,"height":860,"rx":861,"fill":690,"stroke":691,"style":876},"87.0","478.5","fill-opacity:0.7;stroke-opacity:0.9",[114,878,880],{"x":879,"y":870,"fill":103,"style":866},"674.0","95%",[114,882,884],{"x":851,"y":883,"fill":103,"style":853,"textAnchor":854},"132.0","160px steps in cache key",[74,886],{"x":858,"y":887,"width":888,"height":860,"rx":861,"fill":683,"stroke":683,"style":889},"118.0","463.4","fill-opacity:0.55;stroke-opacity:0.9",[114,891,893],{"x":892,"y":883,"fill":103,"style":866},"658.9","92%",[200,895,897],{"id":896},"common-mistakes","Common Mistakes",[205,899,900,910,918,927],{},[208,901,902,72,907,909],{},[211,903,904,905,266],{},"Omitting ",[29,906,35],{},[29,908,50],{}," is not sent without it.",[208,911,912,915,916,266],{},[211,913,914],{},"Forgetting delegation."," Third-party image origins receive no hints without ",[29,917,232],{},[208,919,920,926],{},[211,921,922,923,925],{},"Raw ",[29,924,57],{}," on hints."," Cache fragmentation and low hit rates.",[208,928,929,932],{},[211,930,931],{},"Dropping srcset entirely."," Non-Chromium browsers get one size for every device.",[200,934,936],{"id":935},"edge-cases","Edge Cases",[14,938,939,942,943,598,946,217,949,952,953,956],{},[211,940,941],{},"Legacy hint names."," Older ",[29,944,945],{},"DPR",[29,947,948],{},"Width",[29,950,951],{},"Viewport-Width"," headers without the ",[29,954,955],{},"Sec-CH-"," prefix are deprecated; use the prefixed versions.",[14,958,959,962,963,966],{},[211,960,961],{},"Critical-CH."," The ",[29,964,965],{},"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.",[14,968,969,972],{},[211,970,971],{},"Privacy budgets."," Browsers limit high-entropy hints; DPR and width hints are low-entropy, but treat future changes as possible.",[14,974,975,72,978,981,982,985],{},[211,976,977],{},"Preloads.",[29,979,980],{},"\u003Clink rel=\"preload\" as=\"image\">"," with ",[29,983,984],{},"imagesizes"," sends hints too; keep preload and image consistent so the same variant is used.",[200,987,989],{"id":988},"faq","FAQ",[991,992,995,999],"details",{"className":993},[994],"faq-item",[996,997,998],"summary",{},"Which browsers send image client hints?",[14,1000,1001],{},"Chromium-based browsers (Chrome, Edge, Opera, Samsung Internet). Safari and Firefox do not send them, so a fallback is required.",[991,1003,1005,1008],{"className":1004},[994],[996,1006,1007],{},"Do hints work on the first page load?",[14,1009,1010,1011,1013],{},"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 ",[29,1012,965],{}," triggers a retry.",[991,1015,1017,1020],{"className":1016},[994],[996,1018,1019],{},"Can I use hints without an image CDN?",[14,1021,1022],{},"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.",[991,1024,1026,1029],{"className":1025},[994],[996,1027,1028],{},"Should I still write srcset?",[14,1030,1031],{},"Yes, as long as a significant share of users have browsers without hint support. Hints then refine sizing in supporting browsers.",[991,1033,1035,1038],{"className":1034},[994],[996,1036,1037],{},"What is Content-DPR?",[14,1039,1040,1041,217,1044,1047],{},"A response header that told the browser the served image's density for intrinsic sizing. It has been deprecated in browsers; set explicit ",[29,1042,1043],{},"width",[29,1045,1046],{},"height"," attributes on images instead.",[991,1049,1051,1054],{"className":1050},[994],[996,1052,1053],{},"Do client hints help LCP?",[14,1055,1056,1057,1060],{},"Indirectly — smaller, correctly sized LCP images download faster. Priority and discovery still matter more, so keep ",[29,1058,1059],{},"fetchpriority"," on the LCP image.",[200,1062,1064],{"id":1063},"related","Related",[205,1066,1067,1074,1081],{},[208,1068,1069,1073],{},[18,1070,1072],{"href":1071},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fself-hosting-an-image-proxy-with-imgproxy\u002F","Self-hosting an image proxy with imgproxy"," — a server that can honour hints.",[208,1075,1076,1080],{},[18,1077,1079],{"href":1078},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fcaching-transformed-images-at-the-edge\u002F","Caching transformed images at the edge"," — cache keys for variants.",[208,1082,1083,1087],{},[18,1084,1086],{"href":1085},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fcdn-edge-caching-configuration\u002Fvary-header-pitfalls-that-destroy-cdn-hit-rate\u002F","Vary header pitfalls that destroy CDN hit rate"," — why raw Vary hurts.",[1089,1090,1092],"script",{"type":1091},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Using Client Hints for Image Width and DPR\",\n  \"description\": \"How responsive image client hints work, how to enable and delegate them to an image CDN, and how to cache hint-based responses without breaking anything.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Opt in on the document response\",\n      \"text\": \"The Permissions-Policy delegation lets the browser send the hints to the third-party image origin.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Keep sizes on the image\",\n      \"text\": \"Sec-CH-Width is only sent for images with a sizes attribute.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Resize on the server and set Vary\",\n      \"text\": \"Resize on the server and set Vary\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Combine with srcset for full coverage\",\n      \"text\": \"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.\"\n    }\n  ]\n}\n",[1089,1094,1095],{"type":1091},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Using Client Hints for Image Width and DPR\",\n  \"description\": \"How responsive image client hints work, how to enable and delegate them to an image CDN, and how to cache hint-based responses without breaking anything.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr\u002F\"\n  }\n}\n",[1089,1097,1098],{"type":1091},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Image & Media Optimization\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Image CDNs and fetchpriority\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Using Client Hints for Image Width and DPR\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr\u002F\"\n    }\n  ]\n}\n",[1100,1101,1102],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}",{"title":306,"searchDepth":318,"depth":318,"links":1104},[1105,1106,1107,1113,1114,1115,1116,1117,1118,1119],{"id":202,"depth":318,"text":203},{"id":248,"depth":318,"text":249},{"id":293,"depth":318,"text":294,"children":1108},[1109,1110,1111,1112],{"id":298,"depth":324,"text":299},{"id":336,"depth":324,"text":337},{"id":424,"depth":324,"text":425},{"id":618,"depth":324,"text":619},{"id":766,"depth":318,"text":767},{"id":781,"depth":318,"text":782},{"id":805,"depth":318,"text":806},{"id":896,"depth":318,"text":897},{"id":935,"depth":318,"text":936},{"id":988,"depth":318,"text":989},{"id":1063,"depth":318,"text":1064},"How responsive image client hints work, how to enable and delegate them to an image CDN, and how to cache hint-based responses without breaking anything.","md",{"slug":12,"type":1123,"breadcrumb":1124,"datePublished":1131,"dateModified":1131},"article",[1125,1127,1128,1129],{"name":1126,"url":509},"Home",{"name":26,"url":25},{"name":21,"url":20},{"name":5,"url":1130},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr\u002F","2026-10-06",true,"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr",{"title":1135,"description":1136},"Client Hints for Image Width and DPR: A Practical Guide","Use Sec-CH-DPR, Sec-CH-Width and Sec-CH-Viewport-Width to size images on the server: opt-in with Accept-CH, delegate to CDNs, cache safely, and fall back.","image-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-client-hints-for-image-width-and-dpr\u002Findex","N-AxXpaiLKF2s_-XdKjYyyoT5-c5Z5lou9USVW_stj0",[1140,1144],{"title":1141,"path":1142,"stem":1143},"Self-Hosting an Image Proxy with imgproxy","\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fself-hosting-an-image-proxy-with-imgproxy","image-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fself-hosting-an-image-proxy-with-imgproxy\u002Findex",{"title":1145,"path":1146,"stem":1147},"Using fetchpriority to Prioritize the LCP Image","\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-fetchpriority-to-prioritize-the-lcp-image","image-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-fetchpriority-to-prioritize-the-lcp-image\u002Findex",1791308077006]