Lazy Loading Images: When It Helps and When It Hurts LCP
Here's a pattern I see in almost every audit that starts with "but I did everything right." A site owner installs a speed plugin, ticks the box for lazy loading images across the whole site, and watches PageSpeed Insights hand back a worse score than before. The warning usually reads something like "Largest Contentful Paint image was lazily loaded," which sounds like a contradiction, because lazy loading is supposed to make pages faster, not slower. It does, for most images. Just not for the one the warning is pointing at.
This confusion sits at the boundary of two layers that rarely get explained together: the HTML attribute that tells the browser what to skip, and the browser's own scheduling logic that decides what to fetch first. Get the two mixed up, and a genuinely useful performance technique turns into a self-inflicted wound on your biggest, most visible image. That's the whole article in one sentence: lazy loading is a below-the-fold tool, and above the fold, particularly on the one image that defines your Largest Contentful Paint (LCP) score, it's the wrong tool entirely.
What Lazy Loading Actually Does
Every browser has a component called the preload scanner. Its job is to read the raw HTML of a page as fast as it arrives, before the page is even laid out, and start fetching the resources it finds: stylesheets, scripts, and images. This is why a page's largest image often starts downloading within milliseconds of the first byte reaching the browser. Speed comes from parallel work, not from waiting politely for one thing to finish before starting the next.
The loading="lazy" attribute (sometimes searched as "loading lazy" without the quotes or equals sign) is an instruction that opts an image out of that early fetch. Put it on an <img> tag, and the preload scanner skips it entirely. The browser waits until it has calculated where that image sits on the page, checks whether it's near the visible viewport, and only then starts the download. A basic example:
<img src="product-thumbnail.jpg" loading="lazy" width="400" height="300" alt="Blue ceramic mug">
For an image far down a long page, this is close to free performance. The browser spends its early bandwidth on things the visitor can actually see, and only fetches the rest as they scroll toward it. The Mozilla Developer Network describes this as the intended use case directly: lazy loading is for off-screen images that need scrolling to reach, not for content that's visible the moment the page renders (MDN, "Lazy loading").
Where lazy loading genuinely helps
Picture a furniture shop with a category page listing sixty products, each with its own thumbnail. Without lazy loading, the browser would try to fetch all sixty images the moment the page loads, competing for bandwidth with the CSS, the fonts, and whatever tracking scripts the marketing team has added over the years. Most of those thumbnails sit below the fold and won't be seen for several seconds, if at all, depending on how far the visitor scrolls.
Lazy loading fixes exactly this kind of waste. Fewer simultaneous requests on page load means the browser's bandwidth goes to what the visitor is actually looking at first. A long-form blog post with a dozen inline screenshots, a news site's related-articles rail, an image-heavy portfolio page: these are the cases lazy loading was built for, and it's the standard, encouraged technique for image content that isn't immediately visible on first render.
The rule of thumb is short enough to keep in your head: if a visitor has to scroll to see it, lazy loading is doing its job. If they don't, it's working against you.
Where it backfires: the LCP image
Largest Contentful Paint measures how long it takes for the biggest visible element (almost always an image, on most pages) to finish rendering after a visitor opens the page. It's one of Google's three Core Web Vitals and a documented ranking signal, which is why a warning about it gets flagged so prominently in PageSpeed Insights and Search Console.
Lazy-loading the LCP candidate does the opposite of what you want. Instead of letting the preload scanner grab that image in the first few milliseconds, loading="lazy" forces the browser to wait for layout to finish, confirm the image is near the viewport, and only then start the fetch. You've taken your biggest, most time-sensitive image and put it at the back of the queue.
The clearest illustration of the cost comes from Google's own team. When Google Flights added fetchpriority="high" to its hero image (the fix that pairs with never lazy-loading it), LCP improved from 2.6 seconds to 1.9 seconds, a 700-millisecond drop on a page that was already reasonably optimized (web.dev, "Optimize resource loading with the Fetch Priority API"). WordPress core ran a broader version of the same experiment: a 50-theme, 200-scenario WebPageTest study found that skipping lazy-loading on just the first content image improved median LCP by 7 percent (1,877ms versus 2,020ms), with 42 percent of scenarios seeing an improvement above 10 percent (Make WordPress Core, "Refining WordPress Core's Lazy-Loading Implementation," 2021). That study is the reason WordPress behaves the way it does today, which I'll get to in a moment.
And it's not a WordPress-only mistake. Even the team behind web.dev shipped loading="lazy" on their own site's LCP image at one point, delaying it until after stylesheets loaded and the page had already calculated its layout, a widely cited example of how easy this is to get wrong even when you know exactly what you're doing (GitHub, GoogleChrome/web.dev issue #5813). I mention it because it's a reassuring kind of mistake. If the people who write the performance guidance can trip on this, a site owner following a generic checklist absolutely can too.
Should the hero image be lazy loaded?
No. If you take one decision rule away from this article, make it that one: don't lazy load hero image banners, product hero shots, or featured images that appear above the fold on first render. These are almost always your LCP candidate, and lazy loading tells the browser to deprioritize the exact resource you most need fetched early.
The fix isn't to leave the hero image unmarked and hope for the best, either. The stronger move is to combine two things: skip loading="lazy" on that one image (either omit the attribute or set it explicitly to loading="eager"), and add fetchpriority="high" so the browser treats it as a priority even among the resources it fetches early. Think of it as two separate dials. One controls when the fetch starts (lazy versus eager), the other controls how urgently the browser treats it relative to everything else competing for bandwidth at the same moment.
fetchpriority="high" explained
fetchpriority is a browser hint, not a lazy-loading replacement. It tells the browser how to rank a resource against everything else it's currently fetching, on a scale that includes high, low, and auto (the default). Setting fetchpriority="high" on your hero image doesn't change when the fetch starts, it changes how much bandwidth priority that fetch gets once it does.
A practical hero image tag combining both fixes looks like this:
<img src="hero-banner.jpg" fetchpriority="high" width="1600" height="900" alt="Autumn collection storefront display">
Notice there's no loading="lazy" attribute at all. That's intentional. The same fetch-priority guidance that explains the Google Flights case above recommends this exact pairing for the LCP image, and reserves fetchpriority="low" for the opposite case: in-viewport assets that aren't shown on load, like carousel slides two and three, which are technically visible in the DOM but not yet on screen. The attribute reached broad cross-browser support relatively recently (it shipped in Chrome 102 and later landed in Safari and Firefox, reaching Baseline status across major browsers in 2024), so if you're working from an older guide that doesn't mention it, that's likely why.
Does lazy loading hurt SEO?
This is the myth I hear most often, and it deserves a direct answer rather than a hedge: implemented correctly, lazy loading does not hurt SEO. Google's own crawling documentation is explicit about this. Googlebot supports native lazy loading, IntersectionObserver-based implementations, and JavaScript libraries, as long as none of them depend on a scroll or click event to fire, since Googlebot doesn't scroll a page the way a human visitor does (Google Search Central, "Fix lazy-loaded content").
Where lazy loading SEO problems actually happen is narrower than most people assume. It's not the attribute itself, it's the implementation: content that only loads after a scroll event, images or text hidden behind a click, or infinite-scroll pages where the content Googlebot needs never renders because nothing ever scrolls. Those are indexing risks. Standard loading="lazy" on an <img> tag isn't one of them.
There's actually an indirect SEO upside to getting this right, which is easy to miss because it's not framed as an "SEO fix." Since LCP is one of the three Core Web Vitals and Google has confirmed page experience signals factor into ranking, correctly scoped lazy loading (below the fold, never on the LCP candidate) contributes to a better Core Web Vitals score. The lazy loading itself isn't a ranking factor. The speed it protects, when applied correctly, can be. If you want the fuller picture of how image choices feed into search visibility beyond Core Web Vitals alone, our image SEO guide covers file names, structured data and how images actually get into Google Images.
How do I lazy load images in WordPress?
WordPress has shipped native lazy loading by default since version 5.5, adding loading="lazy" automatically to most <img> tags in post content. For a while, that included the very first image in a post, which is exactly the scenario that caused the 7 percent LCP regression in WordPress core's own study referenced above.
Core fixed this in version 5.9 (2022) by exempting the first content image and the featured image from automatic lazy loading, on the logic that the first image on a typical post or page is disproportionately likely to be the LCP element. If you're running a reasonably current WordPress install with a standard theme, this part is handled for you without any configuration.
The nuance worth flagging: core's fix covers core's own image-insertion logic. It doesn't reach into every theme or page builder. Some themes and builders (particularly ones that construct hero sections, sliders, or custom headers outside the standard content editor) apply their own lazy-loading logic independently of core, and can still lazy-load a hero banner that core would otherwise have protected.
If you want to force eager loading on a specific image regardless of what a theme does, you can filter it directly with wp_lazy_loading_enabled, or add loading="eager" to an individual image tag if you're editing the template by hand. Worth checking after any theme change, not just once.
Quick self-check: finding lazy-loaded hero images
You don't need to guess whether your own site has this problem. Three ways to check, roughly in order of effort: open PageSpeed Insights and look for an LCP-related warning naming a lazily loaded image directly; open your browser's DevTools, go to the Network panel, and watch whether your hero image fires early or waits until after layout; or view the page source and search for loading="lazy" near the top of the markup, close to your main banner or featured image.
If you'd rather run a single check across a page's full image set, that's exactly what imagecheck.tools does: paste a URL and it flags images that are lazy-loaded above the fold (the lazy_above_fold issue) alongside images missing lazy loading entirely further down the page (no_lazy), plus format, oversized file, and alt text problems in the same pass. It's a faster way to confirm the fix worked than refreshing PageSpeed Insights and waiting for a fresh score each time. The about page walks through exactly what each report checks and, just as importantly, what it doesn't.
The one rule to remember
Below the fold: lazy load it. Above the fold, and especially your LCP candidate: eager-load it and add fetchpriority="high". That's the whole decision tree. Everything else in this article is the reasoning behind those two lines, so you're not just following a rule, you understand why it holds.
If you're auditing a page for other image issues at the same time, our guide to checking alt text across a whole page walks through the same kind of full-page pass for accessibility, and the full tools index lists the sister checkers if a caching or markup issue turns out to sit outside image territory entirely.
Frequently Asked Questions
What is lazy loading?
Lazy loading is a technique that delays fetching an image (or other resource) until it's about to become visible in the viewport, instead of fetching it the moment the page loads. On the web, the most common form is the loading="lazy" HTML attribute on an <img> tag, which tells the browser to skip that image during its early preload scan and fetch it only once layout confirms it's near the visible area.
Should the hero image be lazy loaded?
No. A hero image is almost always the page's LCP candidate, so lazy loading it deprioritizes the fetch of the exact resource that determines your Largest Contentful Paint score. The correct pattern is to leave the hero image eager (no loading="lazy" attribute, or loading="eager" explicitly) and add fetchpriority="high" so the browser treats the fetch as urgent.
Does lazy loading hurt SEO?
Not when it's implemented correctly. Google explicitly supports native lazy loading and IntersectionObserver-based implementations, provided they don't depend on a scroll or click event to trigger, since Googlebot doesn't scroll a page. The real SEO risk lives in scroll-dependent or click-dependent lazy loading, not in the standard loading="lazy" attribute itself.
How do I lazy load images in WordPress?
WordPress has applied loading="lazy" automatically to most content images since version 5.5, and since version 5.9 it exempts the first content image and the featured image from that automatic behavior, because that image is disproportionately likely to be the page's LCP element. Some themes and page builders still apply their own lazy loading to hero sections outside of core's logic, so it's worth checking a new theme's hero markup directly rather than assuming core's fix covers it.