Few performance tweaks feel as safe as lazy loading. You add one attribute, the browser stops downloading pictures nobody has scrolled to, and the page feels lighter. Then a quarter later someone notices that the hero image arrives late, or that a product grid is missing from the version of the page Google stored. Nothing in the code looked wrong, because lazy loading is not one technique. It is a family of them, and some members keep content away from search engines while others do not.
This guide is written for developers who ship the markup and for SEO specialists who have to explain why a page behaves the way it does. It separates the harmless uses from the harmful ones and ties each rule to Google or web.dev documentation. Alt text, file formats and image sitemaps are deliberately left out, because the article on image SEO and Google Images optimization covers them. The question here is narrower: when you postpone loading something, will the visitor and the crawler still get it?
No search volumes, ranking effects or speed gains are quoted. Those depend on each site and nothing here was measured on one. Where the documentation is silent, this guide says so instead of filling the gap with folklore.
What loading="lazy" Actually Does
The attribute is easy to describe and easy to misjudge. According to the web.dev article on browser-level lazy loading (Opens in a new tab), the value lazy defers an image until it comes near the viewport, while eager is the default and loads the image wherever it sits on the page. The same attribute works on iframe elements, and browsers that do not recognise it simply ignore it, so adding it is safe even where support is missing.
Support and limits worth knowing
The article lists support for images starting with Chrome 77, Edge 79, Firefox 75 and Safari 15.4, and for iframes starting with Chrome 77, Edge 79, Firefox 121 and Safari 16.4. It also lists limits that surprise people. Deferral only happens when JavaScript is enabled. CSS background images cannot use the attribute at all, because it exists only on img and iframe. An image hidden with display none is not loaded, but one hidden with opacity zero still is. When a page is printed, every image loads at once. And the distance at which a browser starts fetching an offscreen image is hardcoded and has been changed over time, so a design should never depend on a particular pixel threshold.
Reserve the space first
The article recommends giving img elements width and height attributes. Without them the browser cannot hold a slot, so the layout jumps when the file arrives and Cumulative Layout Shift suffers. The article adds a second consequence: an image without dimensions can be treated as zero by zero, which may cause a whole gallery to load at once and cancel the saving. Dimensions therefore serve two goals, a stable layout and lazy loading that actually defers anything.
A quick sorting rule
| Resource | Where it appears | Defer it? |
|---|---|---|
| Hero or lead product image | First screen | No, keep the default eager loading |
| Logo in the header | First screen | No |
| Images deep in an article | Below the first screen | Yes |
| Video or map embed near the footer | Below the first screen | Yes |
| Body text, headings, key links | Anywhere | Do not hide behind a user action |
The table is a planning aid, not a verdict. Which images sit on the first screen depends on the viewport, so check desktop and mobile separately.
Above-the-Fold Images: Where Lazy Loading Backfires
The most common mistake is also the easiest to make by accident. A theme, a plugin or a framework component adds loading="lazy" to every image, the hero included, and nobody writes an exception. The browser then treats the largest visible element like any other low priority picture.
What the guidance says
Both major references are explicit. The web.dev article says not to lazy-load images likely to be in the viewport at load, and singles out the Largest Contentful Paint image. Google's guide to lazy-loaded content (Opens in a new tab) advises against deferring content that people will see immediately. The LCP optimization guide (Opens in a new tab) is blunter still and tells you never to lazy-load the LCP image, because doing so delays the resource.
That guide splits LCP into four subparts that add up to the total: time to first byte, resource load delay, resource load duration and element render delay. Its target is 2.5 seconds or less for at least 75 percent of visits, and it describes values above 4.0 seconds as poor. A deferred hero image mostly inflates the load delay, because the browser holds back the download. That reading is an inference from the guide's structure and not a sentence the guide spells out.
Discoverability matters as much as priority
The LCP guide also asks that the LCP resource be discoverable in the initial HTML, so the preload scanner can find it early. An img element with src or srcset in the markup qualifies. A CSS background image does not, and the guide suggests a preload link for that case. Images injected by script, or referenced only in external CSS or JavaScript, wait until that code has run. For the one or two images that are likely to be the LCP element, the guide recommends fetchpriority="high" and warns that using it on many images makes it far less useful. The web.dev lazy loading article adds that combining fetchpriority high with loading lazy is pointless, since the image is still delayed while offscreen.
A short audit
- Capture the first screen on a phone and on a desktop, then list every img visible in it. None should carry loading="lazy".
- Look for global settings such as "add lazy loading to all images" in themes and plugins, and exclude the first image.
- If the main visual is a CSS background, consider a real img element or a preload.
- Give every image its real width and height.
- Reserve fetchpriority="high" for the single image most likely to be the LCP element.
The measurement side, including how field and lab data differ, belongs to the page speed and Core Web Vitals guide. The lesson is simple: defer what lies below the first screen and leave the first screen alone.
Content That Waits for a Scroll: What Google Can Fetch
A late image costs speed. Content that never loads costs the content itself, because the page that gets indexed lacks it. Google's lazy-loading guide states the requirement in one line: your implementation should load all relevant content when it enters the viewport.
The methods Google accepts
The guide names three approaches as safe: the browser's built-in lazy loading for images and iframes, the IntersectionObserver API, and a JavaScript library that loads data when it enters the viewport. It also says loading should not depend on user actions. The page does not spell out every consequence of that sentence, so the practical reading is a design rule: never make content conditional on a click, a key press or a manual scroll event handler. An IntersectionObserver fires when an element intersects the viewport, which is a layout fact and not a gesture, so it fits the rule. A listener that waits for a wheel movement does not.
Why rendering decides everything
The JavaScript SEO basics (Opens in a new tab) page explains the pipeline. Pages that return a 200 status are queued for rendering whether or not they use JavaScript. A page may wait in that queue for a few seconds or longer, and then a headless Chromium renders it. Google parses the rendered HTML for links, queues new URLs for crawling, and uses the rendered HTML to index the page. Content that is not in the rendered HTML therefore cannot be indexed. For lazy loading, that is the whole story: if your deferral code does not put the content into the DOM during rendering, the content is absent from the index.
The same page makes a rule about links: Google can only discover links that are a elements with an href attribute. A "load more" component that builds its links out of clickable div elements may hide the next set of URLs. The page also advises against using URL fragments such as a hash route to load different content, and recommends the History API with real paths.
What the documentation leaves out
The lazy-loading page does not describe how Googlebot picks its viewport size, whether scroll events are processed, or how noscript fallbacks are treated. Treat confident claims about those details with caution. What is documented is enough to build safely: use viewport-based loading and verify the rendered output yourself, as the testing section below shows.
Hypothetical example: reviews behind a button
Take a hypothetical product page whose customer reviews appear only after a visitor presses a "show reviews" button, which triggers a request. Reviews are original content and a trust signal, yet before the press they are not in the page, so a crawler sees none of them. Two repairs are reasonable. The server can render the first group of reviews directly into the HTML, or the review block can move to an IntersectionObserver that loads it when it nears the viewport. Review volume and server cost decide between them. The example is invented and carries no figures.
Iframes, Embeds and Widgets
Deferring an iframe is often the biggest single saving on a page, because an iframe can pull in as many resources as a full page. The attribute works on iframes as described above. For SEO the interesting questions are what the iframe contains and where it sits.
Decorative or supporting embeds
A map, a booking calendar or a video player is rarely the main text of the page. Postponing it does not change what the page is about, as long as the headings, descriptions and links around it stay in the HTML. Give the iframe a meaningful title for accessibility, and do not defer one that appears on the first screen.
Embeds that carry the main content
If the substance of the page lives inside an iframe served from another address, that text belongs to the framed document and may not be treated as your page's content. This is an architectural question separate from lazy loading, and the documents used here do not settle it, so it is flagged and not answered. The practical advice is to keep the central text in your own HTML and use iframes for supporting material.
Click-to-play facades
Many sites show a thumbnail and load the heavy video player only after a click. This is a legitimate way to save resources, but the information around the video, such as the title, a written summary and structured details, should be present in the page without any click. Video discovery is its own topic, covered in the video SEO and YouTube guide.
Hand-built lazy loaders
The common home-made pattern stores the real address in a data attribute such as data-src and leaves src empty until a script swaps it. It works when the script runs. If it does not run during rendering, or its trigger never fires, the HTML contains no image address at all. Google's guide gives a direct check: confirm that image and video URLs show up in the src attributes of img and video elements in the rendered HTML. For new work, prefer the native attribute, and keep custom libraries for cases that need extra behaviour.
Background images and responsive sources
Google's image guidance (Opens in a new tab) says images are found in the src attribute of img elements, including an img inside a picture element, and that Google does not index CSS images. An image that matters for search should therefore be a real img. For responsive images, srcset and picture are fine, but the page recommends keeping an img fallback with a src, because some browsers and crawlers do not support the newer attributes.
Infinite Scroll Without Losing URLs
Infinite scroll appends new items as the visitor moves down. It feels continuous to a person, but a crawler needs an address for every batch of items. Google's lazy-loading guide gives a concrete recipe.
The recipe
- Give each chunk of content a persistent, unique URL.
- Make the content of that URL the same on every load. Absolute page numbers such as ?page=12 are the example given. Relative parameters such as ?date=yesterday change meaning over time and should be avoided.
- Link the paginated URLs to each other in order, so a crawler can walk the series.
- When a new chunk becomes the main visible content, update the address bar with the History API, so refreshing or sharing returns to the same place.
Three setups compared
| Setup | What a crawler can reach | Assessment |
|---|---|---|
| Items appended by a scroll handler, no address changes | Only the first batch | Risky, later items have no URL |
| A "load more" button that fetches items with no separate page | Only the first batch | Risky, depends on a click |
| Real paginated pages with href links, and an infinite scroll layer on top | Every page at its own address | Matches the documented approach |
The third row is a progressive enhancement pattern. The label is ours. Build working, linked pagination first, then let JavaScript make the experience smoother. How canonicals, filters and page counts behave in a shop is covered in the guide to SEO pagination for category pages.
Hypothetical example: a blog archive
Imagine a blog archive that adds older posts as you scroll, with the extra posts living only behind a script endpoint and the address bar never changing. Older posts can be found only if some other page happens to link to them. The repair is to add real archive pages such as /blog?page=2, leave an href link to the next page at the end of each one, and make the scrolling script a layer that fetches those same pages. No numbers are involved.
A Repeatable Test Routine
Many lazy loading faults show up only at a certain viewport width, load order or network speed, so reading code is not enough. The dependable check is to look at what Google produces. The lazy-loading guide itself recommends the URL Inspection tool to confirm that all content loads, that text appears in the rendered HTML, and that image and video URLs appear in the src attributes.
What URL Inspection shows
The URL Inspection tool (Opens in a new tab) offers two views. The indexed version reflects what was most recently indexed and may differ from the current page. The live test fetches the URL in real time and can return different results. From the crawled or tested page you can open the raw HTML, the HTTP headers, JavaScript console messages and the loaded resources, and a rendered screenshot appears only for a successful live test.
The help page also lists limits. The live test does not check sitemaps or referring pages, does not decide the canonical, and follows redirects without showing the final tested URL. A "URL is on Google" result means eligibility, not a promise of appearing in search. There are daily limits per property, and server or DNS errors can be transient, so a failed live test may not match what happened during a real crawl.
Steps
- Inspect the suspect URL in Search Console and run a live test.
- Open the tested page HTML and search for text that your code defers. If it is missing, it did not load.
- Search the src attributes of img and video elements for the deferred media addresses.
- Look at the screenshot for blank or placeholder areas.
- Read the console and resource lists for blocked files, since a blocked script can stop deferred content from ever appearing.
- For infinite scroll, inspect page two and page three by their own URLs.
Checks before you have access
Browser developer tools give a fast first pass. In the network panel, see which images download on first load, and notice whether a first-screen image starts late. In the elements panel, inspect the src of deferred img elements before scrolling. None of this replaces Google's rendering, but it catches obvious faults while you are still building.
Compare source HTML and rendered HTML
Put the page source next to the rendered DOM. Anything in the source does not depend on the rendering step, which makes it the safest place for descriptions, headings and important links. Content that exists only after rendering depends on a queue that, according to the JavaScript SEO page, can take a few seconds or longer. That is fine for a minor aside and a poor bet for the main text. For the wider diagnostic method, see the JavaScript SEO rendering and indexing guide.
Keep checking after launch
Theme updates, plugin versions and new components change lazy loading settings quietly. After each release, repeat the same inspection for the first-screen image, the first product list and at least one paginated URL. The aim is a single statement you can confirm each time: everything deferred is present in the rendered HTML.
Common Mistakes
- Applying lazy loading to every image: the hero image is included and LCP gets worse. Define an exception.
- Skipping dimensions: layout shifts when the file arrives, and a gallery without dimensions may load all at once.
- Tying content to a click or scroll handler: user-triggered content may be missing from the rendered HTML.
- Keeping the real address only in a data attribute: if the script does not run, the HTML has no image address.
- Using a CSS background for a content image: Google does not index CSS images.
- Offering infinite scroll without URLs: later items cannot be discovered.
- Building links from div elements: links without an href may not be found.
- Not testing: code that reads correctly can still render differently.
Frequently Asked Questions
Does loading="lazy" stop Google from indexing my images?
Not when it is used correctly. Google's guide lists the browser's built-in lazy loading among the safe methods. What matters is that the image address sits in the src attribute of an img element and appears in the rendered HTML, which you can confirm in the URL Inspection tool.
Should the first-screen image be lazy loaded?
No. web.dev advises against lazy loading images likely to be visible at load, especially the LCP image, and the LCP guide says never to lazy-load it. Reserve deferral for images below the first screen.
Is content loaded by a scroll or a button click indexed?
It cannot be guaranteed. Google asks that content load when it enters the viewport and not depend on user actions. Content that appears only after a click or a scroll handler may be missing from the rendered HTML, while IntersectionObserver based loading is safer.
What does infinite scroll need for SEO?
Each chunk of content needs a persistent, unique URL that returns the same content on every load, for example an absolute page number. Link those pages in sequence with href anchors and update the address bar with the History API as new content becomes visible.
How do I test lazy loading?
Run a live test in the Search Console URL Inspection tool, open the tested page HTML and confirm that the deferred text and the img and video src addresses are present. Also review the screenshot and the console output.
Conclusion
Lazy loading rewards care. Leave the first screen alone, above all the LCP image, and make everything you postpone load when it enters the viewport and not when someone clicks. In practice that means the native loading attribute for images and iframes, real linked page URLs behind infinite scroll, and a URL Inspection check that the deferred text and media addresses appear in the rendered HTML.
No technique guarantees a ranking or a score. The goal is that visitors and crawlers receive the whole page. Once the technical layer is settled, if you want help with the page copy that sits on top of it, Akua Adforce offers SEO content writing, with scope and terms listed on the product page.
Post a comment
Please log in to leave a comment. Login