Lazy Loading
How lazy loading images and iframes improves Core Web Vitals, the loading attribute, the SEO risks of lazy-loading above-the-fold content, and how Googlebot renders deferred content.
Lazy loading defers off-screen images and iframes until they're about to scroll into view, cutting initial page weight and helping Core Web Vitals. The native way is the loading="lazy" attribute on <img> and <iframe> — no JavaScript needed. The big mistake is lazy-loading your hero/LCP image, which delays Largest Contentful Paint. Googlebot doesn't scroll or click, so anything gated behind a scroll or click event can go unseen. It's not a direct ranking factor — the effect runs through Core Web Vitals and crawlability. Verify what actually renders in Search Console's URL Inspection Tool: the image URLs should sit in the src attribute of the rendered HTML.
TL;DR — Lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. tells the browser to hold off downloading images and embeds until you’re about to scroll to them, so the page loads faster up front. The easy, no-code way is to add
loading="lazy"to an<img>or<iframe>. The one rule to remember: don’t lazy-load the big image at the top of the page — that makes the page feel slower, not faster.
What lazy loading is
Normally, when a browser opens a page, it tries to download everything on it — every image, every embedded map or video — right away. On a long page with lots of images, that’s a lot of downloading for stuff you might never scroll down to see.
Lazy loading fixes that. It defers loading the off-screen images and embeds until you’re about to scroll them into view. The page shows you what’s at the top quickly, and the rest loads as you go. Less data up front means a faster first impression, plus savings on bandwidth and battery — which matters most on phones.
The easy way: the loading attribute
You used to need a JavaScript library to do this. Not anymore. Modern browsers have it built in. You just add one attribute:
<img src="photo.jpg" loading="lazy" alt="…">That’s it. It works on <img> and <iframe> (think embedded YouTube videos, Google
Maps, social widgets) in every major browser, with no JavaScript.
The one mistake to avoid
Don’t lazy-load the big image at the top of the page — the hero image, the thing people see first. Lazy loading tells the browser “this can wait,” so a lazy-loaded top image loads later than it should, and the page feels slower. Google’s own guidance is to skip lazy loading for anything that’s visible right away when the page opens.
The short version: lazy-load the stuff below the fold, load the stuff above the fold normally.
Stop deferring a confirmed LCP image
htmlBefore
removed
<img
src="/images/hero.webp"
Removed line.
loading="lazy"
alt="Trail shoes on a mountain path">
Fixed
added
<img
src="/images/hero.webp"
Added line.
loading="eager"
Added line.
fetchpriority="high"
Added line.
width="1600"
Added line.
height="900"
alt="Trail shoes on a mountain path">
- The browser no longer receives a lazy-loading hint for the LCP candidate.
- High fetch priority helps the known critical image compete earlier.
- Intrinsic dimensions reserve its layout space.
Does it hurt SEO?
By itself, no. Google can indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. lazy-loaded images and content just fine when it’s
done the normal way. The trouble starts only when a page hides content behind
scrolling or clicking — because search engines don’t scroll or click. If your images
just use loading="lazy", you’re fine. Want the details on how Google actually sees
this, and how to check it? Switch to the Advanced tab.
TL;DR — Lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. defers off-screen images and iframesHTML element that displays one webpage inside another — how embeds work. until they near the viewport, cutting initial page weight (helps LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good.) and startup main-thread work (helps INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good.). The native
loading="lazy"attribute on<img>/<iframe>has replaced most JS libraries; onlylazyandeagerare meaningful values (autois deprecated). The damaging mistakes: lazy-loading the LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good./above-the-fold image (delays the very metric you’re chasing), and gating content behind scroll/click — which GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. never triggers because it doesn’t interact with the page. It’s not a direct ranking factor; the effect runs through Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. and crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index.. Verify in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results.’s URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. that image URLs land in thesrcattribute of the rendered HTML.
What lazy loading actually does
The idea is simple: only load resources when you need them, instead of loading everything at once. On a media-heavy page, downloading every image and embed up front keeps the browser busy fetching things the visitor may never scroll to — burning bandwidth, memory, and battery for nothing. Deferring the off-screen ones lets the above-the-fold content paint sooner. Martin Splitt made exactly this point on Google’s Search Off the Record episode “Lazy loading demystified”: the goal is to avoid work that yields nothing, because non-critical images the page would be fine without just keep the browser occupied.
This connects to the Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. most people are chasing. Fewer bytes competing for the network up front means the Largest Contentful Paint element can render sooner. For iframes — ads, social widgets, comment sections, maps — deferring them also cuts main-thread work during startup, which is an Interaction to Next Paint win, not just an LCP one. Google’s own web.dev guidance frames lazy-loaded iframes as an INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. improvement during page load.
Native vs. JavaScript-driven lazy loading
A few years ago, browsers gained a native loading attribute for images and iframes,
so you can hand the whole job to the browser instead of wiring up a JavaScript API. In
my JavaScript SEO guide at Ahrefs I make the
same observation: since I first wrote that piece, lazy loading has mostly moved from
being JavaScript-driven to being handled by browsers. You’ll still run into JS-driven
setups, and for images they’re usually fine — the thing I check is whether actual
content (not just images) is being lazy loaded, because those setups are the ones
that have caused content not to be picked up correctly.
The native version:
<!-- Below-the-fold image: defer it -->
<img src="gallery-07.jpg" loading="lazy" width="800" height="600" alt="…">
<!-- Off-screen embed: defer it -->
<iframe src="https://www.youtube.com/embed/…" loading="lazy" title="…"></iframe>Always set explicit width/height (or an aspect-ratio) on lazy images so the browser
reserves the space before the image loads — that’s the biggest layout-shift risk with
deferred images. Reserved dimensions aren’t an absolute CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. guarantee, though: if the
surrounding layout or a responsive crop still changes after the image loads, you can
still see a shift, so confirm with a real layout-shift trace rather than assuming fixed
dimensions alone settle it.
Lazy loading and iframes need one more distinction: loading="lazy" on an <iframe>
only defers when the embed’s fetch and creation happen. It doesn’t set its title,
focus behavior, sandbox, allow/permissions policy, referrerpolicy, consent
handling, or dimensions for you — those still need their own attention, and an embed
can keep doing work (scripts, tracking pixels, layout) once it becomes eligible to
load. And don’t assume “below the fold” behaves the same everywhere: display: none
content, offscreen carousel slides, transformed elements, and nested scroll containers
can intersect the viewport differently than a plain below-the-fold element, so test the
actual layout and navigation controls rather than assuming equivalence.
The loading attribute’s values
Only two values matter today:
loading="lazy"— defer the resource until it’s near the viewport.loading="eager"— load it immediately, the default behavior. Use it to be explicit about above-the-fold images.
You may see loading="auto" in older articles — it’s deprecated in Chrome, so
don’t reach for it. There’s no need to; omitting the attribute already gives you the
default (eager) behavior.
How near is “near”? loading="lazy" is a hint, not an author-controlled guarantee —
the spec leaves the actual near-viewport decision to the browser. Chromium tries to
fetch a lazy resource early enough that it’s ready by the time you scroll to it, and
the trigger distance varies by browser, connection speed, and resource type; it isn’t
a fixed pixel value you can rely on or reproduce across browsers or versions. Don’t
publish — or trust — a specific “loads N pixels before the viewport” number; treat the
near-viewport window as implementation-defined and confirm actual behavior with a
Network trace on the browser/connection you care about instead of assuming a constant.
Native lazy loading also plays fine with responsive images: it applies to ordinary
src and srcset/sizes selection, so you don’t lose responsive image behavior by
adding loading="lazy". If you instead hide the real URL only in a data-* attribute
for a script to swap in later, loading now depends on that script — test the rendered
HTML and what happens if the script fails (more on this in the Scripts and
Troubleshooting tabs).
The #1 mistake: lazy-loading the LCP / above-the-fold image
This is the failure I see most, and every source agrees on it. If you lazy-load the hero image — or any image likely to be the LCP element — you’ve told the browser to wait on the single most important pixel for perceived load speed. The browser also can’t lazy-load an image until it knows where the image will sit on the page, so lazy above-the-fold images tend to load more slowly than eager ones. That directly delays Largest Contentful Paint, the metric Google says should resolve within the first 2.5 seconds of load.
The eager path discovers the likely LCP image in HTML and starts its request promptly. The lazy path waits for browser loading heuristics before request start. The comparison uses no fixed timing values and notes that actual LCP must be measured.
© Patrick Stox LLC · CC BY 4.0 ·
Splitt put the flip side plainly on the SOTR episode: if you’re not using lazy loading where you should, that will probably hurt some aspect of Core Web VitalsWeb Vitals is Google's initiative (launched May 2020) for unified page-experience quality signals. Core Web Vitals — LCP, INP, and CLS — are the subset used in ranking; the rest (TTFB, FCP, TBT, Speed Index) are diagnostic, not ranking factors. — most likely LCP. So it cuts both ways. The rule:
- Probable or observed LCP candidate → load eagerly (omit
loading="lazy", or seteager). Considerfetchpriority="high"on the LCP image. - Below the fold →
loading="lazy".
Not every image above the fold is the LCP candidate — identify the actual one (a
Performance trace or PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. will name it) and verify its request timing
rather than treating every first-screen image the same. And these are separate hints,
not one setting: loading="eager" (or omitting loading) only means the browser
won’t defer discovery of the resource — it doesn’t itself raise fetch priority.
fetchpriority is a distinct, advisory hint on top of that. Stacking a <link rel="preload"> with loading="lazy" on the same resource sends the browser
conflicting intent, so check the actual network waterfall rather than assuming the
combination does what you expect.
The blanket anti-pattern is switching on lazy loading for every image site-wide — a common CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. default. As Splitt noted, if every image is lazy loaded, then images that are (or should be) immediately visible get lazy loaded too, which is exactly the case you want to avoid.
How Googlebot renders lazy-loaded content
Here’s the crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. reality that trips people up: GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll, and it doesn’t click. It renders your page with a headless browser, but it doesn’t simulate a user interacting with it. Google states this directly — its recommended lazy-loading methods deliberately don’t rely on user actions like scrolling or clicking, because Google Search does not interact with your page.
Evidence for this claim Google Search does not scroll or click to trigger lazy-loaded content, so implementations should not depend on user interaction and should expose resource URLs in rendered HTML. Scope: Google Search guidance for JavaScript-driven lazy loading. Confidence: high · Verified: Google Search Central: Lazy-load contentThat’s why the how of your implementation matters. Google’s doc lists three implementations it considers safe: the browser’s built-in lazy loading for images and iframes, the IntersectionObserver API (with a polyfill), or a JavaScript library that loads data as it enters the viewport. All three key off viewport intersection — not a scroll or click event that Googlebot will never fire.
The high-risk pattern is a custom or third-party JS lazy-load library. If the library
misbehaves and the image URL never lands in the src attribute, Google simply won’t
pick that image up — Splitt described exactly this failure mode on the SOTR episode.
There’s nothing to index if the URL isn’t there. This is the same thing I flag in
my JavaScript SEO guide: image lazy loading
is usually fine, but lazy-loaded content is where indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. problems creep in, and the
fix is to check what Google actually renders.
Infinite scroll is a different problem
Don’t conflate basic image/iframe lazy loading with infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. or paginated
loading. Deferring images is one thing; loading new chunks of content as the user
scrolls is another, and it needs its own architecture. Google’s guidance: give each
chunk a persistent, unique URL, keep the content stable per URL (use absolute page
numbers like ?page=12, not relative values like ?date=yesterday), and update the
displayed URL with the History API as each chunk becomes the primary visible content
so it can be refreshed, shared, and linked. Skip that and the deeper content behind an
endless scroll may never be reliably crawled or indexed.
How to test it
The verification path is the same in Google’s doc and in my own methodology: use
Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.’s URL Inspection ToolA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. and look at the rendered HTML. If your
image (or video) URLs appear in the src attribute on the <img>/<video> elements
in that rendered HTML, your setup works. Google says this outright — check the
rendered HTML to make sure your content is in it.
If the URL is missing from src, that’s your problem, and it usually points back to a
scroll/click trigger or a broken library.
You can also lean on your web-performance tooling: PageSpeed Insights flags off-screen images you should be deferring. In my PageSpeed Insights guide at Ahrefs I note that the “defer offscreen elements” audit is telling you to lazy-load images — a handy way to connect the diagnostic you already run to the fix.
Ranking-signal honesty
Be clear about what lazy loading is and isn’t. Using it is not a direct ranking factor, and not using it isn’t a penalty. The connection to rankings is indirect: it flows through Core Web Vitals (mainly LCP, sometimes INP for iframes) and through crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index., if a bad implementation hides content. Splitt characterized the ranking effect through Core Web Vitals as a tiny, minute factor in most cases. So optimize lazy loading for your users’ load experience and for clean indexing — not because you expect a ranking bump from the attribute itself.
Where this fits
Lazy loading is one lever in the broader web performance toolkit. It pairs with resource hintsResource hints are <link> elements (or equivalent HTTP Link headers) that tell the browser to do network work — DNS lookups, connection setup, or fetching a resource — earlier than it would discover the need on its own. The main ones are dns-prefetch, preconnect, preload, modulepreload, and prefetch. (preload/preconnect for the resources you do want early), font-loading strategy, caching, and a CDN — and it’s judged, ultimately, through Core Web Vitals. Get the above-the-fold/below-the-fold split right and it’s one of the cheapest wins available.
AI summary
A condensed take on the Advanced version:
- Lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. defers off-screen images and iframesHTML element that displays one webpage inside another — how embeds work. until they near the viewport —
cutting initial page weight and startup work. The native, no-JS way is
loading="lazy"on<img>and<iframe>; it has largely replaced JS libraries. It’s a browser hint, not a guaranteed distance or timing — the trigger point varies by browser, connection, and resource type, so don’t rely on a fixed pixel number. - Values: only
lazyandeagermatter.autois deprecated in Chrome. - Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. link: fewer up-front bytes help LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good.; deferring iframes cuts
main-thread work at startup, helping INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good.. Set
width/heightso deferred images don’t cause CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. — though reserved dimensions alone don’t guarantee zero shift if the surrounding layout still changes. - #1 mistake: lazy-loading the probable/observed LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image, not just any
above-the-fold image. It delays Largest Contentful Paint, which Google says should
resolve within 2.5s.
eager/omittingloadingonly affects discovery — it doesn’t itself raise fetch priority;fetchpriorityis a separate hint, and stackingpreloadwithloading="lazy"on the same resource conflicts. Blanket site-wide lazy loading is the common CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. anti-pattern. - Iframes get their own contract:
loading="lazy"only defers fetch/creation timing — title, sandbox, permissions policy, referrer policy, consent, and dimensions still need setting independently, and hidden/carousel/transformed layouts can intersect the viewport differently than a plain below-the-fold element. - GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll or click. Any content gated behind scroll/click events can go unseen. Google’s safe methods — native lazy loading, IntersectionObserver, or a well-behaved JS library — all key off viewport intersection.
- Highest risk: custom/third-party JS lazy-load libraries. If the URL never lands
in
src, Google won’t indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. the image (per Martin Splitt). - Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. is distinct: it needs unique paginated URLs + History API.
- Verify in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL Inspection → rendered HTML → image URLs present in
the
srcattribute. - Not a direct ranking factor. The effect is indirect, via Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. and crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index., and Splitt called the Core-Web-Vitals ranking effect tiny.
Official documentation
Primary-source guidance from the search engines and Google’s web.dev.
Google — Search Central
- Fix Lazy-Loaded Website Content — the definitive doc: safe implementation methods, the “Google doesn’t interact with your page” rule, infinite-scroll/paginated-loading requirements, and how to verify in rendered HTML.
- Understand JavaScript SEO Basics — recommends lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. images as a bandwidth/performance best practice and links out to the dedicated guide.
- Core Web Vitals — why lazy-loading the LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. element is self-defeating (LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. target is 2.5s).
Google — web.dev (Learn Performance)
- Lazy load images and
<iframe>elements — when to defer, and the INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. benefit of lazy iframesHTML element that displays one webpage inside another — how embeds work.. - Browser-level image lazy loading for the web — the native attribute, and why not to lazy-load in-viewport/LCP images.
- It’s time to lazy-load offscreen iframes! — the iframe-specific case (ads, widgets, maps).
- Browser-level lazy loading for CMSs — guidance for CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. platforms.
Google — podcast
- Search Off the Record — Ep. 98, “Lazy loading demystified” (Aug 21, 2025) — John Mueller and Martin Splitt on lazy loading, renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data.. Also indexed on Google’s Search Off the Record page.
Developer reference (not SEO-specific, but authoritative on the API)
- MDN — Lazy loading (Performance guide)
- MDN — HTMLImageElement: loading property
- caniuse — Lazy loading via attribute for images & iframes
Bing / Microsoft
- Bing publishes no dedicated lazy-loading document. Its general Webmaster Guidelines cover crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. and JS renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. broadly. BingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. renders with a Chromium-based headless browser and, like GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer., does not scroll or click — so the same native
loading="lazy"/ IntersectionObserver approach that satisfies Google should satisfy Bing. That last point is an inference from BingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share.’s general rendering behavior, not a sourced Bing statement about lazy loading — treat it accordingly.
Quotes from the source
On-the-record statements from Google’s official documentation. Each link is a deep link that jumps to the quoted passage on the source page.
Google — Search Central, “Fix Lazy-Loaded Website Content”
- “Deferring loading of non-critical or non-visible content, also commonly known as ‘lazy-loading’, is a common performance and UX best practice.” Jump to quote
- “However, if not implemented correctly, this technique can inadvertently hide content from Google. This document explains how to make sure Google can crawl and indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. lazy-loaded content.” Jump to quote
- “The methods mentioned don’t rely on user actions, such as scrolling or clicking, to load content, which is important as Google Search does not interact with your page.” Jump to quote
- “Don’t add lazy-loading to content that is likely to be immediately visible when a user opens a page. That might cause content to take longer to load and show up in the browser, which will be very noticeable to the user.” Jump to quote
- “Give each chunk its own persistent, unique URL.” — on infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. / paginated loading. Jump to quote
Lazy-loading checklist
Run this before you ship a lazy-loading change:
- The hero / LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image is NOT lazy-loaded — it loads eagerly (omit
loading="lazy"), ideally withfetchpriority="high". -
loading="lazy"is applied to images and iframesHTML element that displays one webpage inside another — how embeds work. that sit below the fold. - Lazy images have explicit
width/height(oraspect-ratio) so they don’t cause layout shiftCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. (CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.) when they load in. - No content is gated behind a scroll or click event — GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. won’t fire those. Use native lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. or IntersectionObserver instead.
- You’re not using the deprecated
loading="auto"value — onlylazy/eager. - Off-screen iframes (embeds, ads, maps, widgets) use
loading="lazy"to cut startup main-thread work. - Lazy-loaded iframes still have their own
title,sandbox,allow/permissions policy,referrerpolicy, and explicit dimensions —loading="lazy"only defers fetch timing, not those attributes. - Verified in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → rendered HTML that image/video
URLs appear in the
srcattribute. - If using a third-party JS lazy-load library, confirmed the
srcstill ends up populated in the rendered HTML. - For infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page., each chunk has a unique, persistent, paginated URL and the History API updates the displayed URL.
- PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking.’ “defer offscreen images” flags are addressed.
Lazy-loading anti-patterns (myths and mistakes)
Each of these is a common belief or habit, why it’s wrong, and what to do instead.
“Lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. is always good, so apply it to every image.” Why it’s wrong: blanket site-wide lazy loading catches your hero/LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image too, which delays Largest Contentful Paint — the opposite of the speed win you wanted. Do instead: lazy-load below-the-fold only; load above-the-fold images eagerly.
“Google doesn’t indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. lazy-loaded content at all.” Why it’s wrong: Google crawls and indexes lazy-loaded content fine when it’s done with native lazy loading, IntersectionObserver, or a well-behaved library. The risk is specific to scroll/click-gated or broken setups — per Google’s own wording, the problem is when it’s “not implemented correctly.” Do instead: use a viewport-intersection method and verify in rendered HTML.
“loading='auto' is a good default.”
Why it’s wrong: auto is deprecated in Chrome; recommending it is stale advice.
Do instead: use lazy for off-screen resources, eager (or nothing) for the rest.
“Lazy loading and infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. are the same fix.” Why it’s wrong: they’re distinct. Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. additionally needs unique paginated URLs and History API updates, or the deeper content may never be crawled reliably. Do instead: treat paginated/infinite loading as its own architecture with per-chunk URLs.
“loading='lazy' works on any element.”
Why it’s wrong: it’s specified for <img> and <iframe>. Support for other elements
isn’t part of the core spec the same way.
Do instead: use the attribute on images and iframesHTML element that displays one webpage inside another — how embeds work.; handle other media with an
appropriate technique (for video, a poster image that loads the video on viewport
entry).
“Lazy loading hurts SEO.” Why it’s wrong: lazy loading itself isn’t a penalty. The ranking-relevant effect runs through Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. and is small; poor implementation is what hurts, not the technique. Do instead: implement it correctly, exclude the LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image, and verify what renders.
Lazy-loading cheat sheet
The loading attribute
| Value | What it does | When to use |
|---|---|---|
loading="lazy" | Defers the resource until it’s near the viewport | Below-the-fold images and iframesHTML element that displays one webpage inside another — how embeds work. |
loading="eager" | Loads immediately (the default) | Above-the-fold / LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. images (or just omit) |
loading="auto" | Deprecated in Chrome — don’t use | — |
Which elements support it
<img>— yes<iframe>— yes- Other elements (video/audio) — not part of the core spec the same way; use a poster-image + load-on-view pattern for video.
Above vs. below the fold
- Above the fold / likely LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. → eager (never lazy). Add
fetchpriority="high"to the LCP image. - Below the fold → lazy.
Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. impact
- Deferring off-screen images → helps LCP (fewer bytes compete up front).
- Deferring off-screen iframes → helps INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. (less startup main-thread work).
- Missing
width/heighton lazy images → can hurt CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. (layout shift on load).
Rules GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. cares about
- GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll or click — no scroll/click-gated content.
- Safe methods: native
loading="lazy", IntersectionObserver, well-behaved JS library. - Verify: URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → rendered HTML → image URL in the
srcattribute. - Infinite scrollInfinite scroll is a loading pattern where content appears automatically as a user scrolls, instead of via numbered pages. Because Googlebot doesn't scroll or click, indexable infinite scroll needs real per-chunk URLs (paginated loading) that update via the History API — otherwise deep content may never be crawled, or worse, get merged into the wrong page. ≠ image lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. — needs unique paginated URLs + History API.
Before / after
Concrete fixes, framed the way you’d hit them in an audit.
1. The hero image is lazy-loaded (LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. delayed)
Before:
<img src="hero.jpg" loading="lazy" alt="Product hero">After:
<img src="hero.jpg" fetchpriority="high" alt="Product hero">Why: the hero is the LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. element. Eager-loading it (and prioritizing the fetch) lets it paint sooner. Lazy-loading it does the opposite.
2. Site-wide blanket lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. from a CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. default
Before: every <img> on the template carries loading="lazy", including the header
logo and the top-of-page featured image.
After: the template loads above-the-fold images eagerly and only applies
loading="lazy" to images rendered below the initial viewport.
Why: blanket lazy loading catches the images that are visible immediately, delaying
what the user (and LCP) sees first.
3. Off-screen embed loading on page load
Before:
<iframe src="https://maps.google.com/…" title="Store map"></iframe>After:
<iframe src="https://maps.google.com/…" loading="lazy" title="Store map"></iframe>Why: the map is below the fold. Deferring it removes its startup cost and helps INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good., since embeds do main-thread work while the page is loading.
4. Custom JS lazy-load leaves src empty for GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.
Before: a library stores the real URL in data-src and swaps it into src on a scroll
event — which GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. never fires, so the rendered HTML shows an empty/placeholder
src.
After: use native loading="lazy" (real URL in src from the start), or an
IntersectionObserver-based library, then confirm in URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. that the URL is
present in the rendered src.
Why: if the URL isn’t in src in the rendered HTML, Google can’t pick the image up.
Find images that should (or shouldn’t) be lazy-loaded
A DevTools Console snippet you can paste on any page to audit the loading attribute.
It lists images with their loading value and whether they’re currently in the
viewport — so you can spot an above-the-fold image marked lazy, or a below-the-fold
one that isn’t.
Chrome DevTools Console
// Audit loading attributes vs. viewport position
[...document.images].forEach(img => {
const r = img.getBoundingClientRect();
const inView = r.top < innerHeight && r.bottom > 0;
const loading = img.getAttribute('loading') || '(none/eager)';
// Flag the two mistakes: in-view + lazy, or off-view + not lazy
const flag =
(inView && loading === 'lazy') ? '⚠ above-the-fold but LAZY' :
(!inView && loading !== 'lazy') ? '· off-screen, not lazy' : '';
console.log(loading.padEnd(14), inView ? 'in-view ' : 'off-view', flag, img.currentSrc || img.src);
}); Grep your source for risky lazy-load patterns
Check your templates/build output for the deprecated auto value and for
data-src-style JS lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. (which can leave src empty for GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.).
macOS / Linux (bash)
# Deprecated loading="auto"
grep -rn 'loading="auto"' ./src
# JS-driven lazy load leaving real URL in data-src (verify these render into src)
grep -rn 'data-src=' ./srcWindows (PowerShell)
# Deprecated loading="auto"
Get-ChildItem -Recurse .\src | Select-String -Pattern 'loading="auto"'
# JS-driven lazy load using data-src
Get-ChildItem -Recurse .\src | Select-String -Pattern 'data-src='Remember: data-src isn’t automatically a problem — it’s a prompt to confirm the real
URL ends up in the rendered src, which you verify in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version..
Hero image starts later after enabling lazy loading
Symptom: LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. gets slower and the hero request begins late in the waterfall.
Likely cause: A global CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. rule added loading="lazy" to an above-the-fold or
LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image.
Fix and confirmation: Remove the lazy attribute from that image, optionally add
fetchpriority="high", and confirm its request starts earlier in a matched trace.
Lazy image appears but shifts the page
Symptom: Content jumps when a deferred image enters the viewport.
Likely cause: The image has no explicit dimensions or reserved aspect ratio.
Fix and confirmation: Add width and height attributes or reserve the same
aspect ratio in CSS. Reload with layout-shift regions enabled and verify the image no
longer moves surrounding content.
Google does not see deferred content
Symptom: A rendered inspection is missing the image URL or content that appears after a human scrolls.
Likely cause: A scroll/click handler never runs for GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer., or a lazy-load
library leaves the real URL in data-src instead of the rendered src.
Fix and confirmation: Use native lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript. or an IntersectionObserver-based implementation, then inspect the rendered HTML and confirm the final URL and content are present without interaction.
Off-screen embed still loads immediately
Symptom: A below-the-fold iframeHTML element that displays one webpage inside another — how embeds work. appears in the initial waterfall despite a lazy-loading change.
Likely cause: The attribute is absent from the deployed iframe, a wrapper creates the iframe eagerly, or the embed sits close enough to the viewport for the browser’s load threshold.
Fix and confirmation: Inspect the live DOM and request initiator, test on a long page with a cold cache, and verify the request is deferred until the browser’s near-viewport threshold.
Patrick's relevant free tools
- Page Speed Test & Core Web Vitals Checker — One sentence tells you whether a page passes Core Web Vitals and what to fix first — real Chrome user data (CrUX) with a Lighthouse lab fallback, mobile and desktop side by side, loudly-labeled data sources, and prioritized diagnostic fixes. Plus a bulk origin scorecard with CSV export.
- Core Web Vitals History & Competitor Comparison — Chart 40 weeks of real-Chrome-user Core Web Vitals — p75 LCP, INP, CLS, FCP, and TTFB from the Chrome UX Report — and compare up to 5 origins or URLs on one chart. Plus a competitor Leaderboard that ranks curated groups of SEO and page-speed tools on each metric. Pass/fail scorecards, mobile vs desktop, shareable links, CSV export.
- Hosting Checker — Find a domain's public IP network, CDN or edge platform, DNS and mail-host evidence, and response transfer facts without pretending a proxy reveals the origin.
Tools for implementation and proof
- Chrome DevTools Elements and Network panels: confirm the deployed
loadingattribute, identify which script created an iframeHTML element that displays one webpage inside another — how embeds work., and compare request start times before and after a change. - Chrome DevTools Performance panelThe Performance panel is Chrome DevTools' built-in, local profiler for recording and analyzing how a page loads and runs — CPU, main-thread work, rendering, network, and live Core Web Vitals. The recorded trace is local, lab data from your own browser — not what Googlebot sees — though the panel can optionally show real-user CrUX field data alongside it.: record a load and verify that deferring an embed reduces startup main-thread work without delaying the LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image.
- PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking.: use the off-screen-image diagnostic as a starting list, then separate true below-the-fold candidates from the hero or other immediate content.
- Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version.: inspect rendered HTML and verify that deferred
image URLs end up in
srcand that lazy-loaded content exists without a scroll or click. - The browser viewport and filmstrip: test more than one viewport size. An image below the fold on desktop may be above the fold on a smaller or differently shaped device.
Below-the-fold image deferral
Test to run: Record a cold-load Network trace before and after adding native lazy loading to an image well below the initial viewport.
Expected result: The image request is absent from the initial critical waterfall and begins as the viewport approaches it.
Failure interpretation: The deployed markup lacks the attribute, JavaScript creates or fetches the image eagerly, or the test image is within the browser’s near-viewport threshold.
Monitoring window: Check immediately after deployment across representative mobile and desktop viewport sizes.
Rollback trigger: Roll back if an image visible on initial load is deferred or if the image routinely fails to appear before the user reaches it.
LCP-image exclusion
Test to run: Compare matched performance traces and request waterfalls for the page’s LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image after removing blanket lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript..
Expected result: The LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. image loads eagerly, its request starts earlier, and LCP does not regress.
Failure interpretation: Another template or optimization layer re-adds the attribute, or discovery is still delayed by CSS, JavaScript, or markup.
Monitoring window: Check repeated lab runs immediately, then watch field LCP over the following reporting window.
Rollback trigger: Roll back the surrounding rollout if the change delays other critical resources enough to cause a repeatable LCP regression.
Rendered-content visibility
Test to run: Use URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. to view rendered HTML without interacting with the page and search for the deferred image URL and associated content.
Expected result: The final URL appears in src, and important content is present
in the rendered HTML.
Failure interpretation: The implementation depends on a scroll/click event or the lazy-load script failed during renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM..
Monitoring window: Test every affected template after release and after changing the lazy-load library or CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. image pipeline.
Rollback trigger: Roll back if indexable content or image URLs disappear from the rendered output.
Test yourself: Lazy Loading
Five quick questions on deferring images and iframesHTML element that displays one webpage inside another — how embeds work. without hurting Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. or indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.. Pick an answer for each, then check.
Resources worth your time
My related writing
- JavaScript SEO Issues & Best Practices — where I cover the shift from JS-driven to browser-native lazy loadingLazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading=\"lazy\" HTML attribute, which needs no JavaScript., and why lazy-loaded content (not just images) is the indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. risk.
- Google PageSpeed Insights For SEOs & Developers — connects the “defer offscreen images” audit to lazy loading, plus the rest of the PSIPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. report.
- The Beginner’s Guide to Technical SEO — where performance and renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. fit in the bigger picture.
From around the industry
- Fix Lazy-Loaded Website Content (Google Search Central) — the definitive implementation-and-testing doc.
- Browser-level image lazy loading for the web (web.dev) — the native attribute and the LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. caveat, straight from Google’s performance team.
- It’s time to lazy-load offscreen iframes! (web.dev) — the iframeHTML element that displays one webpage inside another — how embeds work. case and its startup/INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. benefit.
- Lazy loading demystified — Search Off the Record, Ep. 98 (Google) — Mueller and Splitt’s full episode on lazy loading, renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data..
- Lazy loading explained: Speed up your site & UX fast (Search Engine Land) — a thorough industry guide with CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms.-specific notes.
- Lazy loading (Performance guide) (MDN) — the developer-reference view of the API.
- A lazy loading primer for crawlability & indexing success (Oncrawl) — the crawl/index angle in depth.
Lazy Loading
Lazy loading defers loading of off-screen or non-critical resources — usually images and iframes — until they're about to enter the viewport. The native way to do it is the loading="lazy" HTML attribute, which needs no JavaScript.
Related: Core Web Vitals, LCP
Lazy Loading
Lazy loading is a performance technique that defers loading non-critical or off-screen resources — typically images, iframesHTML element that displays one webpage inside another — how embeds work., and video — until they’re needed, usually as they’re about to scroll into the viewport. Instead of downloading every image and embed at page load, the browser requests each deferred resource only when it’s about to become visible. That cuts initial page weight and load time and conserves bandwidth, battery, and memory, which matters most on mobile.
The modern, native way to do this is the HTML loading attribute — loading="lazy" on <img> and <iframe> elements — which is supported across all major browsers with no JavaScript. It has largely replaced the older JavaScript-driven lazy-load libraries, though those still exist.
Done wrong, lazy loading backfires. Applying it to a hero image or the Largest Contentful PaintLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. element delays the very metric it’s meant to help. And gating content behind scroll or click events can hide it from search engines: GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. doesn’t scroll or click, so it never fires those triggers. The lazy-loading effect on rankings runs indirectly through Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. and crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index., not as a direct ranking factor by itself.
Related: Core Web Vitals, LCP
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Revision history
Compare the published article with an archived editorial snapshot. Added and removed words are shown only after you open a comparison.
Updated Jul 26, 2026.
Editorial summary and recorded change details.Summary
Added an inspectable Before / Fixed LCP-image example.
Change details
-
Compared a lazy-loaded, unsized hero with an eager, high-priority, dimensioned image, explicitly scoped to an image already confirmed as the LCP candidate.
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Sharpened the near-viewport threshold, LCP/priority, and iframe/CLS guidance against dated primary sources; dismissed two needs-review claims.
Change details
-
Reframed the native near-viewport trigger as a browser hint with no fixed pixel distance, matching current WHATWG/web.dev guidance, and added a note that native lazy loading still works with srcset/sizes.
-
Distinguished loading="eager" (discovery only) from fetchpriority and preload, and flagged the conflict from combining preload with loading="lazy".
-
Added the iframe-specific contract (title, sandbox, allow, referrerpolicy, consent, dimensions) and hidden/carousel/transformed-layout caveats that loading="lazy" does not cover.
-
Clarified that reserved width/height reduces but doesn't guarantee zero layout shift for lazy images.
Full comparison unavailable — no prior snapshot was archived for this revision.
Updated Jul 17, 2026.
Editorial summary and recorded change details.Summary
Added an eager-versus-lazy loading timeline.
Change details
-
Added a figure comparing above-the-fold eager loading with deferred resource timing.