Why Shopify Stores Get Slow
Shocking Data:
- 1 second page delay → 7% CVR decrease
- 3+ second load → 53% bounce rate
Yet most Shopify stores have an average load time of 3.5 seconds. Meaning they’re losing over half their potential sales.
5 Major Performance Degradation Causes
1. Excessive App Installation (Primary Cause)
// ❌ BAD: 20 apps = 20 JavaScript files
<script src="app1.js"></script>
<script src="app2.js"></script>
// ... x20
// Result: 5s initial load, Lighthouse score 30
Solution:
- Immediately uninstall unused apps
- Consolidate apps with overlapping features
- Monthly app inventory routine
2. Unoptimized Images
{% raw %}
<!-- ❌ BAD: Display 5MB image as-is -->
<img src="{{ product.image }}" alt="Product">
<!-- ✅ GOOD: WebP + srcset + lazy loading -->
<img
src="{{ product.image | image_url: width: 800, format: 'webp' }}"
srcset="
{{ product.image | image_url: width: 400, format: 'webp' }} 400w,
{{ product.image | image_url: width: 800, format: 'webp' }} 800w,
{{ product.image | image_url: width: 1200, format: 'webp' }} 1200w
"
sizes="(max-width: 768px) 100vw, 50vw"
loading="lazy"
alt="{{ product.title }}"
>
{% endraw %}
3. Unnecessary JavaScript
Reduction Techniques:
// Defer non-critical scripts
<script defer src="analytics.js"></script>
// Async for independent scripts
<script async src="chatbot.js"></script>
// Conditional loading (mobile only)
if (window.innerWidth < 768) {
loadScript('mobile-specific.js');
}
4. Font Loading Without Optimization
<!-- ❌ BAD: Font blocks rendering -->
<link href="https://fonts.googleapis.com/css2?family=Roboto" rel="stylesheet">
<!-- ✅ GOOD: preload + font-display -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
5. Third-party Scripts
Analytics, chat widgets, and ad pixels are often the biggest hidden performance killers. They block rendering and add hundreds of milliseconds to load time.
// ✅ GOOD: Delay GA4 loading until after page is interactive
window.addEventListener('load', function() {
setTimeout(function() {
gtag('config', 'G-XXXXXXXXXX');
}, 3000);
});
10 Practical Optimization Tactics
Tactic 1: App Minimalism
Target: Under 10 apps (5-7 ideal)
Reduction checklist:
- Uninstall apps unused in past 30 days
- Consolidate apps with same features
- Remove apps replaceable with native Shopify features
Tactic 2: Critical CSS Inline
<head>
<style>
/* Minimal above-the-fold CSS */
.hero { display: flex; min-height: 100vh; }
.header { position: fixed; width: 100%; }
</style>
<!-- Async load other CSS -->
<link rel="preload" href="main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>
Tactic 3: Next-Gen Image Formats
{% raw %}
<!-- WebP/AVIF priority with fallback -->
<picture>
<source
type="image/avif"
srcset="{{ product.image | image_url: width: 800, format: 'avif' }}"
>
<source
type="image/webp"
srcset="{{ product.image | image_url: width: 800, format: 'webp' }}"
>
<img
src="{{ product.image | image_url: width: 800 }}"
alt="{{ product.title }}"
>
</picture>
{% endraw %}
Tactic 4: Service Worker (PWA)
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/collections/all',
'/assets/theme.css',
]);
})
);
});
Tactic 5: Get More Out of Shopify’s CDN
Shopify automatically serves assets through its global CDN, but you can push performance further by setting up a custom domain CNAME to point directly at Shopify’s CDN edge nodes. This reduces DNS lookup time and improves cache hit rates for repeat visitors.
Also make sure to use Shopify’s image_url filter with explicit width parameters so the CDN serves correctly-sized images rather than letting the browser scale them down.
Tactic 6: Preconnect and Prefetch
Tell the browser early what connections it’ll need. This shaves 100-300ms off perceived load time for external resources.
<!-- Warm up connections to frequently used external domains -->
<link rel="preconnect" href="https://cdn.shopify.com">
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<!-- Prefetch next likely page for instant navigation -->
<link rel="prefetch" href="/collections/bestsellers">
Tactic 7: Split Your JavaScript Bundles
Monolithic JS files force users to download code they don’t need on every page. Use Shopify Theme App Extensions to isolate each app’s JavaScript into its own bundle - that way checkout-specific code doesn’t load on the homepage.
Conditional loading cuts waste further:
// Load Klaviyo email capture only when cart is non-empty
document.addEventListener('cart:updated', function(event) {
if (event.detail.itemCount > 0) {
loadScript('klaviyo-capture.js');
}
});
Tactic 8: Write Efficient Liquid Templates
Liquid loops are the most common cause of slow server-side rendering in Shopify themes.
{% raw %}
<!-- ❌ BAD: Loop through entire catalog on every render -->
{% for product in collections.all.products %}
{{ product.title }}
{% endfor %}
<!-- ✅ GOOD: Paginate and cap at 20 per page -->
{% paginate collections.all.products by 20 %}
{% for product in collections.all.products %}
{{ product.title }}
{% endfor %}
{% endpaginate %}
{% endraw %}
Avoid deep nested loops, and use limit filters aggressively. Each unnecessary object access adds render time.
Tactic 9: Move Logic to Shopify Functions
Custom JavaScript in the checkout flow is a major render blocker. Shopify Functions let you move discount logic, shipping rules, and cart validation to the server side via Checkout Extensibility - no client-side JS required.
The result: checkout renders faster, works without JavaScript, and isn’t blocked by ad blockers or slow connections.
Tactic 10: Automate Performance Monitoring
Manual Lighthouse checks get skipped. Set up Lighthouse CI in GitHub Actions so every PR automatically generates a performance report.
# .github/workflows/lighthouse.yml
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
https://your-store.myshopify.com/
https://your-store.myshopify.com/collections/all
budgetPath: ./budget.json
uploadArtifacts: true
If a PR drops your Lighthouse score below 85, the check fails and the team knows before it ships.
Before/After Case Study
Case: Apparel EC “FashionHub”
Before:
- Lighthouse: 35
- LCP: 4.2s
- CLS: 0.28
- Mobile bounce: 68%
After (Tactics 1-10):
- Lighthouse: 92 (+163%)
- LCP: 1.1s (-74%)
- CLS: 0.05 (-82%)
- Mobile bounce: 31% (-54%)
- CVR: 2.1% → 3.8% (+81%)
Performance Checklist
- Under 10 apps installed
- All images have loading=“lazy”
- Using WebP/AVIF formats
- Critical CSS inlined
- Third-party scripts deferred
- Lighthouse score 85+
- LCP under 2.5s
- CLS under 0.1
Conclusion
Shopify optimization requires both technical tactics and operational discipline:
- Minimize apps
- Always optimize images
- Regular performance monitoring
DEMETIO offers Shopify performance audit services. Free diagnostics available.
Related Articles: