[{"data":1,"prerenderedAt":907},["ShallowReactive",2],{"content:\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn":3,"surroundings:\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn":899},{"id":4,"title":5,"body":6,"description":879,"extension":880,"meta":881,"navigation":893,"path":894,"seo":895,"stem":897,"__hash__":898},"content\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002Findex.md","Fixing a Slow LCP Image Behind an Image CDN",{"type":7,"value":8,"toc":871},"minimark",[9,14,43,48,89,212,216,222,228,234,244,250,254,259,420,427,433,544,547,553,598,604,608,611,749,752,756,777,790,804,813,822,831,835,856,861,864,867],[10,11,13],"h1",{"id":12},"how-to-fix-a-slow-lcp-image-served-through-an-image-cdn","How to Fix a Slow LCP Image Served Through an Image CDN",[15,16,17,18,23,24,28,29,33,34,37,38,42],"p",{},"This walkthrough extends ",[19,20,22],"a",{"href":21},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002F","Image CDNs and fetchpriority"," within ",[19,25,27],{"href":26},"\u002Fimage-media-optimization\u002F","Image & Media Optimization",". You moved the hero image behind an image CDN, the file is now ",[30,31,32],"code",{},"62KB"," of AVIF instead of ",[30,35,36],{},"310KB"," of JPEG, and ",[19,39,41],{"href":40},"\u002Fcore-web-vitals-measurement\u002Fmeasuring-lcp-with-chrome-devtools\u002F","LCP"," got worse. The bytes are not the problem. The first request for a given variant is doing work — a fetch from origin, a decode, a re-encode — while the browser waits.",[44,45,47],"h2",{"id":46},"rapid-diagnosis-where-is-the-time-going","Rapid Diagnosis: Where Is the Time Going?",[49,50,51,63,73,83],"ul",{},[52,53,54,58,59,62],"li",{},[55,56,57],"strong",{},"Split the request timing."," In the Network panel, expand the image's ",[55,60,61],{},"Timing"," tab. A large \"Waiting for server response\" with a small \"Content Download\" means transform latency, not transfer.",[52,64,65,68,69,72],{},[55,66,67],{},"Check the cache status header."," Most image CDNs expose a hit\u002Fmiss header. A ",[30,70,71],{},"MISS"," on your hero image on every deploy means the variant is not warm.",[52,74,75,78,79,82],{},[55,76,77],{},"Look for a redirect."," A ",[30,80,81],{},"302"," from your origin to the CDN adds a full round trip before the image request even starts.",[52,84,85,88],{},[55,86,87],{},"Count the variants."," If the URL includes a viewport-derived width, you may be generating dozens of near-identical variants, none of which stays warm.",[90,91,98,99,106,107,106,111,106,115,106,124,106,131,106,136,106,144,106,150,106,157,106,162,106,167,106,170,106,175,106,179,106,182,106,184,106,187,106,191,106,194,106,197,106,201,106,207,106],"svg",{"xmlns":92,"viewBox":93,"width":94,"role":95,"ariaLabel":96,"style":97},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","0 0 760 244","100%","img","Timing bars for a cold transform showing connection, a long server wait for the transform, and a short download, compared with a warm hit where the wait is minimal","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)","\n  ",[100,101],"rect",{"className":102,"x":104,"y":104,"width":94,"height":94,"fill":105},[103],"svg-canvas","0","#ffffff"," ",[108,109,110],"title",{},"Cold transform versus warm hit for the LCP image",[112,113,114],"desc",{},"On a cache miss the image CDN spends most of the time transforming before any bytes are sent; on a hit the same variant returns almost immediately, so the download dominates.",[100,116],{"x":117,"y":117,"width":118,"height":119,"rx":120,"fill":121,"stroke":122,"style":123},"1","758","242","10","none","currentColor","stroke-opacity:0.18",[125,126,130],"text",{"x":127,"y":128,"fill":122,"style":129},"24","32","font-size:16px;font-weight:700","Small file, slow arrival",[125,132,135],{"x":127,"y":133,"fill":122,"style":134},"76","font-size:11.5px;font-weight:700","Cold (MISS)",[100,137],{"x":138,"y":139,"width":140,"height":141,"rx":142,"fill":122,"stroke":122,"style":143},"140","58","70","26","3","fill-opacity:0.1;stroke-opacity:0.35",[125,145,149],{"x":146,"y":133,"fill":122,"style":147,"textAnchor":148},"175","font-size:10px;","middle","connect",[100,151],{"x":152,"y":139,"width":153,"height":141,"rx":142,"fill":154,"stroke":155,"style":156},"210","330","#ffc300","#b8860b","fill-opacity:0.3",[125,158,161],{"x":159,"y":133,"fill":122,"style":160,"textAnchor":148},"375","font-size:10.5px;font-weight:700;","origin fetch + decode + re-encode",[100,163],{"x":164,"y":139,"width":140,"height":141,"rx":142,"fill":165,"stroke":165,"style":166},"540","#0466c8","fill-opacity:0.2;stroke-opacity:0.55",[125,168,32],{"x":169,"y":133,"fill":122,"style":147,"textAnchor":148},"575",[125,171,174],{"x":172,"y":133,"fill":155,"style":173},"622","font-size:11px;font-weight:700","1.9s",[125,176,178],{"x":127,"y":177,"fill":122,"style":134},"146","Warm (HIT)",[100,180],{"x":138,"y":181,"width":140,"height":141,"rx":142,"fill":122,"stroke":122,"style":143},"128",[125,183,149],{"x":146,"y":177,"fill":122,"style":147,"textAnchor":148},[100,185],{"x":152,"y":181,"width":186,"height":141,"rx":142,"fill":154,"stroke":155,"style":156},"40",[125,188,190],{"x":189,"y":177,"fill":122,"style":147,"textAnchor":148},"230","wait",[100,192],{"x":193,"y":181,"width":140,"height":141,"rx":142,"fill":165,"stroke":165,"style":166},"250",[125,195,32],{"x":196,"y":177,"fill":122,"style":147,"textAnchor":148},"285",[125,198,200],{"x":199,"y":177,"fill":122,"style":173},"332","0.5s",[202,203],"line",{"x1":127,"y1":204,"x2":205,"y2":204,"stroke":122,"style":206},"176","736","stroke-opacity:0.2",[125,208,211],{"x":127,"y":209,"fill":122,"style":210},"204","font-size:11.5px;fill-opacity:0.85","Your LCP image must be a HIT for the first visitor after every deploy — not the request that warms it.",[44,213,215],{"id":214},"root-cause-analysis","Root Cause Analysis",[15,217,218,221],{},[55,219,220],{},"1. Transform-on-miss latency."," The first request for a variant triggers an origin fetch plus a decode and re-encode. AVIF encoding in particular is expensive, and a large source image can take a second or more.",[15,223,224,227],{},[55,225,226],{},"2. A redirect hop."," Serving the image from your own origin and redirecting to the CDN costs a full round trip at high priority, directly in front of the LCP element.",[15,229,230,233],{},[55,231,232],{},"3. Variant explosion."," URLs built from the actual viewport width produce a distinct variant per device width. Each one is cold on first use, and the rarest widths are never warm for anyone.",[15,235,236,239,240,243],{},[55,237,238],{},"4. A missing preconnect."," The image CDN is a separate origin. Without a hint, the DNS lookup and TLS handshake happen at the moment the LCP image is discovered, adding ",[30,241,242],{},"100–300ms"," on mobile.",[15,245,246,249],{},[55,247,248],{},"5. The variant changes on every deploy."," If the URL includes a build hash or a changing signature, yesterday's warm cache is worthless today.",[44,251,253],{"id":252},"step-by-step-resolution","Step-by-Step Resolution",[15,255,256],{},[55,257,258],{},"1. Pin a small set of widths and warm them at deploy.",[260,261,266],"pre",{"className":262,"code":263,"language":264,"meta":265,"style":265},"language-bash shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","# Warm exactly the variants the site can request, right after deploy.\nfor w in 640 960 1280 1600 2400; do\n  for fmt in avif webp; do\n    curl -s -o \u002Fdev\u002Fnull -H \"Accept: image\u002F$fmt\" \\\n      \"https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=$w&fm=$fmt&q=70\" &\n  done\ndone; wait\n# trade-off: warming costs transform capacity at deploy time and only helps the\n# variants you listed. Keep the ladder short — five widths covers virtually\n# every device once srcset is doing its job.\n","bash","",[30,267,268,276,312,333,365,385,391,402,408,414],{"__ignoreMap":265},[269,270,272],"span",{"class":202,"line":271},1,[269,273,275],{"class":274},"sjfSM","# Warm exactly the variants the site can request, right after deploy.\n",[269,277,279,283,287,290,294,297,300,303,306,309],{"class":202,"line":278},2,[269,280,282],{"class":281},"sPARh","for",[269,284,286],{"class":285},"saISM"," w ",[269,288,289],{"class":281},"in",[269,291,293],{"class":292},"sZ8jY"," 640",[269,295,296],{"class":292}," 960",[269,298,299],{"class":292}," 1280",[269,301,302],{"class":292}," 1600",[269,304,305],{"class":292}," 2400",[269,307,308],{"class":285},"; ",[269,310,311],{"class":281},"do\n",[269,313,315,318,321,323,326,329,331],{"class":202,"line":314},3,[269,316,317],{"class":281},"  for",[269,319,320],{"class":285}," fmt ",[269,322,289],{"class":281},[269,324,325],{"class":292}," avif",[269,327,328],{"class":292}," webp",[269,330,308],{"class":285},[269,332,311],{"class":281},[269,334,336,340,344,347,350,353,356,359,362],{"class":202,"line":335},4,[269,337,339],{"class":338},"sQw3B","    curl",[269,341,343],{"class":342},"sPXB4"," -s",[269,345,346],{"class":342}," -o",[269,348,349],{"class":292}," \u002Fdev\u002Fnull",[269,351,352],{"class":342}," -H",[269,354,355],{"class":292}," \"Accept: image\u002F",[269,357,358],{"class":285},"$fmt",[269,360,361],{"class":292},"\"",[269,363,364],{"class":281}," \\\n",[269,366,368,371,374,377,379,382],{"class":202,"line":367},5,[269,369,370],{"class":292},"      \"https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=",[269,372,373],{"class":285},"$w",[269,375,376],{"class":292},"&fm=",[269,378,358],{"class":285},[269,380,381],{"class":292},"&q=70\"",[269,383,384],{"class":285}," &\n",[269,386,388],{"class":202,"line":387},6,[269,389,390],{"class":281},"  done\n",[269,392,394,397,399],{"class":202,"line":393},7,[269,395,396],{"class":281},"done",[269,398,308],{"class":285},[269,400,401],{"class":342},"wait\n",[269,403,405],{"class":202,"line":404},8,[269,406,407],{"class":274},"# trade-off: warming costs transform capacity at deploy time and only helps the\n",[269,409,411],{"class":202,"line":410},9,[269,412,413],{"class":274},"# variants you listed. Keep the ladder short — five widths covers virtually\n",[269,415,417],{"class":202,"line":416},10,[269,418,419],{"class":274},"# every device once srcset is doing its job.\n",[15,421,422,423,426],{},"Expected outcome: the first real visitor after a deploy gets a cache hit, removing ",[30,424,425],{},"0.5–1.5s"," of transform latency from LCP.",[15,428,429,432],{},[55,430,431],{},"2. Remove the redirect."," Reference the CDN URL directly in the markup rather than routing through your origin.",[260,434,438],{"className":435,"code":436,"language":437,"meta":265,"style":265},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u003Cimg src=\"https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=1600&fm=avif&q=70\"\n     srcset=\"https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=960&fm=avif&q=70 960w,\n             https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=1600&fm=avif&q=70 1600w\"\n     sizes=\"(min-width: 1200px) 1100px, 100vw\"\n     width=\"1600\" height=\"900\" alt=\"Coastal trail at sunrise\"\n     fetchpriority=\"high\" decoding=\"async\">\n\u003C!-- trade-off: hard-coding the CDN host couples your markup to the vendor.\n     Emit it from one config value so a migration is a single change, not a\n     find-and-replace across templates. -->\n","html",[30,439,440,457,467,472,482,508,529,534,539],{"__ignoreMap":265},[269,441,442,445,448,451,454],{"class":202,"line":271},[269,443,444],{"class":285},"\u003C",[269,446,95],{"class":447},"sZBmE",[269,449,450],{"class":342}," src",[269,452,453],{"class":285},"=",[269,455,456],{"class":292},"\"https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=1600&fm=avif&q=70\"\n",[269,458,459,462,464],{"class":202,"line":278},[269,460,461],{"class":342},"     srcset",[269,463,453],{"class":285},[269,465,466],{"class":292},"\"https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=960&fm=avif&q=70 960w,\n",[269,468,469],{"class":202,"line":314},[269,470,471],{"class":292},"             https:\u002F\u002Fimg.example-cdn.com\u002Fhero.jpg?w=1600&fm=avif&q=70 1600w\"\n",[269,473,474,477,479],{"class":202,"line":335},[269,475,476],{"class":342},"     sizes",[269,478,453],{"class":285},[269,480,481],{"class":292},"\"(min-width: 1200px) 1100px, 100vw\"\n",[269,483,484,487,489,492,495,497,500,503,505],{"class":202,"line":367},[269,485,486],{"class":342},"     width",[269,488,453],{"class":285},[269,490,491],{"class":292},"\"1600\"",[269,493,494],{"class":342}," height",[269,496,453],{"class":285},[269,498,499],{"class":292},"\"900\"",[269,501,502],{"class":342}," alt",[269,504,453],{"class":285},[269,506,507],{"class":292},"\"Coastal trail at sunrise\"\n",[269,509,510,513,515,518,521,523,526],{"class":202,"line":387},[269,511,512],{"class":342},"     fetchpriority",[269,514,453],{"class":285},[269,516,517],{"class":292},"\"high\"",[269,519,520],{"class":342}," decoding",[269,522,453],{"class":285},[269,524,525],{"class":292},"\"async\"",[269,527,528],{"class":285},">\n",[269,530,531],{"class":202,"line":393},[269,532,533],{"class":274},"\u003C!-- trade-off: hard-coding the CDN host couples your markup to the vendor.\n",[269,535,536],{"class":202,"line":404},[269,537,538],{"class":274},"     Emit it from one config value so a migration is a single change, not a\n",[269,540,541],{"class":202,"line":410},[269,542,543],{"class":274},"     find-and-replace across templates. -->\n",[15,545,546],{},"Expected outcome: one round trip removed from the critical path.",[15,548,549,552],{},[55,550,551],{},"3. Preconnect the image origin."," The hint must appear before the image is discovered, in the document head.",[260,554,556],{"className":435,"code":555,"language":437,"meta":265,"style":265},"\u003Clink rel=\"preconnect\" href=\"https:\u002F\u002Fimg.example-cdn.com\">\n\u003C!-- trade-off: preconnect slots are scarce — two or three total. If the image\n     CDN shares an origin with other assets you already preconnect, this hint\n     is free; if not, it is worth one of the slots for the LCP resource. -->\n",[30,557,558,583,588,593],{"__ignoreMap":265},[269,559,560,562,565,568,570,573,576,578,581],{"class":202,"line":271},[269,561,444],{"class":285},[269,563,564],{"class":447},"link",[269,566,567],{"class":342}," rel",[269,569,453],{"class":285},[269,571,572],{"class":292},"\"preconnect\"",[269,574,575],{"class":342}," href",[269,577,453],{"class":285},[269,579,580],{"class":292},"\"https:\u002F\u002Fimg.example-cdn.com\"",[269,582,528],{"class":285},[269,584,585],{"class":202,"line":278},[269,586,587],{"class":274},"\u003C!-- trade-off: preconnect slots are scarce — two or three total. If the image\n",[269,589,590],{"class":202,"line":314},[269,591,592],{"class":274},"     CDN shares an origin with other assets you already preconnect, this hint\n",[269,594,595],{"class":202,"line":335},[269,596,597],{"class":274},"     is free; if not, it is worth one of the slots for the LCP resource. -->\n",[15,599,600,603],{},[55,601,602],{},"4. Keep the variant URL stable."," Derive it from the source asset and the ladder, never from a build hash or a per-request signature. If your CDN requires signed URLs, use a long-lived signature so the cache key does not rotate on every deploy.",[44,605,607],{"id":606},"verification","Verification",[15,609,610],{},"Deploy, then request the hero variant twice and compare. The first request should already be a hit if warming worked; if the first is a miss and the second is fast, the warm step ran against a different URL than the page uses — a very common off-by-one in the query parameters.",[260,612,614],{"className":262,"code":613,"language":264,"meta":265,"style":265},"# Confirm the exact URL the page requests is warm.\nurl=$(curl -s https:\u002F\u002Fexample.com | grep -o 'https:\u002F\u002Fimg\\.example-cdn\\.com[^\" ]*w=1600[^\" ]*' | head -1)\nfor i in 1 2; do\n  curl -s -o \u002Fdev\u002Fnull -w '%{time_starttransfer}s  %{http_code}  ' \"$url\"\n  curl -sI \"$url\" | grep -i '^\\(x-cache\\|cf-cache-status\\|x-served-by\\):'\ndone\n# trade-off: shell extraction of the URL is fragile against HTML changes. It is\n# still the right check, because the whole class of bug is warming a URL that\n# differs from the one in the markup.\n",[30,615,616,621,661,680,706,729,734,739,744],{"__ignoreMap":265},[269,617,618],{"class":202,"line":271},[269,619,620],{"class":274},"# Confirm the exact URL the page requests is warm.\n",[269,622,623,626,628,631,634,636,639,642,645,647,650,652,655,658],{"class":202,"line":278},[269,624,625],{"class":285},"url",[269,627,453],{"class":281},[269,629,630],{"class":285},"$(",[269,632,633],{"class":338},"curl",[269,635,343],{"class":342},[269,637,638],{"class":292}," https:\u002F\u002Fexample.com",[269,640,641],{"class":281}," |",[269,643,644],{"class":338}," grep",[269,646,346],{"class":342},[269,648,649],{"class":292}," 'https:\u002F\u002Fimg\\.example-cdn\\.com[^\" ]*w=1600[^\" ]*'",[269,651,641],{"class":281},[269,653,654],{"class":338}," head",[269,656,657],{"class":342}," -1",[269,659,660],{"class":285},")\n",[269,662,663,665,668,670,673,676,678],{"class":202,"line":314},[269,664,282],{"class":281},[269,666,667],{"class":285}," i ",[269,669,289],{"class":281},[269,671,672],{"class":292}," 1",[269,674,675],{"class":292}," 2",[269,677,308],{"class":285},[269,679,311],{"class":281},[269,681,682,685,687,689,691,694,697,700,703],{"class":202,"line":335},[269,683,684],{"class":338},"  curl",[269,686,343],{"class":342},[269,688,346],{"class":342},[269,690,349],{"class":292},[269,692,693],{"class":342}," -w",[269,695,696],{"class":292}," '%{time_starttransfer}s  %{http_code}  '",[269,698,699],{"class":292}," \"",[269,701,702],{"class":285},"$url",[269,704,705],{"class":292},"\"\n",[269,707,708,710,713,715,717,719,721,723,726],{"class":202,"line":367},[269,709,684],{"class":338},[269,711,712],{"class":342}," -sI",[269,714,699],{"class":292},[269,716,702],{"class":285},[269,718,361],{"class":292},[269,720,641],{"class":281},[269,722,644],{"class":338},[269,724,725],{"class":342}," -i",[269,727,728],{"class":292}," '^\\(x-cache\\|cf-cache-status\\|x-served-by\\):'\n",[269,730,731],{"class":202,"line":387},[269,732,733],{"class":281},"done\n",[269,735,736],{"class":202,"line":393},[269,737,738],{"class":274},"# trade-off: shell extraction of the URL is fragile against HTML changes. It is\n",[269,740,741],{"class":202,"line":404},[269,742,743],{"class":274},"# still the right check, because the whole class of bug is warming a URL that\n",[269,745,746],{"class":202,"line":410},[269,747,748],{"class":274},"# differs from the one in the markup.\n",[15,750,751],{},"Then confirm the metric. LCP's resource-load-delay and load-time phases should both shrink — delay from the preconnect and the removed redirect, load time from the warm transform. If only bytes improved and the timestamp did not, the transform was never the bottleneck and you should re-read the phase breakdown.",[44,753,755],{"id":754},"faq","FAQ",[757,758,761,765],"details",{"className":759},[760],"faq-item",[762,763,764],"summary",{},"Should the LCP image be lazy-loaded if it is behind a CDN?",[15,766,767,768,771,772,776],{},"No. Lazy-loading defers discovery until layout, which is the opposite of what the LCP element needs regardless of who serves it. Keep the hero eager, give it ",[30,769,770],{},"fetchpriority=\"high\"",", and reserve lazy loading for images below the fold — the rules in ",[19,773,775],{"href":774},"\u002Fimage-media-optimization\u002Flazy-loading-images-without-hurting-lcp\u002F","lazy loading images without hurting LCP"," apply unchanged.",[757,778,780,783],{"className":779},[760],[762,781,782],{},"How many width variants should I generate?",[15,784,785,786,789],{},"Four to six. Each additional width divides your cache warmth without meaningfully improving the byte fit, since ",[30,787,788],{},"srcset"," already picks the nearest candidate above the required size. A ladder like 640, 960, 1280, 1600 and 2400 covers essentially every device, and every one of those variants can be kept warm.",[757,791,793,796],{"className":792},[760],[762,794,795],{},"Is AVIF still the right format for the hero?",[15,797,798,799,803],{},"It depends on decode cost for your audience, not on file size alone. AVIF's smaller bytes are a clear win when the device can decode quickly, and a net loss on low-end hardware where decode lands inside LCP render delay. Measure both on your target device profile — the trade-off is worked through in ",[19,800,802],{"href":801},"\u002Fimage-media-optimization\u002Fserving-avif-and-webp-with-fallbacks\u002Favif-vs-webp-which-format-to-serve\u002F","AVIF vs WebP",".",[757,805,807,810],{"className":806},[760],[762,808,809],{},"Should I warm variants for every page or only key templates?",[15,811,812],{},"Only where a cold transform lands on the critical path — the hero of your highest-traffic templates, and any campaign landing page shipped with new imagery. Warming the entire catalogue costs transform capacity for images most visitors will never request, and a below-the-fold image absorbing a transform delay is invisible. Rank by traffic multiplied by whether the image is the LCP candidate, and warm the top of that list.",[757,814,816,819],{"className":815},[760],[762,817,818],{},"What quality setting should the LCP image use?",[15,820,821],{},"Lower than you think, and verified on a real screen rather than chosen by number. Perceptual quality flattens out well below the defaults most CDNs ship — for a photographic hero, a setting around 60–70 is usually indistinguishable from 85 while shipping a third fewer bytes. Compare the two at the actual rendered size on a high-DPI display, not zoomed in: artefacts that are obvious at 400% are invisible at 100%.",[757,823,825,828],{"className":824},[760],[762,826,827],{},"Can I keep the transform on my own origin instead?",[15,829,830],{},"You can, and it trades one problem for another. Transforming at your origin removes a connection and gives you full control of caching, but it puts image encoding on infrastructure that is usually sized for HTML, and a cold hero transform now competes with request handling. The pattern that works is to pre-generate the fixed variant ladder at build time and serve the results as static assets — no runtime transform anywhere, and every variant permanently warm.",[44,832,834],{"id":833},"related","Related",[49,836,837,842,849],{},[52,838,839,841],{},[19,840,22],{"href":21}," — the delivery configuration this fix sits inside.",[52,843,844,848],{},[19,845,847],{"href":846},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-fetchpriority-to-prioritize-the-lcp-image\u002F","Using fetchpriority to prioritize the LCP image"," — make sure the request also starts at high priority.",[52,850,851,855],{},[19,852,854],{"href":853},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002F","Resource Hints & Early Hints"," — warm the image origin before the parser reaches the markup.",[857,858,860],"script",{"type":859},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Fix a slow LCP image served through an image CDN\",\n  \"description\": \"Remove transform-on-miss latency by pinning and warming a small variant ladder, eliminate the redirect hop, preconnect the image origin, and keep variant URLs stable across deploys.\",\n  \"step\": [\n    { \"@type\": \"HowToStep\", \"position\": 1, \"name\": \"Warm a pinned variant ladder\", \"text\": \"Generate a short list of widths and formats and request them at deploy time so the first visitor gets a cache hit.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 2, \"name\": \"Remove the redirect\", \"text\": \"Reference the CDN URL directly in markup instead of redirecting through your own origin.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 3, \"name\": \"Preconnect the image origin\", \"text\": \"Add a preconnect hint in the head so DNS and TLS are done before the image is discovered.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 4, \"name\": \"Stabilise the variant URL\", \"text\": \"Derive URLs from the source asset and the ladder rather than a build hash, so warmth survives deploys.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F#step-by-step-resolution\" }\n  ]\n}\n",[857,862,863],{"type":859},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Fix a Slow LCP Image Served Through an Image CDN\",\n  \"description\": \"Smaller files can still arrive later: transform-on-miss latency, a redirect hop, variant explosion and a missing preconnect all delay the LCP image.\",\n  \"datePublished\": \"2026-08-01\",\n  \"dateModified\": \"2026-08-01\",\n  \"author\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"publisher\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"mainEntityOfPage\": { \"@type\": \"WebPage\", \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F\" }\n}\n",[857,865,866],{"type":859},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    { \"@type\": \"ListItem\", \"position\": 1, \"name\": \"Home\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 2, \"name\": \"Image & Media Optimization\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 3, \"name\": \"Image CDNs and fetchpriority\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 4, \"name\": \"Fixing a Slow LCP Image Behind an Image CDN\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F\" }\n  ]\n}\n",[868,869,870],"style",{},"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 .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}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 .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}",{"title":265,"searchDepth":278,"depth":278,"links":872},[873,874,875,876,877,878],{"id":46,"depth":278,"text":47},{"id":214,"depth":278,"text":215},{"id":252,"depth":278,"text":253},{"id":606,"depth":278,"text":607},{"id":754,"depth":278,"text":755},{"id":833,"depth":278,"text":834},"An image CDN can make the LCP image slower than the original. Diagnose transform-on-miss latency, redirect hops and variant explosion.","md",{"slug":882,"type":883,"breadcrumb":884,"datePublished":892,"dateModified":892},"fixing-a-slow-lcp-image-behind-an-image-cdn","article",[885,888,889,890],{"name":886,"url":887},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":891},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002F","2026-08-01",true,"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn",{"title":5,"description":896},"The transform is fast but the first request is slow: cold-cache transform latency, a redirect hop, a missed preconnect and an unpinned variant all delay the LCP image.","image-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Ffixing-a-slow-lcp-image-behind-an-image-cdn\u002Findex","Oa_eEaHsFHRLpisbbxWOHuF4jG_iilOio6OpIXOKIKc",[900,903],{"title":22,"path":901,"stem":902,"children":-1},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority","image-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Findex",{"title":904,"path":905,"stem":906,"children":-1},"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",1785622407319]