Key takeaways
- Native video elements should use
loading="lazy"andpreload="none"to prevent auto-downloading video data.- YouTube and Vimeo embeds use a “facade” pattern — show a clickable thumbnail, load the iframe only when clicked.
- Background videos should load only when the section scrolls into view, not on page load.
- Unoptimized video is one of the largest contributors to slow Shopify page load times.
Video on a Shopify store can be compelling — product demos, brand films, how-to content. But video is also one of the heaviest assets on the web. A single unoptimized video embed can add seconds to your page load time even for visitors who scroll past it without watching.
Lazy loading video is the fix.
How to add lazy loading to native video in Shopify
For self-hosted video files uploaded to Shopify’s asset system or a CDN, use HTML’s native lazy loading attributes.
<video
src="{{ section.settings.video_url }}"
poster="{{ section.settings.poster_image | img_url: '1200x' }}"
loading="lazy"
preload="none"
muted
playsinline
loop
>
Your browser doesn't support video.
</video>
Key attributes:
loading="lazy" — tells the browser to defer loading the video source until needed.
preload="none" — prevents the browser from downloading any video data until the user interacts with the player. Without this, browsers often prefetch video metadata or even the first few seconds of video, wasting bandwidth.
poster — shows a still image while the video hasn’t loaded. Always include this. Without a poster, visitors see a blank gray rectangle until the video loads. The poster image should be pre-loaded (don’t lazy load it).
The facade pattern for YouTube and Vimeo embeds
YouTube and Vimeo iframes are among the biggest performance problems on Shopify stores. Each one loads multiple megabytes of scripts from YouTube/Vimeo’s servers, even if the visitor never watches the video.
The facade pattern: replace the iframe with a clickable thumbnail image. When the visitor clicks to play, replace the image with the actual iframe.
Here’s a basic implementation:
<div class="video-facade" data-video-id="YOUR_YOUTUBE_ID">
<img
src="https://img.youtube.com/vi/YOUR_YOUTUBE_ID/maxresdefault.jpg"
alt="Video thumbnail"
loading="lazy"
style="width:100%; cursor:pointer;"
/>
<button class="video-play-btn" aria-label="Play video">
<!-- Play icon SVG here -->
</button>
</div>
document.querySelectorAll('.video-facade').forEach(function(facade) {
facade.addEventListener('click', function() {
var videoId = facade.dataset.videoId;
var iframe = document.createElement('iframe');
iframe.src = 'https://www.youtube.com/embed/' + videoId + '?autoplay=1';
iframe.allow = 'autoplay; encrypted-media';
iframe.style.width = '100%';
iframe.style.height = '100%';
facade.replaceWith(iframe);
});
});
For Vimeo: replace img.youtube.com/vi/ID/maxresdefault.jpg with a Vimeo thumbnail URL and update the embed URL to https://player.vimeo.com/video/ID?autoplay=1.
Easier option: Use the Lite YouTube Embed web component (a popular open-source library) which implements the facade pattern with a single HTML element.
Lazy loading background videos
Background videos (the kind that auto-play as a decorative element behind text) are particularly wasteful if they load for every visitor who lands on the page.
Approach: load video only when the section scrolls into view.
var videoSection = document.querySelector('.hero-video-section');
var videoEl = videoSection.querySelector('video');
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
// Load the video
var source = videoEl.querySelector('source');
if (source && source.dataset.src) {
source.src = source.dataset.src;
videoEl.load();
videoEl.play();
}
observer.disconnect();
}
});
}, { threshold: 0.1 });
observer.observe(videoSection);
Use this with a <source data-src="..."> instead of <source src="..."> to prevent the browser from downloading the video source before the Intersection Observer fires.
For the hero section (above the fold): background video in the hero loads immediately regardless — it’s already visible. In this case, use preload="metadata" instead of preload="none" so the browser prepares to play the video quickly.
Should you use video in Shopify at all?
Video is worth it when:
- It shows something that can’t be conveyed in a photo (fabric texture, product in motion, a process)
- It’s well-produced (low-quality video hurts trust)
- You’ve implemented lazy loading (otherwise the performance cost is too high)
Video is not worth it when:
- It’s purely decorative with no product-related purpose
- It auto-plays with sound (annoying, and most browsers block it anyway)
- The same message could be delivered more efficiently with a well-shot photo
Consider GIF alternatives. For short looping clips (2-5 seconds), an MP4 video with autoplay muted loop is typically 60-80% smaller than an equivalent GIF while looking identical.
Checking video performance impact
Run your product or homepage URL through PageSpeed Insights. Video embeds will often trigger:
- “Reduce unused JavaScript” — from YouTube’s API loading
- “Avoid enormous network payloads” — if video is loading on page load
- “Defer offscreen images/resources” — if video poster or src isn’t lazy loaded
After implementing the facade pattern, re-run PageSpeed — you should see improvements in both score and Total Blocking Time.