7 Shopify Speed Optimizations That Actually Moved Core Web Vitals (With Before/After Data) — Jhango Blog
Performance

7 Shopify Speed Optimizations That Actually Moved Core Web Vitals (With Before/After Data)

Every Shopify store owner has Googled "how to speed up Shopify." The results are usually a mix of generic advice ("compress your images!") and vendor-sponsored content pushing yet another app. This post is different.

Below are 7 specific optimizations we have implemented across client stores, with real before/after Core Web Vitals data. These are not theoretical. Every number comes from anonymized client projects, measured using CrUX (Chrome User Experience Report) field data -- not synthetic Lighthouse runs.

Aggregate Results Across 12 Client Stores
91
PageSpeed
Average (After)
1.4s
LCP Median
from 3.2s
68ms
INP Median
from 248ms
0.02
CLS Median
from 0.18
1

Critical Image Preloading and Lazy-Load Strategy

The single biggest LCP improvement we make on every store. Most Shopify themes lazy-load everything, including the hero image that IS the LCP element. This is backwards.

What we do

  • Preload the LCP image using <link rel="preload"> in the <head>
  • Remove loading="lazy" from above-the-fold images (hero, first product image)
  • Add fetchpriority="high" to the LCP element
  • Use responsive srcset with Shopify's image CDN transforms to serve correctly sized images
  • Lazy-load everything below the fold using native loading="lazy" (no JavaScript library)
<!-- Before: Hero image lazy-loaded (bad) -->
<img src="{{ section.settings.hero_image | image_url: width: 1920 }}"
     loading="lazy" alt="Hero">

<!-- After: Hero image preloaded, priority fetched -->
{%- liquid
  assign hero_img = section.settings.hero_image
  assign hero_url = hero_img | image_url: width: 1200
-%}
<link rel="preload" as="image" href="{{ hero_url }}"
      imagesrcset="{{ hero_img | image_url: width: 600 }} 600w,
                    {{ hero_img | image_url: width: 900 }} 900w,
                    {{ hero_img | image_url: width: 1200 }} 1200w"
      imagesizes="100vw">

<img src="{{ hero_url }}"
     srcset="{{ hero_img | image_url: width: 600 }} 600w,
             {{ hero_img | image_url: width: 900 }} 900w,
             {{ hero_img | image_url: width: 1200 }} 1200w"
     sizes="100vw"
     fetchpriority="high"
     alt="Hero">
Metric Before After Change
LCP (p75) 3.8s 1.6s -58%
LCP Element Load Time 2.4s 0.6s -75%
2

App Bloat Audit and Script Removal

The average Shopify store we audit has 12-18 apps installed, but only uses 8-10 actively. The unused apps still inject JavaScript into every page load. This is the single most impactful INP optimization.

Our app audit process

  1. List all installed apps and their last-used date in the Shopify admin
  2. Run a script audit using Chrome DevTools Network tab -- identify every third-party script and which app owns it
  3. Measure individual script impact by blocking each script and measuring the performance delta
  4. Remove unused apps -- uninstall completely (not just deactivate)
  5. Verify leftover code -- many apps leave behind Liquid snippets, theme assets, and script tags even after uninstalling. Manually clean these out.

Pro Tip: After uninstalling apps, search your theme code for the app's handle. Common leftover patterns: {% render 'app-name' %}, {{ 'app-name.js' | asset_url | script_tag }}, and inline <script> blocks with the app's domain.

Metric Before After Change
Total JS Payload 1.8 MB 620 KB -66%
INP (p75) 312ms 84ms -73%
Third-party requests 47 18 -62%
3

Third-Party Script Deferral with Partytown or requestIdleCallback

Even essential third-party scripts (analytics, chat widgets, review widgets) do not need to run during initial page load. Deferring them to after the main thread is idle dramatically improves INP and TBT (Total Blocking Time).

Scripts we defer

  • Google Analytics / GA4 -- defer by 2 seconds or use requestIdleCallback
  • Facebook Pixel -- load after DOMContentLoaded
  • Chat widgets (Tidio, Gorgias, Zendesk) -- load on user interaction (scroll or click)
  • Review widgets (Judge.me, Yotpo) -- load when the review section enters viewport via IntersectionObserver
  • Recommendation carousels -- load on viewport intersection
// Defer non-critical scripts until browser is idle
function loadDeferredScripts() {
  const scripts = [
    'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX',
    'https://connect.facebook.net/en_US/fbevents.js'
  ];
  scripts.forEach(src => {
    const s = document.createElement('script');
    s.src = src;
    s.async = true;
    document.head.appendChild(s);
  });
}

if ('requestIdleCallback' in window) {
  requestIdleCallback(loadDeferredScripts);
} else {
  setTimeout(loadDeferredScripts, 3000);
}
Metric Before After Change
TBT (Total Blocking Time) 1,400ms 280ms -80%
INP (p75) 248ms 92ms -63%
4

Shopify Image CDN Tuning and Format Optimization

Shopify's CDN automatically serves WebP and AVIF formats when the browser supports them. But most themes do not take full advantage of this. Here is what we optimize:

  • Use image_url filter (not img_url) for responsive images with proper width parameters
  • Set explicit width and height attributes on all <img> tags to prevent CLS
  • Use format: 'pjpg' for product images (progressive JPEG loads perceived faster)
  • Cap maximum image width to the actual display size -- never serve a 4000px image for a 600px container
  • Use CSS aspect-ratio on image containers to reserve space before load
Metric Before After Change
Total Image Payload 4.2 MB 890 KB -79%
CLS (p75) 0.22 0.03 -86%
LCP (p75) 2.9s 1.8s -38%
5

Liquid Render Optimization (Reducing Server Response Time)

Shopify's servers have to parse and execute your Liquid templates on every request. Complex Liquid code directly impacts TTFB. Here are the biggest Liquid performance offenders we fix:

  • Nested for-loops in collection pages -- iterating over products, then variants, then metafields creates O(n^3) complexity. Use assign to pre-filter.
  • Excessive include / render calls -- each one adds parse overhead. Inline small snippets instead of rendering them.
  • Unused sections in JSON templates -- remove any sections in your template JSON that are disabled or hidden. They still render server-side.
  • Complex where filters on large collections -- use Shopify's Collection API filtering instead of Liquid loops.
  • Metafield overuse on listing pages -- each metafield access on a collection page with 50 products is 50 additional queries. Access metafields only on product pages.
{%- comment -%} BEFORE: Nested loops (slow) {%- endcomment -%}
{% for product in collection.products %}
  {% for variant in product.variants %}
    {% if variant.metafields.custom.badge != blank %}
      <span>{{ variant.metafields.custom.badge }}</span>
    {% endif %}
  {% endfor %}
{% endfor %}

{%- comment -%} AFTER: Pre-filter and flatten (fast) {%- endcomment -%}
{% for product in collection.products %}
  {%- assign first_badge = product.metafields.custom.badge -%}
  {% if first_badge != blank %}
    <span>{{ first_badge }}</span>
  {% endif %}
{% endfor %}
Metric Before After Change
TTFB (p75) 680ms 320ms -53%
Server Response (collection page) 1.2s 0.4s -67%
6

CSS Critical Path Extraction and Font Loading Strategy

Render-blocking CSS is a major LCP bottleneck. Shopify's content_for_header injects significant render-blocking resources that you cannot remove. But you can control everything else.

What we implement

  • Inline critical CSS for above-the-fold content (header, hero section) directly in the <head>
  • Async load non-critical CSS using <link rel="preload" as="style" onload="this.rel='stylesheet'">
  • Font display: swap on all custom fonts to prevent invisible text during load
  • Preconnect to font CDNs -- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  • Subset fonts -- only load the character sets you actually use (Latin, not Latin Extended + Cyrillic)
Metric Before After Change
FCP (First Contentful Paint) 2.1s 0.9s -57%
Render-blocking resources 8 files 2 files -75%
7

Layout Shift Prevention (CLS Below 0.05)

CLS is the most underrated Core Web Vital. It directly affects user experience -- elements jumping around the page as resources load makes a store feel broken. Common CLS offenders on Shopify:

  • Images without dimensions -- the browser cannot reserve space until the image loads
  • Dynamic content injection -- review widgets, "recently viewed" sections, and announcement bars that load after page render
  • Web fonts causing FOUT (Flash of Unstyled Text) -- text reflows when the custom font loads
  • Sticky headers with dynamic height -- header changes height on scroll, pushing content down

Our CLS prevention checklist

  1. Set explicit width and height on every <img> and <video> element
  2. Use CSS aspect-ratio on containers that hold dynamic content
  3. Reserve space for ad slots and widget injection points with min-height
  4. Use font-display: optional for body text to prevent FOUT entirely
  5. Set a fixed height for the header with min-height in CSS
  6. Pre-render announcement bar content server-side (not via JavaScript)
Metric Before After Change
CLS (p75) 0.18 0.02 -89%
Layout shift sources 14 elements 2 elements -86%

The Business Impact

Improved Core Web Vitals are not just about a higher PageSpeed score. Across the 12 stores where we implemented all 7 optimizations, we measured:

+18%
average conversion
rate increase
-24%
bounce rate
reduction
+12%
organic traffic
growth (90 days)

Key insight: The conversion rate improvements correlated most strongly with INP improvements, not LCP. Users who experience a responsive, interactive storefront are more likely to add to cart and complete checkout. Speed is not just about the initial load -- it is about how the page feels during interaction.

Where to Start

If you can only do three things from this list, do these: (1) fix your LCP image loading strategy, (2) audit and remove unused apps, and (3) defer all non-critical third-party scripts. These three changes alone typically move a store from a 40-60 PageSpeed score to 75-85.

For a comprehensive performance audit of your Shopify store, including CrUX data analysis and a prioritized optimization roadmap, learn about our Shopify audit service.

J
Jhango Team
Shopify Plus Certified Partners

Jhango is India's leading Shopify development agency. Our team of 50+ experts has built, migrated, and scaled over 600 Shopify stores across industries. We specialize in custom theme development, performance optimization, B2B solutions, and conversion rate optimization.

Want Us to Speed Up Your Shopify Store?

Get a free performance audit with Core Web Vitals analysis and a prioritized optimization plan.

Get Free Speed Audit