DEV Community

Rishabh Sethia
Rishabh Sethia

Posted on • Originally published at innovatrixinfotech.com

Shopify Speed Optimization: How We Improved Core Web Vitals and Boosted Conversions

FloraSoul India had a problem that's more common than most D2C founders realise: a visually stunning Shopify store with a mobile conversion rate that didn't reflect the quality of the product or the brand.

When they came to us, the store had been live for several months. Traffic was healthy. The product photography was excellent. The brand story was compelling. But mobile conversion sat below 1%.

We ran the audit. Within 20 minutes, we'd identified four issues that any experienced frontend engineer would spot immediately. None of them required a redesign. None required switching themes or moving to headless. They required clean engineering — the kind that page builder tools and agency generalists tend to leave undone.

The outcome: +41% mobile conversion lift after fixes were shipped. This tutorial walks through exactly what we found, why each issue mattered, and the specific code fixes we applied.

The Diagnostic Stack We Use

Before writing a single line of fix code, we run a structured diagnostic. Three tools, in order:

1. Google PageSpeed Insights — Field data (CrUX) shows real-user performance. Lab data shows what's fixable. The "Opportunities" and "Diagnostics" sections are your starting point. Always test the product page URL, not just the homepage — product pages are where mobile conversion happens.

2. Shopify Theme Inspector — A Chrome extension that profiles Liquid template render time section-by-section. It tells you which parts of your theme are slow to render on Shopify's servers, before a single byte hits the browser. Most developers never use this. It's the Shopify-specific tool that cuts hours off a performance audit.

3. Chrome DevTools Performance tab — For deep INP and long task analysis. Record a typical user interaction (page load → product page → add to cart) and review the flame chart. Long tasks blocking the main thread for 50ms+ are your INP killers.

As a Shopify Partner, we also have access to Shopify's internal theme performance guidelines — which give us a higher ceiling on what "optimised" actually means for a given theme architecture.

Issue 1: Render-Blocking Animation Library

What we found: FloraSoul's theme was loading an animation library (animate.css + a custom JS animation controller) synchronously in the <head> of theme.liquid. The library was being used for subtle product card entrance animations — a nice visual touch, but not critical to the page rendering path.

Why it matters: Scripts and stylesheets loaded synchronously in <head> block the browser from rendering anything below them until they've fully downloaded, parsed, and executed. On a mobile device on a 4G connection, a 180KB animation library can add 1.2-2 seconds to Time to First Contentful Paint. The user stares at a blank screen.

The fix: We moved the animation script to load with defer, which tells the browser to download it in parallel but not execute it until after the page has parsed. We also lazy-loaded animate.css via a <link rel="preload"> with onload swap:

<!-- Before: blocking -->
<link rel="stylesheet" href="animate.min.css">
<script src="animations.js"></script>

<!-- After: non-blocking -->
<link rel="preload" href="animate.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="animate.min.css"></noscript>
<script src="animations.js" defer></script>
Enter fullscreen mode Exit fullscreen mode

Result: FCP dropped by approximately 1.4 seconds on mobile. The animations still work — they initialise ~300ms after page paint, which is imperceptible to users.

Issue 2: LCP Image Not Preloaded

What we found: The hero product image on every product page — the Largest Contentful Paint element — was being loaded as a regular <img> tag with loading="lazy". This is one of the most common LCP performance mistakes we encounter, and it directly contradicts Google's guidance.

Why it matters: loading="lazy" tells the browser to defer loading this image until it's near the viewport. For the LCP image, which is by definition in the viewport on load, this delays the most important paint event on the page. Combined with no preload hint, the browser discovers the LCP image only after it has parsed the full HTML — wasting critical connection time.

The fix: We identified the LCP image in the product template (sections/main-product.liquid) and added an explicit preload hint in the <head> and removed loading="lazy" from the primary image:

{% comment %} In theme.liquid <head>, injected via section schema: {% endcomment %}
{% if template == 'product' %}
  <link
    rel="preload"
    as="image"
    href="{{ product.featured_image | img_url: '1200x' }}"
    imagesrcset="{{ product.featured_image | img_url: '400x' }} 400w,
                 {{ product.featured_image | img_url: '800x' }} 800w,
                 {{ product.featured_image | img_url: '1200x' }} 1200w"
    imagesizes="(max-width: 768px) 100vw, 50vw"
  >
{% endif %}
Enter fullscreen mode Exit fullscreen mode

And in the product image template, the primary image:

<img
  src="{{ product.featured_image | img_url: '800x' }}"
  srcset="{{ product.featured_image | img_url: '400x' }} 400w,
          {{ product.featured_image | img_url: '800x' }} 800w,
          {{ product.featured_image | img_url: '1200x' }} 1200w"
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="{{ product.featured_image.alt | escape }}"
  width="800"
  height="800"
  fetchpriority="high"
  {%- comment %} No loading=lazy on LCP image {%- endcomment %}
>
Enter fullscreen mode Exit fullscreen mode

Secondary images in the gallery kept loading="lazy" since they're below the fold.

Result: LCP on mobile moved from 4.1 seconds to 2.3 seconds — crossing the "Good" threshold for the first time.

Issue 3: Oversized Product Images Without srcset

What we found: All product images were being served at their original upload resolution — averaging 2400x2400px at 1.8MB per image. Mobile devices were downloading desktop-sized images and then scaling them down via CSS. On a product page with 6 images, that's over 10MB of image data downloaded before the user has seen a single product detail.

Why it matters: Image weight is the single largest contributor to slow LCP and high Total Blocking Time on Shopify product pages. Shopify's CDN serves WebP automatically, but it serves the full resolution unless you specify a resize in the URL. Without srcset, every device gets the largest image.

The fix: We applied srcset across all product image elements (the gallery, thumbnails, and zoom view), using Shopify's built-in image URL filter to request device-appropriate sizes:

{%- for image in product.images -%}
  <img
    src="{{ image | img_url: '600x' }}"
    srcset="{{ image | img_url: '300x' }} 300w,
            {{ image | img_url: '600x' }} 600w,
            {{ image | img_url: '1200x' }} 1200w"
    sizes="(max-width: 480px) 90vw,
           (max-width: 900px) 50vw,
           40vw"
    alt="{{ image.alt | escape }}"
    width="600"
    height="600"
    loading="{% if forloop.first %}eager{% else %}lazy{% endif %}"
  >
{%- endfor -%}
Enter fullscreen mode Exit fullscreen mode

Note the forloop.first logic: the first image gets loading="eager" (matching the fetchpriority="high" LCP fix), all subsequent gallery images get loading="lazy".

Result: Median image payload on product pages dropped from 10.2MB to 1.4MB on mobile. Visible page weight in DevTools Network tab went from 12.8MB to 2.1MB total for an average product page load.

Issue 4: Third-Party Tracking Scripts Firing Synchronously

What we found: FloraSoul had five tracking integrations installed: Facebook Pixel, Google Analytics 4, a heatmap tool, an email capture popup, and a WhatsApp chat widget. All five were being injected into <head> as synchronous scripts, either by apps or by manual snippet additions to theme.liquid.

Why it matters: Each synchronous third-party script is a single point of failure for your entire page render. If any one of these services has a slow response (which happens regularly with ad tracking endpoints), your page waits. Combined, five synchronous tracking scripts were adding 800ms-1.2 seconds of network round-trip time before the browser could paint anything.

The fix: We consolidated all third-party scripts under Google Tag Manager with the GTM container loading async. Within GTM, we configured all tags to fire on DOM Ready or Window Loaded events, not Page View. This decouples the tracking instrumentation from the critical rendering path entirely:

<!-- In theme.liquid <head>: only GTM loads here -->
<script>
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');
</script>
Enter fullscreen mode Exit fullscreen mode

All five tracking scripts were then moved into GTM and configured to fire post-render. The WhatsApp widget in particular was set to trigger only after the first user interaction (click event), eliminating its zero-interaction load cost entirely.

Result: Total Blocking Time dropped from 1,840ms to 290ms on mobile — crossing the "Good" threshold. The INP score moved from "Needs Improvement" to "Good" across most user sessions.

The Combined Result

These four fixes shipped over two development sprints. No redesign. No theme switch. No Hydrogen migration (our comparison of Liquid vs Hydrogen architecture covers when that conversation becomes relevant). Just clean engineering on an existing Liquid store.

Before:

  • Mobile LCP: 4.1s
  • Total Blocking Time: 1,840ms
  • Image payload per product page: 10.2MB
  • Mobile PageSpeed score: 31

After:

  • Mobile LCP: 2.3s
  • Total Blocking Time: 290ms
  • Image payload per product page: 1.4MB
  • Mobile PageSpeed score: 78

Business outcome: +41% mobile conversion rate lift over the following 8 weeks. FloraSoul also saw a +28% improvement in average order value, which we attribute partly to faster load enabling users to browse more products per session.

What To Do Next For Your Store

If you want to run this same diagnostic on your store, start with our full Shopify SEO checklist — it covers all the CWV items in audit format with a priority ordering for which fixes to address first.

If you'd rather have our team do it, we offer full Shopify performance audits and implementation through our Shopify development service. We use the exact diagnostic process and fix patterns above on every store we touch. As a DPIIT-recognised startup and official Shopify Partner, we combine the credibility of a verified agency with the technical depth of an engineering team that has shipped 50+ production Shopify builds.


Frequently Asked Questions

How much does Shopify speed optimisation cost?
For a targeted performance fix project (similar to the FloraSoul engagement), typical scope runs 2–3 weeks of development work. For a combined audit + implementation engagement, budget 3–4 weeks. Exact scope depends on theme complexity and number of third-party integrations installed.

Will speed optimisation affect my store's design?
Not if done correctly. The four fixes in this tutorial — deferring scripts, preloading LCP images, implementing srcset, and consolidating trackers into GTM — are invisible to end users. The store looks and feels identical. Only the performance metrics change.

My PageSpeed score is 30 on mobile. Is that fixable without changing themes?
In most cases, yes. A score of 30 typically indicates one or more of: render-blocking scripts, oversized images, no LCP preload, or heavy third-party payloads. All of these are fixable in your existing theme. We've seen stores go from 28 to 74 without a single design change.

What's the difference between PageSpeed score and Core Web Vitals?
PageSpeed Insights shows both. The score (0–100) is a lab-based synthetic measurement useful for benchmarking. Core Web Vitals (LCP, INP, CLS) are field data metrics pulled from real Chrome user sessions — this is what Google uses for ranking. Both matter, but CWV is the more important one for SEO.

Does page speed directly affect Shopify conversion rates?
Yes. Google's own research shows conversion rates drop approximately 12% for every second of mobile load time after the first second. For a mobile-first market like India — where most shoppers are on 4G connections and mid-range Android devices — page speed is one of the most direct levers on conversion you can pull.

Should I use a Shopify speed optimisation app?
Most "speed optimisation" apps add more script weight than they remove. The legitimate fixes require code access — modifying theme.liquid, section templates, and image rendering logic. These aren't things an app can do safely at scale. Avoid apps that promise PageSpeed score improvements through automatic optimisation. Do the engineering work instead.


Rishabh Sethia — Founder & CEO of Innovatrix Infotech. Former Senior Software Engineer and Head of Engineering. DPIIT Recognised Startup. Shopify Partner.


Originally published at Innovatrix Infotech

Top comments (0)