Lazy Loading and SEO: What Works and What to Avoid
What Lazy Loading Is and How It Works
Lazy loading is the practice of deferring the loading of off-screen resources (images, iframes, videos) until the user scrolls them into the viewport. Instead of loading all images when the page first loads, only the images visible on screen are loaded immediately — reducing initial page weight, improving load times, and saving bandwidth for users who never scroll to the bottom of a page.
The native HTML lazy loading attribute (loading="lazy") is supported in all modern browsers and requires no JavaScript. Simply add it to your image or iframe element:
How Googlebot Handles Lazy Loading
Google's crawler (Googlebot) renders pages using a modern Chrome-based engine. It does scroll the page during rendering — so in theory, it can trigger lazy-loaded content. In practice, Googlebot's rendering has limits: it doesn't always scroll the full length of a page, and it may not trigger JavaScript-based lazy loading if the IntersectionObserver fires only well below the initial viewport.
For native loading="lazy" on images, Google has confirmed that its crawler handles this correctly and can see lazy-loaded images. The risk is lower for native lazy loading than for JavaScript-based implementations. However, for content that is critical for indexing (like product descriptions, blog text, key headings), never put it inside a lazy-loaded container. Only defer non-critical visual elements.
For JavaScript IntersectionObserver-based lazy loading: if your implementation only triggers after a large scroll distance, Googlebot may not see the content. Use a generous rootMargin (e.g., 200px) so content starts loading well before entering the viewport — this helps both users on slow connections and crawlers with limited scroll simulation.
The Critical Rule: Never Lazy-Load Your LCP Image
This is the most important lazy loading rule for SEO and Core Web Vitals: your LCP image must NOT have loading="lazy". The LCP image is the largest visible element on screen when the page loads — typically a hero image, product photo, or featured image. Lazy loading it tells the browser to defer loading it until it's needed, which directly causes poor LCP scores.
The correct treatment for your LCP image is the opposite: add fetchpriority="high" to tell the browser to load it as soon as possible, and add a <link rel="preload"> hint in your document <head> so the browser discovers it before it parses the image tag in the body. Together, these can improve LCP by 0.5-2 seconds.
Lazy Loading and CLS: Always Set Image Dimensions
Lazy-loaded images cause Cumulative Layout Shift (CLS) when the browser doesn't know their dimensions before they load. The browser allocates no space for the image, renders the surrounding content, and then shifts everything when the image loads and takes up space. This is a major CLS source on pages with many images.
The fix is simple and non-negotiable: always include explicit width and height attributes on every image, including lazy-loaded ones. The browser uses these to reserve the correct amount of space before the image loads, preventing the shift. You can also use the CSS aspect-ratio property as an alternative if you don't know exact pixel dimensions:
Lazy Loading Videos and Iframes: The Facade Pattern
YouTube embeds are one of the most common causes of poor performance scores. A single embedded YouTube video loads over 500KB of JavaScript from YouTube's servers before the user even interacts with it. The solution is the facade pattern: show a static image (the video thumbnail) initially, and only load the actual iframe when the user clicks play.
The Lite YouTube Embed web component is the easiest implementation. It shows the thumbnail, adds a play button overlay, and loads the real iframe only on click — reducing the initial page weight by ~500KB per embedded video. Native loading="lazy" also works on iframes: <iframe loading="lazy" src="..."></iframe> defers the iframe until it's near the viewport, but doesn't prevent all the JavaScript from loading — the facade pattern is significantly better.
Testing If Googlebot Sees Your Lazy-Loaded Content
To verify Googlebot renders your lazy-loaded content: go to Google Search Console > URL Inspection > enter your page URL > click "Test Live URL" > click "View Tested Page" > click the "Screenshot" tab. This shows you exactly what Googlebot's renderer saw when it crawled your page. If lazy-loaded content doesn't appear in the screenshot, Google isn't seeing it.
If critical content is missing from the GSC screenshot, consider moving it out of a lazy-loaded container or adjusting your IntersectionObserver's rootMargin to start loading earlier. Content that only loads after significant scrolling (more than 2-3 viewport heights) is at risk of being missed by Googlebot.