Shopify Theme Performance: Core Web Vitals in Practice
How to improve Shopify theme performance — LCP, CLS, and INP — with practical fixes that actually move the needle.
- 01Where Shopify themes actually lose points
- 02Fixing LCP: hero images and product images
- 03Fixing CLS: fonts and images
- 04Third-party scripts: the biggest culprit
Where Shopify themes actually lose points
Shopify themes lose Core Web Vitals performance in predictable places: large unoptimized hero images (LCP), layout shifts from late-loading images and fonts (CLS), slow third-party scripts (INP and LCP), and excessive app scripts injecting themselves into the page.
The first step is measuring: PageSpeed Insights on real product pages and the homepage. Many Shopify stores have homepage scores that look acceptable but product pages with poor LCP because the product image isn't preloaded. Measure the pages that matter — the ones customers actually land on from ads and search.
Fixing LCP: hero images and product images
The Largest Contentful Paint element is usually the hero image (homepage) or the main product image (product pages). For LCP images: add `loading="eager"` and `fetchpriority="high"` to the above-the-fold image, and add a `<link rel="preload">` in the `<head>`.
Shopify's CDN serves WebP automatically when the browser supports it (use the `image_url` filter with `format: 'webp'`). Ensure your image sizes are appropriate — a hero image displayed at 800px wide shouldn't be served at 2400px wide.
For the product image carousel: only the first image needs `loading="eager"`. All subsequent images should be `loading="lazy"`. This single change can improve LCP by 300-500ms on product pages.
Fixing CLS: fonts and images
Layout shift comes from two main sources in Shopify themes: images without explicit width/height attributes that cause reflow when loaded, and web fonts that cause text to reflow when they swap in.
For images: always set `width` and `height` attributes matching the aspect ratio (they don't need to be the exact pixel dimensions — the browser uses them to reserve space). In Liquid, you can calculate these from the image object.
For fonts: use `font-display: optional` or `font-display: swap` in your `@font-face` declarations. `optional` is more aggressive — if the font doesn't load before first render, the system font is used permanently. This eliminates CLS from font swap entirely, at the cost of occasionally showing the fallback font.
Third-party scripts: the biggest culprit
Shopify app scripts are the biggest CWV killer that's hardest to fix cleanly. Each installed app can inject JavaScript into every page, and most apps load eagerly regardless of whether they're needed.
Audit installed apps: check Google Tag Manager's Coverage report (or use WebPageTest's waterfall) to see which scripts are loading and how long they take. Uninstall apps that are no longer used — many stores have 2-3 apps installed but not actively configured that are still injecting scripts.
For analytics: load Google Analytics / GA4 asynchronously. Defer non-critical scripts (chat widgets, heatmap tools) using `defer` or `loading them after user interaction. A `setTimeout` of 3-5 seconds before loading chat widgets is a practical compromise between analytics accuracy and performance.
Need help implementing this?
I build what I write about. If you need this implemented on your Shopify store, get in touch.
Discuss your projectReady to build this on your store?
Let's scope it.
I reply personally within 24 hours.