What Is Lazy Loading? How It Affects SEO and Page Speed

Lazy loading is a technique that holds back images, iframes and other embeds until the visitor scrolls near them. I have worked on speed and SEO problems on client sites since 2012. In my experience, lazy loading is one of the most frequently misconfigured parts of that work. This guide covers how to use it well, the most expensive mistake, and what Google expects.
I covered the broader link between speed and rankings in how site speed affects SEO. Here the focus stays narrow. Which elements should you defer, which ones must never wait, and how does a search engine read the result?
What is lazy loading and how does it work?
Lazy loading means the browser postpones downloading off-screen resources such as images, iframes and videos until the user scrolls close to them. As a result, the first view downloads less data, the browser spends its connections on visible content, and visitors never pay for media they never see.
The logic is simple. Normally the browser requests every img tag it finds while parsing the HTML. Even a footer logo competes for bandwidth in the first seconds, although most visitors never reach the footer. Lazy loading puts those resources on a waiting list instead.
As the user scrolls, the browser checks how close each waiting element sits to the viewport. Once an element crosses a certain distance, the download starts. So in a well-built setup the visitor never notices a delay. The image arrives before it enters the screen.
I care about this because long category pages, blog posts and product galleries often carry dozens of images. However, many visitors only see the top part of a page. In other words, every image nobody looks at still costs you server traffic and costs the visitor mobile data.
What problems does lazy loading actually solve?
The benefit grows with page length and media weight. On a short service page the difference stays small. On a category page with hundreds of product cards, on the other hand, the effect becomes obvious.
- It cuts the total amount of data the first view downloads.
- The browser can focus its connections on resources in the viewport.
- It saves mobile visitors from spending data on content they never reach.
- Server and CDN traffic drops for images that nobody views.
- It stops heavy third party embeds, such as maps and video players, from blocking the first view.
One distinction matters here. Lazy loading is a prioritisation tool, not a compression tool. It does not make an image smaller. It only decides when the download happens. So do not expect it to fix every speed problem on its own.
How do you use the loading="lazy" attribute?
My first choice today is the browser's own loading attribute. When you add loading="lazy" to an img or iframe tag, the browser handles the deferral itself. You need no extra JavaScript library for that.
The attribute accepts three values:
- lazy: The browser defers the download until the element approaches the viewport.
- eager: The browser downloads the element right away, wherever it sits.
- auto: The browser decides; in practice it behaves like eager.
If you leave the attribute out, the browser treats the image as eager. The MDN documentation describes the behaviour in detail. Current versions of Chrome, Edge, Firefox and Safari also support it.
In practice I follow two rules. First, every lazy image gets explicit width and height values. Second, I never add the attribute to the whole template blindly. Images at the top of the page need separate treatment, and the next sections explain why.
When does the browser start loading a lazy image?
The browser does not wait until a lazy image is fully on screen. Instead, it starts the request a little earlier. According to the Chrome team's guide on web.dev, that distance depends on connection speed.
The same guide says Chrome refined these thresholds over time. It now uses roughly 1250 pixels on fast connections and roughly 2500 pixels on slower ones. These values can change between browser versions. Therefore, do not hard-code them into your own logic.
What does this mean for you? A user who scrolls at a normal pace rarely sees an empty box. That said, a very fast scroll or a weak connection can make an image arrive a moment late. That is exactly why width and height matter. The browser reserves the space in advance, so the layout does not jump.
My practical takeaway: native lazy loading behaves more sensibly than most older JavaScript libraries. The reason is simple. The browser knows the network conditions better than your script does, and it adjusts the threshold accordingly.
Why should you never lazy load the LCP image?
This is the most common and most expensive mistake I see. LCP marks the moment the largest element in the viewport finishes rendering. On most sites that element is the hero image. When you add loading="lazy" to it, the browser does not request it immediately. First it calculates the layout, then it realises the image sits on screen, and only then does it start the download.
As a result, your most important image becomes one of the last ones the browser discovers. An analysis on web.dev looked at the period when WordPress lazy loaded every image by default. Pages with a lazy LCP image showed worse LCP. WordPress later changed its default to skip the first images.
My rule is strict. No image that appears in the first view gets a lazy attribute. For the hero image specifically, I do the following:
- I remove the loading attribute or set it to eager.
- Adding fetchpriority="high" signals its importance.
- I place it directly in the HTML rather than injecting it with JavaScript.
- I use an img tag instead of a CSS background, so the browser finds it early.
In short, lazy loading speeds up the lower part of a page. At the top, it acts as a brake.
The easiest way to spot this mistake is to open the page source in mobile view and inspect the hero image tag. Also, many themes use separate hero images for desktop and mobile. Check both of them.
Which images should you lazy load and which should load eagerly?
To decide, think about the first screen, the part a visitor sees without scrolling. However, that area changes with the device. A desktop layout might show four product cards up front, while a phone shows only one. For that reason I always check mobile and desktop separately.
| Element | Position | My recommendation |
|---|---|---|
| Hero image, main banner | First screen | No lazy, fetchpriority="high" |
| Logo | Header | No lazy |
| First product cards | First screen or just below | First few eager, rest lazy |
| Images inside blog posts | Middle and bottom of the text | Lazy |
| Review avatars, footer icons | Bottom of the page | Lazy |
| YouTube or map embed | Middle or bottom | Lazy or a preview image |
| Hidden carousel slides | First screen but hidden | First slide eager, others lazy |
A practical method: keep a counter in your template. Mark the first two or three images as eager and the rest as lazy. This number comes from field experience. It is a starting point, not a guarantee, so test it against your own layout.
Can Google see lazy loaded content?
Yes, as long as you implement it correctly. Google explains this clearly in its Search Central guidance on lazy loading. One detail matters most. Googlebot does not scroll, click or type the way a person does.
Instead, Google resizes the viewport to a very tall window while it renders the page. So if your content loads when it becomes visible, Googlebot sees it. But if your content waits for a user action, such as a scroll event or a button click, Googlebot never triggers that action. Consequently, the content never appears in the rendered page.
Google recommends these approaches:
- Use the browser's native loading="lazy" attribute.
- If you need JavaScript, choose a solution built on the IntersectionObserver API.
- Avoid older libraries that listen to scroll events.
- Give every chunk of infinite scroll content its own persistent URL.
That is why my first question in an audit is always the same. Does this content wait for a user action, or does it simply wait to become visible? If it waits for an action, you have an SEO risk.
What SEO problems can lazy loading cause?
A correct setup is search friendly. A broken one, however, causes silent damage. The page looks fine to users while the search engine sees an incomplete version. These are the mistakes I find most often:
- Empty src attributes: The real address lives only in data-src. If the script fails, the image never loads.
- Lazy loaded text: Product descriptions or reviews wait for a scroll event, so Googlebot may miss them.
- No noscript fallback: Older JavaScript setups skip the fallback, and the image never reaches the index.
- Infinite scroll without URLs: Later product groups have no address, so crawlers cannot reach them.
- A lazy LCP image: This hurts your speed signals directly.
On the other hand, lazy loading itself carries no ranking penalty. The technique is fine; the implementation is the problem. So the honest answer to "does lazy loading hurt SEO?" is "only if you set it up wrong". A thorough technical SEO review usually catches most of these issues.
Does lazy loading cause layout shift (CLS)?
It can, but the cause is missing size information rather than the technique itself. CLS measures unexpected movement of elements while the page loads. When a lazy image arrives late and the browser does not know its size, the image pushes the text below it down the page.
The fix is straightforward. Write the real width and height on every img tag. Modern browsers calculate the aspect ratio from those two values and reserve the right height before the image arrives. So even with fluid CSS widths, the placeholder keeps its shape.
Alternatively, you can use the CSS aspect-ratio property. It works well for card layouts that mix different image ratios. The same rule also applies to iframes. If a video container has no fixed ratio, the page jumps when the iframe loads.
I have seen this pattern many times. A team adds lazy loading, the speed score rises a little, and CLS gets worse. Then they blame lazy loading and remove it. In reality, the template simply lacked size attributes. I discuss this balance between speed and experience in SEO and UX page experience factors.
How do you lazy load iframes and video embeds?
Iframes are usually much heavier than images. A single YouTube embed pulls in its own scripts, stylesheets and fonts. Therefore I recommend loading="lazy" on every iframe below the first screen. The web.dev guide on iframe lazy loading confirms the attribute works as a standard for iframes too.
A more advanced option is the facade approach. Instead of the real player, you show the video's thumbnail and a play button. When the user clicks, the page swaps in the real iframe. That way, visitors who never watch the video never download the player code.
The video element works differently. It does not support the loading attribute. Instead I use these settings:
- I set preload="none" or preload="metadata" to stop the file from downloading early.
- I add a lightweight poster image for the first view.
- I avoid autoplay background videos in the first screen wherever possible.
A facade can have an SEO cost, though. Video rich results and video page signals need Google to find the video. So if the video is the main content of the page, add video structured data alongside the facade.
Native lazy loading or a JavaScript library?
For most projects today, my answer is native. The built-in attribute needs no extra code and does not occupy the main thread. It also matches the method Google recommends. That said, JavaScript still has a place in a few cases.
| Criterion | Native (loading="lazy") | JavaScript (IntersectionObserver) |
|---|---|---|
| Setup | One attribute | Script and configuration |
| Extra JavaScript weight | None | Depends on the library |
| Threshold control | The browser decides | You decide |
| CSS background images | Not supported | Supported |
| Googlebot compatibility | Compatible out of the box | Compatible if set up correctly |
| Behaviour on script error | Image still loads | Image may never load |
I only reach for JavaScript in three situations. I might need to defer CSS background images. A component might need to trigger other work when it becomes visible. Or the project might need a very specific loading distance. Meanwhile, I no longer recommend libraries that listen to scroll events. They hurt performance and put Googlebot compatibility at risk.
How do you configure lazy loading in WordPress and site builders?
WordPress has added loading="lazy" to images automatically since version 5.5. Later releases also added logic to skip the first content images. So core WordPress handles most of this well.
The trouble usually comes from plugins and themes. Here is a pattern I see often. Core adds native lazy loading. A speed plugin then adds its own JavaScript solution, and the theme uses a third method for its slider. As a result, three different mechanisms control the same image, and the hero image can end up deferred by accident.
On any platform, I suggest this check:
- Open the page source and find the img tag of the hero image.
- Look for loading="lazy", data-src or any other sign of deferral.
- If more than one lazy loading plugin or setting is active, keep only one.
- If the plugin offers an "exclude the first X images" setting, base it on the mobile layout.
On hosted platforms such as Shopify, your access to the theme code may be limited. In that case, agree on a separate rule for the hero and the first product cards with your theme developer. In e-commerce consulting projects, this is one of the topics that takes the most coordination.
How should infinite scroll and lazy loading work together?
Infinite scroll is lazy loading at the content level. As the user scrolls, the page appends new products or posts. It feels smooth for users. For search engines, however, it creates a real risk, because Googlebot does not scroll and may never see anything after the first batch.
Google's position is clear: every chunk of content needs its own persistent URL. In practice I build it like this:
- I keep classic pagination underneath, such as category/page-2 and category/page-3.
- As the user scrolls, I load the next batch and update the address bar with the History API.
- Every paginated URL also works when someone opens it directly.
- I keep normal a tags linking the paginated pages.
This way users get the infinite scroll experience, and Googlebot crawls each batch as a separate page. The setup matters most on large catalogues. Moreover, users can return to the exact spot after visiting a product, which improves the experience too.
How do you test for lazy loading problems?
I never rely on a single tool, because each tool answers a different question. This is the order I use:
- Lighthouse: I look for the warning about a lazy loaded LCP image and the suggestion to defer off-screen images. I explain the full process in my Lighthouse performance test guide.
- Search Console URL Inspection: I run a live test and check whether the images appear in the rendered HTML and the screenshot.
- Browser developer tools: I open the Network tab and watch which images download before I scroll.
- JavaScript disabled test: I turn scripts off and confirm the key images still show up.
The rendered HTML check in Search Console matters most. What you see there is what Google actually reads. If product images or review text do not appear in that HTML, the page looks incomplete to the search engine, no matter how good it looks to users.
Does lazy loading affect Google Images traffic?
Not if you set it up correctly. Google needs the image address to index an image. With native loading="lazy", the real address stays in the src attribute, so Google finds the image without trouble.
The risk comes from older JavaScript solutions. They place a tiny placeholder in src and hide the real address in data-src. If the script runs, everything works. But if the script fails or does not fire during rendering, Google only sees the placeholder.
So for sites that earn traffic from image search, I suggest a few safeguards. Always keep the real address in src. Add important images to an image sitemap. Write descriptive alt text. Also, check regularly that product images appear in the HTML Google renders. File size and format are a separate topic that I leave out here. If you need a correctly sized file, the image resizer tool can help.
What is the difference between lazy loading and preload?
These two techniques are opposites, and people mix them up constantly. Lazy loading delays a resource. Preload pulls a resource forward. One tells the browser "do not request this yet", and the other says "request this now, you will need it soon".
I mostly use preload for critical resources the browser would otherwise discover late. For example, when a CSS background image is the LCP element, the browser only finds it after it reads the stylesheet. In that case I add a preload line in the head. On the other hand, preloading everything is also a mistake. Every file you pull forward competes with other important files for bandwidth.
So the right setup is simple. Pull the critical first-screen image forward, and defer the images below it. Giving the same image both preload and lazy sends a contradictory signal. I still find that combination in audits from time to time.
Why does lazy loading matter more on mobile?
On mobile devices the screen is small and the connection often varies. A desktop visitor might see four product cards on the first screen. A phone user sees one. Therefore mobile pages have many more images you can safely defer.
Mobile visitors also often browse on a data plan. Downloading a gallery they will never see costs them real money. That is why I base lazy loading decisions on the mobile layout first, and then I check desktop.
Mobile also hides a trap. An "eager for the first three images" rule designed for desktop may pull too many images forward on a phone. The reverse also happens. An image that sits in the mobile first screen may get a lazy flag because it appears lower in the desktop template. So test both layouts separately.
What steps should you follow when setting up lazy loading?
Whether I work on a new project or an existing site, I follow the same order. This list is not a guarantee. It is simply a routine that keeps working in the field:
- For each template type (home, category, product, blog), list the images that appear in the mobile first screen.
- Remove the lazy flag from those images and add fetchpriority="high" to the LCP image.
- Add loading="lazy" to the remaining images and iframes.
- Add width and height to every img tag.
- Remove overlapping plugins or script based solutions.
- If any text content waits for a scroll or click event, render it in the HTML instead.
- If you use infinite scroll, set up paginated URLs.
- Test with the Search Console live test and Lighthouse, then watch field data for a few weeks.
I care about this order because the biggest gains usually come from the first two steps. Still, do not skip the last one. A lab test gives you a snapshot from one device. Field data shows what real users experience.
I also recommend shipping each step separately. Then, if a metric drops, you can tell at once which change caused it.
When do you not need lazy loading?
Not every page needs it. Think of a single-screen contact page, a short service page with a few images, or a landing page where almost everything fits in the first view. These pages have little to defer, and the risk of flagging the wrong image goes up.
Likewise, the gain is tiny for small images the visitor will almost certainly see. Menu icons or a trust badge right below the fold are good examples. Deferring them sometimes does nothing except show an empty space for a moment.
My view is this. Treat lazy loading as a tool for long, media-heavy pages, not as a default rule. In other words, the right approach is "add it where it helps", not "add it everywhere".
Who should make lazy loading decisions on your team?
Lazy loading looks like a technical switch, but I would not leave the decision to one person. The designer knows which image sits in the first screen. Meanwhile, the developer controls the template. The SEO side checks what Google actually sees. When these three views do not meet, one team's improvement can break another team's metric.
In my own workflow, we define the "first screen" for each template together during design. Then development turns that definition into code. After launch, we check the result with Search Console and field data. Setting this up from the start costs far less than fixing it later. That is why I raise the topic early in every web design project.
If an existing site shows lazy loading, infinite scroll and indexing problems at the same time, you need to handle them as one system. In those cases I start with a template level audit as part of SEO consulting. I also cover the technical expectations of AI driven search in technical SEO after AI.




