Home Blog SEO
SEO

Shopify Image Optimization

Technical Shopify image optimization: WebP, AVIF, responsive image_url, lazy loading, and LCP. Real Liquid code, concrete fixes.

Lionel Fenestraz · 20 May 2026 · 13 min read · Updated: May 2026
Lighthouse panel showing Core Web Vitals metrics and image weight analysis of a Shopify store after applying WebP and lazy loading
In this article

If your Shopify store feels slow, the problem is almost always images. I see it on every audit. The HTTP Archive Web Almanac reports that images account for, on average, 42.3% of a mobile page’s total weight, more than any other resource (HTTP Archive Web Almanac, 2024). On Shopify it gets worse: modern themes load hero, collection, and product images at generous sizes out of the box, and almost nobody touches the Liquid code to tune it. This post is the technical guide I wish I’d had: formats, img_url, lazy loading, alt text at scale, and what the Shopify CDN does (and doesn’t) do for you. For the wider ranking picture, my Shopify SEO ecommerce 2026 guide covers the rest of the architecture.

Key Takeaways

  • Images make up 42.3% of the average mobile page weight (HTTP Archive, 2024)
  • Shopify automatically serves WebP when the browser supports it, since 2021 (Shopify.dev)
  • The image_url filter with width and the image_tag helper generate the responsive srcset for you, no hand-writing needed (Shopify.dev)
  • The native loading="lazy" attribute is supported on 95%+ of browsers per Can I Use (Can I Use, 2025); you rarely need Intersection Observer
  • LCP must happen in under 2.5 seconds at the 75th percentile to rate “Good” (web.dev)

Why are images the number one bottleneck on Shopify?

The HTTP Archive Web Almanac puts images at 42.3% of the average mobile page weight, ahead of JavaScript and CSS combined (HTTP Archive, 2024). On Shopify the effect gets amplified because themes load full-screen heroes, dense collections, and product galleries without the merchant tweaking a thing.

The root cause is twofold. First, themes ship with defaults built to “look nice” in the editor, not to pass Core Web Vitals. Second, Shopify apps inject their own images, widgets, and scripts without asking. At a cosmetics brand I audited in early 2026 with 200+ SKUs, the home hero weighed 1.4 MB on mobile. That one file alone blew the LCP budget.

How does this affect your store’s LCP?

LCP (Largest Contentful Paint) is, in 72-81% of web pages per Google’s analysis, an image (web.dev, 2024). On a Shopify product page, the LCP is almost always the first product photo. If that file weighs 800 KB and has no fetchpriority="high", LCP jumps to 4-5 seconds on 4G. Google only rates “Good” below 2.5 seconds at the 75th percentile (web.dev).

Images account for 42.3% of the average mobile page weight per the HTTP Archive 2024 Web Almanac, and in 72-81% of websites the LCP element is an image (HTTP Archive, 2024; web.dev, 2024).


Image formats: when should you use WebP, AVIF, or JPG on Shopify?

Shopify automatically converts your images to WebP when the browser supports it, since 2021 (Shopify.dev). Meaning: if you upload a 2 MB JPG, Shopify serves a ~600 KB WebP without you touching a thing. But if you upload an unoptimized PNG, the conversion still happens, it just starts from a needlessly heavy source file.

AVIF still isn’t served natively by the Shopify CDN today. Per Can I Use, AVIF is supported on 93.9% of browsers as of early 2026 (Can I Use, 2025), but Shopify doesn’t deliver it automatically in most themes. If you want it, you have to use third-party apps or serve from your own CDN, which breaks the standard pipeline.

Comparison table: WebP vs AVIF vs JPG

FormatSavings vs JPGBrowser supportServed automatically by Shopify
JPG0% (baseline)100% (Can I Use, 2025)Yes (source original)
WebP~25-35% lighter (web.dev, 2024)97.5% (Can I Use, 2025)Yes, since 2021
AVIF~50% lighter than JPG (web.dev, 2023)93.9% (Can I Use, 2025)Not natively

The most common mistake I see: merchants installing “WebP converter” apps without knowing Shopify already does it. They end up with double conversion, worse quality, and a monthly cost that adds nothing.

What about transparent PNGs?

PNG is still the right format for logos, icons, and anything with clean-edge transparency. Shopify also converts them to WebP on modern browsers, but if the source file is 1 MB, the resulting WebP will be heavy too. Run the PNG through TinyPNG or Squoosh before uploading.


The image_url filter and image_tag in Liquid: responsive without the pain

Shopify replaced the old img_url filter with image_url in 2022, and the new image_tag helper automatically generates srcset, sizes, loading, and width/height attributes (Shopify.dev). If you’re still using img_url in your theme, you’re leaving the easiest optimization on the table.

The modern pattern is this. Instead of hardcoding a fixed size, you pass a list of widths to the filter and the browser picks the one it needs based on viewport and screen density.

Liquid snippet: responsive hero with image_tag

{%- comment -%}
  Hero responsive con srcset generado automáticamente.
  Añade fetchpriority="high" solo en el LCP (normalmente el primer hero).
{%- endcomment -%}

{{ section.settings.hero_image | image_url: width: 2000
   | image_tag:
     loading: 'eager',
     fetchpriority: 'high',
     sizes: '100vw',
     widths: '400, 600, 800, 1200, 1600, 2000',
     alt: section.settings.hero_image.alt | default: section.settings.heading
}}

This block generates an <img> with a full srcset, automatic width and height (preventing CLS), loading="eager", and fetchpriority="high" because it’s the LCP. Don’t put this on below-the-fold images. Google says explicitly that misusing fetchpriority="high" hurts performance (web.dev, 2023).

Liquid snippet: product card in a collection

{%- comment -%}
  Imagen de producto en grid de colección.
  Lazy por defecto, con aspect-ratio para prevenir CLS.
{%- endcomment -%}

<a href="{{ product.url }}" class="product-card">
  {{ product.featured_image | image_url: width: 600
     | image_tag:
       loading: 'lazy',
       sizes: '(min-width: 990px) 25vw, (min-width: 750px) 33vw, 50vw',
       widths: '200, 300, 400, 600, 800',
       alt: product.featured_image.alt | default: product.title
  }}
</a>

Your sizes need to match your actual grid. If your collection is 4 columns on desktop, 3 on tablet, and 2 on mobile, the breakpoints above are correct. If you use others, adjust them. Passing sizes: '100vw' on a small card means downloading a huge image for nothing.


Lazy loading on Shopify: native or Intersection Observer?

The native loading="lazy" attribute is supported on 95.7% of browsers per Can I Use (Can I Use, 2025). The mental rule is simple: a single line of HTML replaces all the Intersection Observer logic you used to write by hand. Use it on everything below the fold.

But watch out for a very common anti-pattern. If you add loading="lazy" to the hero or the first product image above the fold, you wreck LCP. The web.dev docs flag it as a common error (web.dev, 2023). Rule: LCP goes eager, everything else goes lazy.

When do you actually need Intersection Observer?

Rarely. The useful case is when you want to defer not just the image but a whole heavy block (a JavaScript carousel, an embedded map, a video). Then Observer lets you delay the associated scripts too. For plain images, loading="lazy" is enough.

On the 2026 cosmetics audit, an “advanced lazy load” app was installed. Turning it off and using the native loading="lazy" from Dawn dropped LCP from 3.8s to 2.1s without touching anything else. Less code, better result.


Alt text at scale: the real problem when you have 200 SKUs

Google and screen readers use alt text to understand visual content, and the official Search Central guide confirms it as a ranking signal for image SEO (Google Search Central). The problem isn’t conceptual. The problem is operational: nobody hand-writes 800 alt texts for 200 products with 4 images each.

At the cosmetics brand I audited in early 2026, 38 of the 212 products had completely empty alt text, and another 94 had the alt equal to the file name (IMG_2341.jpg). That isn’t alt text, that’s noise.

How do you generate alt text in bulk without losing your mind?

Three tactics that work:

  1. Smart fallback in Liquid: if there’s no alt text, use the product title as a fallback inside the theme. I already include it in the snippets above with | default: product.title.
  2. CSV export from the admin: Shopify lets you export products with their images. Edit the alts in Excel or Google Sheets and reimport. Tedious but it scales.
  3. AI apps for alt text: there are apps (Alt Text AI, for example) that generate descriptive alt from visual content. Always review them, AI hallucinates descriptions.

The ideal ecommerce alt text is specific: “Brand X vitamin C serum 30 ml in an amber bottle with pipette”, not “serum”. Specific, not keyword stuffing.


What does the Shopify CDN do, and what doesn’t it do?

Shopify’s CDN is powered by Fastly and delivers assets from global points of presence, per the official docs (Shopify.dev). It does four things well: automatic WebP conversion, on-the-fly resizing via the width URL parameter, aggressive edge caching, and HTTPS over HTTP/2.

But there are four things it doesn’t do. It doesn’t generate AVIF natively. It doesn’t aggressively compress the source images you upload (if you upload 2 MB, you start from there). It doesn’t reorder load priority or add fetchpriority for you. And it doesn’t fix your badly configured sizes. The CDN multiplies what you give it: feed it a good base, it serves it fast; feed it a 5 MB PNG, it delivers that too, only now you’re paying the cost.

How do you know if the CDN is serving WebP?

Open DevTools, Network tab, filter by “Img”. Look at the Type column or the response’s Content-Type header. If you see image/webp, the CDN is doing its job. If you see image/jpeg on a modern browser, the URL is probably hardcoded, bypassing the Liquid filter.


LCP and hero images: case study at a cosmetics brand

72-81% of web LCP elements are images, per Google analysis published on web.dev (web.dev, 2024). At the cosmetics brand I audited in early 2026 with 200+ SKUs, mobile LCP sat at 4.2s at the 75th percentile, squarely in “Poor” per the official thresholds.

The original hero file was a 1.4 MB JPG, served without passing width to the Liquid filter (so it returned the original size), with loading="lazy" by mistake, and no fetchpriority. Four errors in a single tag.

Results after the fix, measured with PageSpeed Insights on CrUX field data:

  • Mobile LCP: from 4.2s to 2.0s (52% drop)
  • Hero weight: from 1.4 MB to 180 KB (WebP, width 1600, full srcset)
  • Mobile performance score: from 42 to 81
  • Core Web Vitals rating: from “Poor” to “Good”

The fix was three changes. First, rewrite the hero tag with image_tag, responsive widths, and fetchpriority="high". Second, remove loading="lazy" from the hero. Third, uninstall a “speed optimization” app that was injecting a JS preloader blocking the render.


What tools do I use to audit Shopify images?

Google classifies Core Web Vitals as an official ranking factor and publishes the thresholds on Search Central (Google Search Central). An audit should combine lab and field data, never just one.

The four tools I use on every audit

  1. Lighthouse (Chrome DevTools): lab data. Good for iterating fast when you touch code. Doesn’t reflect real user experience.
  2. PageSpeed Insights: combines Lighthouse with CrUX (Chrome User Experience Report) data, which is real field data aggregated from Chrome (web.dev). This is the source Google uses for ranking.
  3. Search Console, Core Web Vitals: the aggregate URL-level view, over 28 days. This is where you spot trends and which URLs are in the red.
  4. Calibre or SpeedCurve: continuous monitoring. Only needed if you’re a brand with serious traffic and want alerts when something breaks.

What’s the difference between lab data and field data?

Lab data is generated in a simulated, controlled environment (Lighthouse). Field data (CrUX) comes from real users on their real networks, devices, and connections. Google uses field data for ranking. If your Lighthouse scores 95 but your CrUX shows LCP of 4s, CrUX is the one that counts.


Frequently asked questions

Does Shopify automatically convert my images to WebP?

Yes. Since 2021, the Shopify CDN automatically serves WebP when the user’s browser supports it, per the official docs (Shopify.dev). You don’t need third-party apps for this. What you do need to do is upload already-optimized source files: the conversion reduces size but won’t fix a poorly exported 5 MB image.

Should I use loading="lazy" on every image in my Shopify store?

No. Per the official web.dev guide, using loading="lazy" on the LCP element degrades performance because it delays its download (web.dev, 2023). The rule: the first visible image goes with loading="eager" and fetchpriority="high". Everything below the fold goes with loading="lazy". Native attribute support is over 95% of browsers (Can I Use, 2025).

What’s the maximum size a product image should be on Shopify?

It depends on how it’s displayed. For a product image shown full-screen in zoom, 2048 px wide is enough. Shopify serves smaller versions automatically via srcset if you use image_url with widths. The general web.dev rule is that no image served to the user should exceed the size it actually occupies on screen by more than 30% (web.dev, 2024).

How much does LCP improve when going from JPG to WebP on Shopify?

It depends on the starting point. WebP weighs 25% to 35% less than an equivalent JPG at similar visual quality per web.dev measurements (web.dev, 2024). On stores where LCP is a large unoptimized image, switching to WebP plus tuning width and srcset can drop LCP by 30% to 50%, like the cosmetics case described above.

Do I need an app to optimize images on Shopify?

Usually, no. The trio of optimizations that actually moves the needle, automatic WebP, image_tag with srcset, and native loading="lazy", ships with modern themes like Dawn (Shopify.dev). “Speed optimization” apps often duplicate what the platform already does and add JavaScript that hurts performance. Audit first, install later.


Conclusion

Images aren’t a decorative topic. They’re 42.3% of the average mobile page weight and, on most Shopify stores, the difference between a “Poor” LCP and a “Good” one. The good news is that the Shopify stack already does half the work: automatic WebP conversion, fast CDN, image_tag with generated srcset. The other half is on you: upload already-optimized files, use image_tag instead of the old img_url, put loading="lazy" where it belongs (and eager on the LCP), and write specific alt text. None of this needs paid apps. It needs reading the theme, editing Liquid, and measuring before and after with PageSpeed Insights and Search Console. If you’d like me to take a look at your store with you, book a 30-minute call and we’ll go through your Core Web Vitals live. 30-min session · No commitment.

Lionel Fenestraz — Freelance Google Ads & Meta Ads Consultant
Lionel Fenestraz
Freelance PPC & CRO Consultant · Google Partner · CXL Certified · Google Ads Search Certified
7+ years managing Google Ads and Meta Ads for vacation rental, B2B and ecommerce. Trilingual ES/EN/FR.
Free first call

Could your ad campaigns
perform better?

30 minutes to review your situation and tell you exactly what I would change. No pitch, no sales proposal.

Book a call →
30 min · Google Meet · No commitment