Technical Guides
Why Your Image CDN Is Not Improving LCP: 7 Configuration Mistakes
Installed an image CDN but Largest Contentful Paint is still bad? Here are the seven configuration mistakes that usually block LCP gains, with fixes for HTML, WordPress, and Next.js.
By Sunny Kumar · Editor
Your image CDN is probably working. Your LCP setup may not be.
That is the part most people miss.
An image CDN can resize, compress, convert, cache, and deliver the LCP image faster. But it cannot fully fix a hero image that the browser discovers late, lazy-loads by mistake, renders after JavaScript, or requests at the wrong size.
TL;DR: If an image CDN is not improving LCP, check the LCP subparts before blaming the provider. The common mistakes are lazy-loading the hero image, missing srcset and sizes, late CSS or JavaScript discovery, no fetchpriority, too many cold-cache variants, a new third-party CDN connection, and render delay from CSS or JavaScript. The CDN mainly fixes image bytes and delivery. Your markup fixes discovery and priority.
Mistakes
The seven configuration mistakes that block LCP gains.
Diagnosis
Use the LCP subparts before changing CDN settings.
Fixes
The HTML, WordPress, and Next.js checklist.
FAQ
Short answers for common CDN and LCP questions.
My Short Verdict
An image CDN is worth using for LCP when the LCP resource is too large, too far away, or served in the wrong format. If the request starts late or the image waits behind JavaScript, fix the page implementation first.

How to Diagnose the Real LCP Bottleneck
Do not start by changing CDN providers.
Start by opening PageSpeed Insights, Chrome DevTools Performance, or WebPageTest and identifying the actual LCP element. Then check the LCP breakdown.
Google's LCP optimization guide breaks the metric into four parts:
| LCP part | What it means | Does an image CDN fix it? |
|---|---|---|
| TTFB | Time until HTML starts arriving | Not directly |
| Resource load delay | Time before the LCP image request starts | Only indirectly |
| Resource load duration | Time spent downloading the image | Yes, this is the main CDN win |
| Element render delay | Time after image load before it renders | No |
This table explains most failed CDN projects.
If resource load duration is the big number, your image CDN setup probably needs better sizing, format, compression, cache, or edge delivery.
If resource load delay or render delay is the big number, the CDN is not the main problem.
For the broader testing setup, read my full image CDN LCP test guide. This page is the troubleshooting version.
What Usually Goes Wrong?
Here is the quick map.
| Symptom | Likely mistake | First fix |
|---|---|---|
| LCP image request starts late | Image hidden in CSS, JavaScript, slider, or client rendering | Put the image in early HTML |
| CDN image is small but LCP still bad | Render delay or TTFB is dominant | Fix CSS, JS, server response, or hydration |
| PageSpeed says LCP image was lazy-loaded | Hero image has loading="lazy" | Remove lazy loading from the LCP image |
| Mobile downloads a desktop-sized image | Missing or wrong srcset / sizes | Generate bounded responsive CDN URLs |
| First visit is slow, second visit is fine | Cold CDN transform | Pre-warm key variants and reduce URL variants |
| CDN URL is on a new domain | Connection setup adds delay | Use a custom CDN hostname or preconnect |
| LCP moves to another element | Wrong element was being optimized | Optimize the real LCP element per viewport |
That last one matters.
Desktop and mobile can have different LCP elements. A homepage can use a hero image on desktop and a text block on mobile. A product page can shift from gallery image to product title depending on layout.
Do not optimize the image you think is important. Optimize the image your tools show as LCP.
Mistake 1: You Lazy-Loaded the LCP Image
This is the easiest mistake to understand.
Lazy loading is for images the user may not see immediately. Your LCP image is the opposite. It is usually the biggest visible thing in the first viewport.
Bad:
<img
src="https://cdn.example.com/hero.jpg?width=1200&format=auto"
loading="lazy"
width="1200"
height="675"
alt="Homepage hero"
>
Better:
<img
src="https://cdn.example.com/hero.jpg?width=1200&format=auto"
width="1200"
height="675"
fetchpriority="high"
decoding="async"
alt="Homepage hero"
>
The image CDN can make the file smaller. But loading="lazy" still tells the browser not to rush the image.
Use lazy loading below the fold. Keep the hero, product lead image, and article cover eager when they are likely to be the LCP element.
I covered the full setup in lazy loading images with an image CDN.
Mistake 2: Your CDN URL Is Optimized, but Your HTML Is Not Responsive
An image CDN URL is not magic if every device requests the same large variant.
This is common on WordPress themes, custom page builders, and quick migrations:
<img
src="https://cdn.example.com/uploads/hero.jpg?width=2400&format=auto"
width="2400"
height="1350"
alt="Hero image"
>
The file may be WebP. It may be compressed. It may be served from a CDN edge.
But mobile is still downloading a 2400 px image for a 390 px viewport.
Better:
<img
src="https://cdn.example.com/uploads/hero.jpg?width=800&format=auto"
srcset="
https://cdn.example.com/uploads/hero.jpg?width=480&format=auto 480w,
https://cdn.example.com/uploads/hero.jpg?width=800&format=auto 800w,
https://cdn.example.com/uploads/hero.jpg?width=1200&format=auto 1200w
"
sizes="100vw"
width="800"
height="450"
fetchpriority="high"
alt="Hero image"
>
Chrome's image delivery insight looks for unnecessarily large downloads, modern formats, compression, and responsive sizing. An image CDN helps with those, but the browser still needs the right candidates.
Do not create endless widths either.
Use a small set of sensible breakpoints like 480, 800, 1200, and 1600. Too many unique widths can hurt cache efficiency.
Mistake 3: The Browser Discovers the Image Too Late
This is the configuration mistake that makes people unfairly blame the CDN.
The CDN cannot download an image before the browser knows the image exists.
Late discovery usually happens when the LCP image is:
- a CSS background image
- injected after JavaScript runs
- inside a carousel
- swapped after hydration
- hidden behind a skeleton loader
- loaded by a tag manager or personalization script
- not present in the initial HTML
Risky:
<div class="hero-image"></div>
.hero-image {
background-image: url("https://cdn.example.com/hero.jpg?width=1200");
}
Better:
<img
src="https://cdn.example.com/hero.jpg?width=1200&format=auto"
width="1200"
height="675"
fetchpriority="high"
alt="Product dashboard"
>
CSS background images can be valid for decoration. They are not my first choice for the main LCP hero.
For LCP, boring HTML usually wins.
Mistake 4: You Did Not Give the LCP Image Priority
Browsers already prioritize resources, but they do not always know which image is the visual winner.
That is where fetchpriority="high" helps.
MDN documents fetchPriority as a browser hint for prioritizing an image fetch, with support across latest devices and browsers since October 2024. It is not a guarantee. It is a signal.
Use it on the one likely LCP image:
<img
src="https://cdn.example.com/hero.jpg?width=1200&format=auto"
width="1200"
height="675"
fetchpriority="high"
alt="Hero image"
>
If the image is discovered late, preload can help:
<link
rel="preload"
as="image"
href="https://cdn.example.com/hero.jpg?width=1200&format=auto"
fetchpriority="high"
>
For responsive images, preload with imagesrcset and imagesizes so the browser can choose the right candidate.
Do not preload every above-the-fold image. That creates competition and can make LCP worse.
One LCP candidate gets priority. The rest should behave normally.
Mistake 5: Your CDN Cache Is Cold or Fragmented
First-request image transforms can be slower than repeat requests.
That is normal. The CDN may need to fetch the original, resize it, convert it, compress it, store the result, and then serve it.
The problem starts when your site keeps generating unique image URLs:
width=781width=782width=783quality=79quality=80quality=81- random cache-busting query strings
- personalized crop values
- unbounded DPR variants
Now the CDN is always doing first-time work.
Fix it by limiting variants:
| Setting | Bad pattern | Better pattern |
|---|---|---|
| Widths | every rendered pixel width | fixed breakpoints |
| Quality | per-template guesses | one default per image type |
| Format | manual format per page | format=auto when supported |
| Crops | random dimensions | named aspect ratios |
| Cache keys | tracking params included | strip non-image params |
For important pages, pre-warm the exact hero variants after deployment.
This matters most for ecommerce, news, landing pages, and pages where the first uncached visitor may be a real buyer.
Mistake 6: You Added a New CDN Hostname Without Thinking About Connection Cost
A CDN can be faster after the connection is ready.
But a new hostname can add DNS, TCP, TLS, and HTTP negotiation before the first image byte arrives. On a warm connection this is less visible. On a cold mobile visit it can matter.
This is not a reason to avoid image CDNs. It is a reason to configure them cleanly.
Use one of these patterns:
- serve images from the same site hostname through a reverse proxy
- use a stable custom CDN hostname like
img.example.com - add
preconnectfor the CDN origin when the LCP image is on that host - avoid splitting critical images across several CDN domains
- make sure HTTP/2 or HTTP/3 is enabled
- keep cache headers long for immutable transformed images
Example:
<link rel="preconnect" href="https://img.example.com" crossorigin>
Do this only for important third-party origins.
Preconnecting to five services just because they exist on the page is not performance work. It is noise.
Mistake 7: Your LCP Problem Is Render Delay, Not Image Delivery
This is the uncomfortable one.
Sometimes the image downloads quickly and still does not render quickly.
Google's LCP guide lists common render-delay causes: render-blocking stylesheets, synchronous scripts in the head, JavaScript that adds the LCP element later, A/B testing tools that hide content, and long main-thread tasks.
In that situation, a smaller CDN image may not move the final LCP number much.
You have to fix the render path:
- reduce render-blocking CSS
- inline only small critical CSS
- remove heavy above-the-fold animations
- avoid hiding the hero until JavaScript finishes
- reduce hydration work
- remove A/B testing flicker wrappers from the hero
- keep the LCP image and text present in server-rendered HTML
This is why I like the LCP subpart breakdown.
It stops you from endlessly compressing an image when the image is already loaded and waiting for the page to render.
The LCP Image Fix Checklist
Use this checklist before changing providers.
1. Confirm the real LCP element
Check mobile and desktop separately. Do not assume the hero image is always LCP.
2. Check when the image request starts
If the request starts late, fix discovery, preload, and priority.
3. Check transfer size
If the image is still huge, fix responsive widths, format, compression, and quality.
4. Check rendered size vs intrinsic size
If a 390 px mobile slot downloads a 2400 px image, the CDN is configured badly.
5. Remove lazy loading from the LCP image
Use lazy loading below the fold, not on the hero.
6. Add explicit dimensions
Use width and height so the browser can reserve space and avoid layout instability. web.dev recommends image dimensions for lazy-loaded images and the same rule is useful for normal images too.
7. Add priority intentionally
Use fetchpriority="high" on the likely LCP image. Use preload only when discovery is genuinely late.
8. Check cache behavior
Look for cache-control, CDN cache hit status, and whether your URL variants are bounded.
9. Check render delay
If the image loads but LCP waits, fix CSS, JavaScript, long tasks, and hydration.
10. Re-test with field data
Lab tests are useful for debugging. CrUX or your own RUM data tells you what real users see after the change.
WordPress Checks
For WordPress, I would check these first:
- featured image is not lazy-loaded when it is above the fold
- theme outputs
srcsetandsizes - CDN plugin is not rewriting URLs twice
- page cache and image plugin are not fighting each other
- first hero image has
widthandheight - slider, animation, or page builder is not hiding the LCP image
- image derivatives are cached and not generated on every request
The common WordPress failure is plugin stacking.
One plugin lazy-loads. Another rewrites images. Another adds WebP. Another adds a CDN URL. The final HTML looks optimized until you inspect the real LCP image and see the browser gets mixed signals.
Pick one tool to own image optimization.
For provider selection, start with best image CDNs for WordPress.
Next.js Checks
For Next.js, check the component output, not only the React code.
The final HTML should include the right image URL, dimensions, srcset, and priority behavior.
For a likely LCP image:
<Image
src="/hero.jpg"
alt="Product dashboard"
width={1200}
height={675}
fetchPriority="high"
/>
If the image is discovered too late, use the current Next.js image API intentionally. The Next.js Image docs say Next.js 16 deprecates priority in favor of clearer preload behavior, and loading="eager" or fetchPriority="high" is enough in most cases.
Do not use preload, loading="eager", and fetchPriority="high" everywhere.
One page can have only one real LCP winner per viewport. Treat it that way.
For loaders, static export, and CDN provider tradeoffs, use the Image CDN for Next.js guide.
Should You Switch Image CDN Providers?
Sometimes, yes.
But only after you know the provider is the bottleneck.
Switch providers when:
- the CDN cannot generate the widths you need
- format negotiation is weak or missing
- transform latency is consistently high
- cache hit ratio stays poor even with bounded URLs
- the provider is far from your main audience
- pricing forces you to avoid good responsive variants
- debugging headers are missing
Do not switch providers when:
- the LCP image is lazy-loaded
- the image is injected after JavaScript
- your HTML requests one giant variant
- your TTFB is already too slow
- CSS or JavaScript blocks rendering
- the LCP element is text
If you are choosing from scratch, compare the best image CDNs and the paid image CDN options.
The cheapest useful test is often BunnyCDN Optimizer because the cost is predictable. Use coupon THEWPX for $5 free credit through this BunnyCDN signup link if you want to test it on a real page.
FAQ
Frequently Asked Questions
Why is my LCP still slow after adding an image CDN?
Because the CDN may only be fixing resource load duration. If your LCP image is discovered late, lazy-loaded, blocked by JavaScript, or waiting behind render-blocking CSS, the final LCP number can stay bad even when the image file is smaller.
Can an image CDN make LCP worse?
Yes, if it adds a new connection cost, generates cold variants on every request, serves the wrong image size, or breaks the original responsive image markup. The fix is usually configuration, not abandoning CDNs.
Should I preload my CDN hero image?
Preload only the likely LCP image when discovery is late. If the image is already present early in the HTML, fetchpriority="high" is often enough. Do not preload several competing hero images.
Is WebP or AVIF enough to fix LCP?
No. WebP and AVIF reduce bytes, but LCP also depends on discovery, priority, TTFB, cache behavior, dimensions, and render delay. A smaller image can still be late if the browser starts the request late.
What is the fastest way to debug image CDN LCP?
Find the LCP element, then check request start time, transfer size, rendered size, file format, cache status, priority, lazy-loading, and render delay. That tells you whether to fix CDN settings, HTML markup, or frontend rendering.
Does `fetchpriority=high` replace an image CDN?
No. fetchpriority="high" tells the browser which image to fetch sooner. An image CDN makes the fetched image smaller, correctly sized, cached, and closer to the user. They solve different parts of the LCP problem.
Summing Up!
If your image CDN is not improving LCP, do not panic and do not switch providers immediately.
First, inspect the LCP breakdown. If the image download itself is slow, fix CDN format, compression, width, quality, cache, and edge delivery. If the request starts late or rendering waits after the image loads, fix your HTML, priority hints, CSS, JavaScript, and framework setup.
My practical rule is simple: CDN fixes bytes. HTML fixes discovery. Frontend performance fixes render delay. You need all three before LCP becomes consistently good.