Lazy Loading
Lazy loading explained: the loading attribute, browser thresholds, the LCP trap, layout shifts, how Googlebot sees lazy-loaded content, infinite scroll, and a practical audit.
- #Page Experience
- #SEO Glossary
- #Web Performance
- #Technical SEO
In Plain English
Lazy loading delays the download of images, iframes, or other resources until they are about to enter the viewport, so the browser can spend its early bandwidth on what the visitor sees first.
Key Takeaways
- Native lazy loading with the loading attribute works for images and iframes in all current major browsers and needs no JavaScript
- Never lazy-load the image that is likely to become the Largest Contentful Paint element or anything else in the first viewport
- Google does not scroll or click, so lazy-loaded content has to load as soon as it becomes visible in the viewport
Deep dive
Quick definition
Lazy loading is a technique that postpones loading a resource until it is actually needed. On the web, that usually means images and iframes further down a page: the browser fetches them shortly before the visitor scrolls them into view instead of downloading everything at once.
The idea is simple. A long category page might contain 60 product images, a video embed, and a map. Most visitors never scroll to the bottom. Downloading all of it up front costs bandwidth and competes with the resources the visitor needs first. Lazy loading lets the browser spend its early network time on the visible part of the page.
The technique has two sides. Used on offscreen media, it saves data and reduces contention. Used on the wrong element, it delays the main image, causes layout shifts, or hides content from crawlers that do not behave like a scrolling person.
How native lazy loading works
Modern browsers support lazy loading directly in HTML through the loading attribute on <img> and <iframe> elements:
html<img src="/images/trail-shoe-side.jpg"
alt="Trail running shoe, side view"
width="800" height="600"
loading="lazy">
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
title="Product video"
width="560" height="315"
loading="lazy"></iframe>
The attribute has two values. lazy defers the request until the element is near the viewport. eager loads it right away, which is also the default when the attribute is missing.
The browser decides what "near" means. According to web.dev, Chromium currently starts loading lazy images about 1,250 pixels before they enter the viewport on fast connections and about 2,500 pixels before on slower ones. Other browsers use their own distances. The point of the margin is that an image should usually be ready by the time the visitor reaches it.
Native lazy loading is supported for images and iframes in all current major browsers. Older browsers simply ignore the attribute and load the resource normally, so it degrades without breaking anything.
Native attribute or JavaScript library
Before the attribute existed, lazy loading was done with JavaScript, and many sites still use libraries.
A typical library pattern stores the real image URL in a data-src attribute, shows a placeholder in src, and swaps the two when an IntersectionObserver reports that the element is close to the viewport. That works, but it adds script, and the real URL only appears in src after the script runs.
Older scripts listened for scroll events instead. Those are the risky ones for SEO, because nothing loads unless something scrolls.
Native lazy loading is the better default for images and iframes. JavaScript still has a place for things the attribute cannot cover:
- CSS background images, which have no
loadingattribute - components or widgets that should only be fetched when they become visible
- content loaded in chunks, such as infinite scroll
When you need a script, IntersectionObserver is the right foundation. It reacts to visibility in the viewport, not to a specific user action.
What lazy loading improves
On a long page with many images, lazy loading reduces the bytes downloaded during the first page view, frees network capacity for the resources that render the first viewport, and saves data for visitors who never scroll. Those benefits are larger on mobile connections.
Iframes are often the biggest win. A single video or map embed can pull in a large amount of script and other resources. Lazy-loading embeds below the fold, or replacing them with a lightweight preview until the visitor clicks, keeps that cost out of the initial load.
Lazy loading is one piece of image optimization, not a replacement for it. A 2 MB hero photo is still a 2 MB hero photo, lazy or not. Correct dimensions, modern formats, compression, and responsive srcset sizes usually matter more.
The LCP trap
The most common lazy loading mistake is applying it to the image that matters most. Largest Contentful Paint, one of the Core Web Vitals, measures when the largest visible element in the viewport has rendered. On many pages that element is a hero image or a product photo.
A lazy image cannot start loading as early as an eager one. The browser first needs layout information to know whether the image is in or near the viewport, so it cannot fetch it from the very first look at the HTML. For an image in the first viewport, that delay goes straight into LCP.
This was not just a theoretical problem. WordPress began adding loading="lazy" to images by default in version 5.5. Analysis later published on web.dev found that lazy-loading images in the first viewport tended to worsen LCP, and WordPress subsequently stopped applying the attribute to the first images on a page.
The fix is straightforward:
- Remove
loading="lazy"from the likely LCP image and from other images in the first viewport. - Consider
fetchpriority="high"on the LCP image so the browser requests it early. - Make sure the LCP image URL is in the initial HTML, not added later by JavaScript.
Lighthouse checks for this. In current versions, the LCP request discovery insight flags an LCP image that is lazy-loaded or hard for the browser to discover early.
Lazy loading and layout shifts
When an image without reserved space loads, everything below it moves. With lazy loading, that often happens while the visitor is already reading, which shows up as Cumulative Layout Shift.
The solution has nothing to do with the loading strategy itself: give every image and iframe width and height attributes, or reserve the space with the CSS aspect-ratio property. The browser can then hold the right space before the file arrives.
How Google handles lazy-loaded content
Google's guidance on lazy loading comes down to one rule: content must load when it becomes visible in the viewport, without user actions such as scrolling, clicking, or typing. Googlebot does not scroll the page the way a person does. A script that waits for a scroll event can leave images, text, or links unloaded in the version Google renders.
Google names three acceptable approaches: the browser's built-in lazy loading for images and iframes, the IntersectionObserver API, or a JavaScript library that loads content when it enters the viewport. All three react to visibility rather than interaction.
For image search, the image URL has to be discoverable. Google indexes images from <img> elements, including those inside <picture>, but not CSS background images. If a library keeps the real URL in data-src and only a placeholder in src, Google sees the real image only if rendering runs the swap. Check the rendered HTML to be sure.
Lazy loading text or links is riskier than lazy loading images. If a section of product descriptions or a list of related articles appears only after interaction, the content and its links may not exist for Google. That is a JavaScript rendering problem as much as a performance one.
Infinite scroll and "load more"
Infinite scroll is lazy loading applied to whole sections of content. It needs extra care, because the items further down a list are often exactly the pages you want crawled.
Google recommends supporting paginated loading: each chunk of content should have its own persistent URL, for example ?page=2, and the page should update the URL with the History API as the visitor scrolls. Each paginated URL should also be reachable through normal links. A "Load more" button that only triggers a script, with no link to a real next page, leaves crawlers stuck on the first chunk.
What not to lazy-load
As a rule of thumb, anything a visitor sees without scrolling should load eagerly:
- the hero image or main product photo
- the logo and above-the-fold icons
- the primary text content of the page
- navigation, including menus and breadcrumb trails
- structured data and metadata
The last point catches some JavaScript setups. Meta tags and preview images belong in the server response. Link preview scrapers for social platforms usually do not run JavaScript at all, so a share image that only appears after a lazy-loading script runs may never be found. If your CMS fills the Open Graph image automatically, check that it points to the real file and not to a lazy-loading placeholder.
A worked example
A recipe site has a long article template: a large hero photo, an ingredient list, twelve step photos, a video embed, and a comment section.
The first version applies loading="lazy" to every image through a theme setting. Field data shows a poor mobile LCP, and the LCP element is the hero photo. Lighthouse confirms that the LCP image is lazy-loaded.
The fix: the hero photo loads eagerly with fetchpriority="high", the twelve step photos stay lazy, every image gets width and height, and the video embed becomes a lightweight preview that loads the player on click. The comment section loads when it enters the viewport via IntersectionObserver, not on scroll events. URL Inspection in Search Console shows the step photos and comments in the rendered HTML.
Common mistakes
- lazy-loading the hero or LCP image
- lazy-loading everything through a global theme switch
- relying on scroll events that crawlers never trigger
- loading text, links, or navigation only after a click
- leaving out
widthandheight, which causes layout shifts - infinite scroll without paginated URLs and real links
- keeping image URLs only in
data-srcand never checking the rendered HTML - expecting lazy loading to fix oversized images
- generating a share image URL from a lazy-loading placeholder
A practical audit
- Identify the LCP element on each key template with Lighthouse or PageSpeed Insights.
- Check whether that element, or anything else in the first viewport, carries
loading="lazy". - Confirm that offscreen images and iframes do use lazy loading where it saves real bytes.
- Verify that every image and iframe has dimensions or a reserved aspect ratio.
- Find any JavaScript lazy loading and check whether it reacts to visibility or to scroll events.
- Use URL Inspection in Search Console to compare the rendered HTML with what you see in the browser.
- Test infinite scroll and "load more" lists for paginated URLs that are linked normally.
- Compare field data before and after a change. A lab improvement does not prove a field improvement.
The Crawl Foundry perspective
Lazy loading problems show up in two places: in performance measurements and in the HTML a crawler gets to see. Crawl Foundry covers both sides in its Site Audit.
For performance, we decided to use the official Lighthouse runner, currently Lighthouse 13, on our own servers rather than passing on numbers from somewhere else. Each measurement runs as an isolated task. The Lighthouse measurement itself costs you nothing extra. Site Audit as a whole is a paid data action, and the price is shown before you start. Lighthouse is lab data, so it tells you whether the LCP image is lazy-loaded on a given run. Whether real visitors are affected still comes from field data.
For content and links, the crawler checks the rendered HTML and shows the internal links it found in the DOM, with source, target, anchor text, and position. If a list of products or related articles is missing from those links, check whether that list loads only after a scroll or click. The Site Audit feature page explains how a crawl and its history are set up.
Related terms
- Page speed
- Web performance optimization
- Page experience metrics
- Mobile SEO
- Video SEO
- Google Search Console
- Indexing
Review sources
- Google Search Central: Fix lazy-loaded content
- Google Search Central: Image SEO best practices
- web.dev: Browser-level image lazy loading for the web
- web.dev: The performance effects of too much lazy loading
- web.dev: Optimize Largest Contentful Paint
- MDN Web Docs: Lazy loading
- WHATWG HTML Standard: Lazy loading attributes
Why It Matters for SEO
Lazy loading saves bandwidth on long pages, but applied to the wrong element it delays the main image, shifts the layout, or hides content and links from crawlers that never scroll.
Common questions
What is Lazy Loading?
Lazy loading delays the download of images, iframes, or other resources until they are about to enter the viewport, so the browser can spend its early bandwidth on what the visitor sees first.
Why does Lazy Loading matter for SEO?
Lazy loading saves bandwidth on long pages, but applied to the wrong element it delays the main image, shifts the layout, or hides content and links from crawlers that never scroll.
Deep blog guides
When you are ready to move from definition to workflow, continue with these practical guides.
Reviewed by
Crawl Foundry Team
Editorial TeamThe Crawl Foundry editorial team.
Measure lazy loading with Lighthouse in Crawl Foundry
Crawl Foundry's Site Audit runs the official Lighthouse runner on its own servers. The Lighthouse measurement itself costs you nothing extra, and the price of the audit is shown before you start.