Load on Demand
Only When Visible
Your Shopify store probably loads dozens of images on every page. Product photos, banners, lifestyle shots, trust badges. Without lazy loading, the browser tries to download all of them the moment a customer lands on your site. That is a problem. Here is how to fix it.
What Is Lazy Loading?
Lazy loading is a technique that delays the loading of images, videos, and other content until the user actually scrolls to them. Instead of forcing the browser to download every asset on page load, lazy loading waits until each element is about to enter the viewport before requesting it.
Think of it like a restaurant kitchen. Rather than preparing every dish on the menu the moment you open the doors, you only cook what customers order. The result: faster service, less waste, and happier guests.
In technical terms, the browser uses the Intersection Observer API (or the native loading="lazy" attribute) to detect when an image is approaching the visible area of the screen. Only then does it begin the download. Everything above the fold loads immediately. Everything below the fold loads on demand.
Why Lazy Loading Matters for Shopify Stores
Shopify stores are image-heavy by nature. A typical collection page might display 24 products with multiple images each. A product page often includes a gallery, lifestyle images, related products, and review photos. Without lazy loading, all of those images compete for bandwidth during the initial page load.
Here is what lazy loading does for your store:
- Faster initial page load: The browser only requests assets visible in the viewport, so the page becomes interactive much sooner
- Lower bandwidth usage: Visitors who bounce early never download the images at the bottom of the page. This saves server resources and reduces costs for customers on mobile data
- Better Core Web Vitals: Largest Contentful Paint (LCP) improves because the browser can focus resources on above-the-fold content. First Input Delay (FID) drops because less JavaScript is competing for the main thread
- Improved mobile experience: Mobile connections are slower and less stable. Lazy loading is especially impactful on phones where every kilobyte matters
- Higher conversion rates: Faster stores convert better. A 1-second improvement in load time can increase mobile conversions by up to 27%
How Shopify Handles Lazy Loading Natively
The good news is that Shopify's Online Store 2.0 themes (Dawn, Craft, Sense, and others) ship with native lazy loading built in. These themes use the HTML loading="lazy" attribute on images that appear below the fold.
Here is how it works in practice. When your theme renders a product grid, each image tag includes the attribute:
<img src="product-image.jpg"
loading="lazy"
alt="Product Name"
width="600"
height="600" />The browser sees loading="lazy" and knows to defer the download until the image is near the viewport. No JavaScript required. No external libraries. It just works.
Shopify's Liquid templating language also provides a way to control this. In Dawn and similar themes, the lazy parameter is passed to image snippets, giving theme developers fine-grained control over which images load eagerly and which load lazily.
Images You Should NOT Lazy Load
This is where many store owners make a critical mistake. Not every image should be lazy loaded. Images that are visible immediately when the page loads (above the fold) should load eagerly. Lazy loading them actually hurts performance.
Never lazy load these elements:
- Hero banners and slideshow images: These are the first things customers see. They directly impact your LCP score
- Your logo: It appears in the header on every page and should load instantly
- First product image: On product pages, the main product photo must load without delay
- Above-the-fold collection images: The first row of products visible without scrolling should load eagerly
- Background images in hero sections: Any CSS background image in the visible viewport on page load
For these elements, use loading="eager" (or simply omit the lazy attribute) and consider adding fetchpriority="high" to tell the browser to prioritize them.
Common pitfall: Lazy loading your hero image is one of the most frequent causes of poor LCP scores on Shopify stores. If your PageSpeed Insights report flags a slow LCP, check whether your hero image has loading="lazy" on it. Removing that attribute can instantly improve your score.
How to Check if Lazy Loading Is Working
You do not need any special tools. Chrome DevTools has everything you need.
- Open DevTools: Right-click on your store and select "Inspect" (or press F12)
- Go to the Network tab: Select "Img" from the filter bar to show only image requests
- Reload the page: Watch which images load immediately
- Scroll down slowly: You should see new image requests appear in the Network tab as you scroll. That means lazy loading is working
You can also inspect individual image elements. Right-click an image, choose "Inspect", and look for the loading attribute in the HTML. If it says lazy, that image will only load when scrolled into view.
For a more automated approach, run your store through Google PageSpeed Insights. If lazy loading is missing, you will see an opportunity flagged under "Defer offscreen images" with an estimate of the potential savings.
Manual Lazy Loading Implementation
If your Shopify theme does not support lazy loading natively (common with older or custom themes), you can add it yourself. There are two approaches.
Approach 1: Native HTML Attribute
The simplest method is adding the loading="lazy" attribute directly to your image tags in your theme's Liquid files. Edit the relevant snippet (often image.liquid or responsive-image.liquid) and add the attribute:
<img
src="{{ img_url }}"
alt="{{ image.alt }}"
loading="lazy"
width="{{ image.width }}"
height="{{ image.height }}" />This is supported by all modern browsers (Chrome, Firefox, Edge, Safari) and requires zero JavaScript. Always include width and height attributes so the browser can reserve space and prevent layout shifts.
Approach 2: JavaScript Intersection Observer
For more control (or for background images that cannot use the HTML attribute), use the Intersection Observer API:
document.addEventListener("DOMContentLoaded", function() {
const lazyImages = document.querySelectorAll("img[data-src]");
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute("data-src");
observer.unobserve(img);
}
});
}, { rootMargin: "200px" });
lazyImages.forEach(img => observer.observe(img));
});With this approach, you replace src with data-src in your image tags and use a tiny placeholder or transparent pixel as the initial source. The rootMargin: "200px" tells the observer to start loading images when they are 200 pixels from entering the viewport, so users never see a blank space.
Lazy Loading Videos and Iframes
Images are not the only resources worth lazy loading. Embedded videos and iframes can be even heavier than images, often adding 1-3MB of JavaScript and assets per embed.
YouTube and Vimeo embeds: Instead of loading the full video player on page load, use a static thumbnail image with a play button overlay. Only load the actual iframe when the customer clicks play. This technique is called "facade loading" and can save 500KB+ per video embed.
Iframes: The loading="lazy" attribute works on iframes too. Add it to any embedded content (Instagram feeds, Google Maps, etc.) that appears below the fold:
<iframe
src="https://www.youtube.com/embed/VIDEO_ID"
loading="lazy"
title="Video title"
width="560"
height="315">
</iframe>Lazy Loading Third-Party Scripts
This is an advanced technique that can dramatically speed up your Shopify store. Third-party scripts like live chat widgets, review apps, social media feeds, and analytics tools often load megabytes of JavaScript on every page, even if the customer never interacts with them.
The solution is to delay these scripts until the user shows intent to interact. Here are a few strategies:
- Chat widgets: Load the chat script only after the user scrolls, moves their mouse, or taps the screen. Most customers do not need live chat within the first second of arriving
- Review widgets: If your reviews section is below the fold, defer loading the review app's JavaScript until the user scrolls near it
- Social media embeds: Instagram feeds and TikTok embeds are extremely heavy. Load them only when they enter the viewport
- Analytics and pixels: Use
requestIdleCallbackor a small delay to load non-critical tracking scripts after the page has finished rendering
A common pattern is to listen for the first user interaction and then load all deferred scripts at once:
const loadDeferredScripts = () => {
// Load chat widget, reviews, etc.
const script = document.createElement("script");
script.src = "https://chat-widget.example.com/widget.js";
document.body.appendChild(script);
};
["scroll", "mousemove", "touchstart"].forEach(event => {
window.addEventListener(event, loadDeferredScripts, { once: true });
});Common Lazy Loading Mistakes
Lazy loading is powerful, but implementing it incorrectly can hurt more than help. Avoid these mistakes:
- Lazy loading hero images: This is the number one mistake. Your hero image is the LCP element. Lazy loading it forces the browser to wait for the Intersection Observer before downloading, adding hundreds of milliseconds to your LCP time
- Missing width and height attributes: Without dimensions, the browser cannot reserve space for lazy-loaded images. This causes layout shifts (CLS issues) as images pop in and push content around
- Lazy loading everything: Above-the-fold content should always load eagerly. Only defer images and assets that are below the initial viewport
- Using JavaScript when native lazy loading works: The HTML
loading="lazy"attribute is simpler, faster, and requires no additional code. Use JavaScript only when you need extra control - No placeholder or skeleton: If lazy images have no placeholder, customers see blank white gaps while scrolling. Use a low-quality image placeholder (LQIP) or a subtle background color
- Forgetting about SEO: Make sure lazy-loaded images still have proper
alttags and that Googlebot can discover them. Native lazy loading is fully supported by Google's crawler
Best Shopify Apps for Lazy Loading
If you prefer not to edit theme code, several Shopify apps handle lazy loading for you:
- Hyperspeed: Comprehensive speed optimization app that includes smart lazy loading for images, videos, and third-party scripts. Also handles image compression and preloading
- TinyIMG: Focuses on image optimization with built-in lazy loading. Automatically compresses images and adds the lazy attribute
- Booster: Page Speed Optimizer: Defers offscreen images and third-party scripts. Includes preloading for critical resources
- Nostra AI: Uses edge caching and smart lazy loading to reduce load times across your entire store
When choosing an app, look for one that gives you control over which images are lazy loaded and which are not. Blanket lazy loading (applying it to every image) will cause the hero image problem discussed above.
Impact on SEO
Lazy loading and SEO work well together when implemented correctly. Here is what you need to know:
- Google supports native lazy loading: Googlebot renders JavaScript and understands
loading="lazy". Your images will still be indexed - Core Web Vitals improve: LCP, CLS, and FID all benefit from proper lazy loading, and Google uses these metrics as ranking signals
- Page speed is a ranking factor: Faster pages rank higher, and lazy loading directly contributes to faster initial load times
- Image search still works: As long as your images have descriptive
alttext and proper filenames, lazy loading does not prevent them from appearing in Google Image Search - Reduced server load: Fewer simultaneous requests means your store handles traffic spikes better, preventing the slowdowns and downtime that hurt rankings
One important consideration: if you use JavaScript-based lazy loading (not the native attribute), make sure the images are still discoverable in the HTML source. Some older implementations hide image URLs entirely until JavaScript runs, which can prevent search engines from finding them. The native loading="lazy" attribute avoids this issue entirely because the src is always present in the markup.
The Quick-Start Lazy Loading Checklist
Here is a practical checklist you can work through right now:
- Check if your theme already uses
loading="lazy"(inspect a below-the-fold image in DevTools) - Verify that your hero image does NOT have
loading="lazy"and usesfetchpriority="high" - Confirm all images have
widthandheightattributes to prevent layout shifts - Add
loading="lazy"to any YouTube, Vimeo, or iframe embeds below the fold - Defer third-party scripts (chat, reviews, social embeds) until user interaction
- Run PageSpeed Insights and check for the "Defer offscreen images" recommendation
- Test on a real mobile device with a throttled connection to see the real-world impact
Stop Wrestling With Theme Code
Clyro builds Shopify themes with smart lazy loading baked in from the start. Hero images load eagerly with high priority. Below-the-fold content defers automatically. Third-party scripts stay out of the critical path. You get a fast store without touching a single line of code.
Build a Faster Store with ClyroFinal Thoughts
Lazy loading is one of the highest-impact, lowest-effort speed optimizations you can make to your Shopify store. When implemented correctly, it reduces initial page weight, improves Core Web Vitals, and creates a smoother browsing experience for your customers.
The key is balance. Load critical above-the-fold content eagerly with high priority. Defer everything else. Test with real tools on real devices. And remember that lazy loading is just one piece of the performance puzzle. Pair it with image compression, minimal app usage, and a well-coded theme for the best results.
Your customers will not notice lazy loading when it works. They will just notice that your store feels fast.
Clyro Team
E-commerce & AI Insights