All posts

Shopify Image Optimization: How to Speed Up Your Store

Learn how to optimize images for Shopify with the right sizes, formats, compression, alt text and lazy loading. A practical guide to faster pages and better SEO.

Open your product page on a phone with a weak signal and count the seconds before the main photo shows up. If you got past three, you already know why this article exists.

Images are the heaviest thing on almost every Shopify store. On a typical storefront they account for somewhere between 60 and 80 percent of total page weight. That single fact explains a lot. It explains why your PageSpeed score is stuck in the yellow, why your Largest Contentful Paint keeps failing in Search Console, and why mobile shoppers bounce before they ever see your add to cart button.

The good news is that image optimization is one of the few technical fixes on Shopify that you can mostly do yourself, without a developer, without a rebuild, and without giving up photo quality. This guide walks through the whole thing in the order you should actually do it.

What Shopify handles for you (and what it quietly does not)

There is a lot of confusion here, so let’s clear it up first. It saves you from doing work twice.

Shopify does this automatically:

  • Serves every image through its global CDN
  • Converts your JPEG and PNG uploads to WebP for browsers that support it, which in 2026 is basically all of them
  • Generates multiple resized versions of each image and serves the right one based on device and screen size
  • Adds lazy loading on modern Online Store 2.0 themes for images further down the page

Shopify does not do this:

  • Compress your original file before you upload it
  • Rename your files for SEO
  • Write your alt text
  • Decide which image is your Largest Contentful Paint element
  • Stop your theme from lazy loading the one image that should never be lazy loaded

Think of Shopify as the delivery truck. It is fast and it goes everywhere. But if you load it with 5MB boxes, it still arrives late. Everything in this guide is about what you put in the truck.

Step 1: Start with the right source dimensions

Before you touch compression, get the pixel dimensions right. Uploading a 6000 pixel wide photo straight from the camera is the single most common mistake, and it costs you nothing to fix.

Shopify accepts images up to 4472 x 4472 pixels and 20MB per file. Do not aim for that ceiling. It is a limit, not a target.

Here is what actually works:

Image typeRecommended sizeAspect ratio
Product photo2048 x 2048 px1:1
Collection thumbnail1024 x 1024 px1:1
Homepage hero / slideshow1920 x 1080 px16:9
Collection banner2800 x 1000 pxWide
Blog post featured image1800 x 1000 pxRoughly 16:9
Logo500 px wide (PNG, transparent)Varies

The 2048 x 2048 recommendation for products is not arbitrary. It is the balance point between three things pulling in different directions: Shopify’s zoom feature needs enough pixels to look sharp when a shopper hovers, the page needs to stay light, and collection grids need every image to line up cleanly. Anything below roughly 800 x 800 will not trigger zoom properly on most themes.

One more thing that gets ignored: pick an aspect ratio and stick to it across your whole catalog. Mixed ratios in a collection grid look sloppy, and they cause visual jumps as the page loads. Consistent grids have been shown to lift browse to product click rates noticeably, which is a conversion win on top of the speed win.

Step 2: Compress before you upload, not after

This is where most of the file size disappears. Shopify’s CDN will convert your file to WebP, but it converts what you gave it. A bloated original becomes a slightly less bloated WebP.

Export your JPEGs at quality 80 to 85. Not 100. At normal viewing sizes almost nobody can tell the difference, and you often cut the file in half.

Target file sizes after compression:

  • Product images: under 200KB, ideally 100 to 150KB
  • Hero and banner images: under 180KB, since this is usually your LCP element
  • Blog and content images: under 150KB
  • Thumbnails and icons: under 50KB

Free tools that do this well:

  • Squoosh (squoosh.app) gives you a side by side slider so you can see quality drop in real time before you commit
  • TinyPNG handles bulk uploads and does smart lossy compression on PNG and JPEG
  • ImageOptim if you are on a Mac and want a drag and drop desktop app
  • SVGOMG for SVG files, which most image CDNs skip entirely

Run one test image through at a few quality levels and view it at the size it will actually appear on your store. Not zoomed to 400 percent in Photoshop. That comparison is where people talk themselves into files three times larger than they need.

Step 3: Choose the right format for the job

Format choice is the highest leverage single decision you make here.

WebP is the default for 2026. It is roughly 25 to 35 percent smaller than JPEG at the same visual quality, supports transparency like PNG, and works in every browser your customers use. Shopify serves it automatically.

JPEG is still a perfectly good upload format for photographs. Shopify converts it to WebP on delivery anyway, so uploading JPEG at quality 85 is a clean workflow that avoids double compression artifacts.

PNG only when you genuinely need transparency, like logos, icons and badges. Never use PNG for a photograph. It will be several times larger for no benefit.

AVIF compresses even harder than WebP, up to about 50 percent smaller than JPEG. It is worth forcing on large photographic heroes if your traffic skews modern. Encoding is slower and support is still a little behind WebP, so treat it as an upgrade for specific images rather than a blanket switch.

SVG for logos, icons and simple line graphics. Infinitely scalable, tiny file size, and it stays crisp on retina screens.

GIF only for short product animations, like showing a color change or a mechanism moving. Watch the file size closely. Animated GIFs balloon into multiple megabytes very fast. If the clip is longer than two seconds, use a video instead.

Step 4: Name your files before you upload them

Here is the part people learn the hard way: you cannot rename an image file after it is uploaded to Shopify. The filename gets baked into the CDN URL. Your only fix is to delete the image and re upload it with the new name, product by product.

So do it right the first time.

Bad: IMG_4521.jpg

Good: organic-cotton-crew-neck-tshirt-black.jpg

Google does read filenames as a signal, especially when other context on the page is thin. It matters most for Google Images and Google Lens, and Google Images now feeds directly into shopping surfaces, so it is a real traffic channel for product photos.

Rules to follow:

  • Lowercase only
  • Hyphens between words, not underscores or spaces
  • Describe what the image actually shows, including color and variant
  • Keep it under about 60 characters
  • Skip stop words and marketing fluff

There are also two Shopify specific quirks that will silently mangle your filenames:

  1. Image names cannot end with pico, icon, thumb, testing, small, compact, medium, large or grande. Shopify’s CDN reads those as resize instructions and will append a random suffix to your file.
  2. Avoid underscores placed right before dimensions. Use product-image-5x4.jpg rather than product_image_5x4.jpg.

Also make sure every filename is unique across your store. Duplicates get a random string tacked on, which undoes all your careful naming.

If you already have hundreds of images named IMG_whatever, do not try to fix them all in one weekend. Prioritize your best selling products, work one product at a time so you never leave a listing without photos, and accept that this is a multi day project.

Step 5: Write alt text that earns its place

Alt text does three jobs at once. It describes the image to screen reader users, it tells Google what the picture contains, and it now feeds AI search results and multimodal systems that read your page. All three want the same thing: an honest, specific description.

Shopify allows up to 512 characters, but keep it under 125. Screen readers cut off longer text, and nobody benefits from a paragraph.

Weak: alt="shoes"

Stuffed: alt="buy shoes cheap shoes best shoes online shoes store shoes for men"

Strong: alt="Men's brown leather Chelsea boot, side view on white background"

A few practical rules:

  • Describe the product, the color or variant, the material, and the angle
  • Work your keyword in naturally, or leave it out. A forced keyword reads badly to everyone
  • Use empty alt text (alt="") for purely decorative images like dividers and background textures. Empty is correct. Missing is not
  • Do not start with “image of” or “photo of”. Screen readers already announce that it is an image
  • Keep alt text consistent with your Product schema. Mismatches can hurt rich result eligibility

To edit alt text in Shopify, go to the product, open the Media panel, click the image, and use the Edit option. For bulk work, export your products to CSV, fill in the Image Alt Text column in a spreadsheet, and re import. That handles alt text at scale, though it will not fix filenames.

Step 6: Never lazy load your hero image

This is the single most damaging image bug on Shopify themes, and it is one attribute long.

Lazy loading is great for images below the fold. It is terrible for the first image a visitor sees, because it tells the browser to deprioritize the exact resource that defines your Largest Contentful Paint score.

Shopify’s image_tag filter applies loading="lazy" by default to images past the third section in a template. Sounds sensible until you count your sections. Announcement bar, sticky promo, an app embed, then your hero. That hero is section four, and it just got lazy loaded.

The fix in your section file:

{{ section.settings.image
  | image_url: width: 1800
  | image_tag:
      loading: 'eager',
      fetchpriority: 'high',
      sizes: '100vw',
      widths: '600, 900, 1200, 1500, 1800',
      alt: section.settings.image.alt
}}

Two attributes are doing the work. loading: 'eager' stops the deferral. fetchpriority: 'high' pushes the image to the front of the browser’s download queue, ahead of theme scripts and app tags.

Merchants who fix a lazy loaded hero typically see LCP improve by one to three seconds on slow mobile connections. If the hero was already eager and just missing fetchpriority, expect something in the 200 to 800 millisecond range. Both are meaningful.

One more thing worth checking: if your hero is a CSS background-image, convert it to a real <img> tag inside the section. Background images cannot use fetchpriority, they do not get automatic srcset, and the browser discovers them late because it has to parse CSS first.

For everything below the fold, lazy loading is correct. Just be a little generous with the fold on mobile. The second and third product cards in a grid often sit right at the edge, and eagerly loading those keeps scrolling feeling instant.

Step 7: Serve the right size to each device

Over 70 percent of Shopify traffic is mobile. Sending a phone a 1800 pixel wide image so it can display it at 390 pixels is pure waste, and it is extremely common.

The image_url filter with a widths list solves this. Shopify generates each variant on first request and caches it globally after that.

For a product card in a collection grid:

{{ product.featured_image
  | image_url: width: 600
  | image_tag:
      loading: 'lazy',
      widths: '200, 300, 400, 600',
      sizes: '(min-width: 990px) 25vw, (min-width: 750px) 33vw, 50vw',
      alt: product.title
}}

The sizes attribute is the part people get wrong. It has to describe how wide the image actually renders in your CSS layout, not how wide the file is. If your grid shows four columns on desktop, that is 25vw. Get this wrong and the browser downloads the wrong variant even though everything else is set up correctly.

A quick way to audit this: open Chrome DevTools, go to the Network tab, filter by Img, and reload a product page. Sort by size. Any file over 300KB deserves a look. Any 500KB image rendering in a 200 pixel box means a width parameter is missing somewhere.

Step 8: Reserve space so nothing jumps

Cumulative Layout Shift is the Core Web Vital that annoys shoppers most, even when they cannot name it. Text moves, they tap the wrong thing, they leave.

Every image needs explicit width and height attributes, or a CSS aspect-ratio on its container. That lets the browser reserve the correct space before the file arrives, so the layout is stable from the first paint.

image_tag handles this automatically when you pass a width. If you are hand writing image markup in a custom section, add the attributes yourself:

<img
  src="{{ image | image_url: width: 700 }}"
  width="700"
  height="{{ 700 | divided_by: image.aspect_ratio | ceil }}"
  alt="{{ image.alt | escape }}"
  loading="lazy"
  decoding="async"
>

Step 9: Check the images your apps are adding

You can optimize every product photo in your catalog and still fail PageSpeed because a review widget, a trust badge app or a popup is injecting uncompressed PNGs into your pages.

Run a page through PageSpeed Insights and read the “Properly size images” and “Serve images in next gen formats” diagnostics. If files appear that you never uploaded, trace them back to the app. Sometimes you can swap the asset in the app’s settings. Sometimes the honest answer is that the app costs more than it earns.

While you are there, upload your theme assets through the Shopify admin rather than hotlinking from an external host. Files uploaded through the admin get served from Shopify’s CDN with all the automatic optimization attached. Files pulled from somewhere else do not.

Step 10: Measure, then keep measuring

Optimization is not a one time cleanup. Every new product upload is a chance to slide backwards.

Build a rhythm:

  • Weekly: spot check new product uploads against your standards
  • Monthly: review Core Web Vitals in Google Search Console, which uses real visitor data rather than a simulated test
  • Quarterly: run a full image audit across your top templates

Tools worth knowing:

  • Google PageSpeed Insights for lab scores plus real world field data
  • Chrome DevTools Performance tab to see exactly which element is your LCP and whether it is being lazy loaded. This is more reliable than PageSpeed scores, which vary between runs
  • Google Search Console for the Core Web Vitals report across your whole store
  • Shopify’s own Online Store Speed report in the admin for a rough trend line

The targets to aim for: LCP under 2.5 seconds, CLS under 0.1, INP under 200 milliseconds.

The quick checklist

Print this. Tape it near your desk.

  • Resize to 2048 x 2048 for products before uploading
  • Export JPEGs at quality 80 to 85
  • Compress every file to under 200KB, heroes under 180KB
  • Rename with lowercase hyphenated keywords before upload
  • Avoid the reserved filename endings and duplicate names
  • Write specific alt text under 125 characters
  • Use alt="" on decorative images
  • Set the hero to loading: 'eager' with fetchpriority: 'high'
  • Lazy load everything below the fold
  • Pass a widths list and an accurate sizes value
  • Include width and height on every image
  • Keep aspect ratios consistent across the catalog
  • Audit app injected images
  • Recheck Core Web Vitals monthly

Mistakes that keep showing up

Uploading straight from the camera. A 6MB, 6000 pixel JPEG goes into Shopify, gets converted to a still oversized WebP, and slows every device that requests it.

Compressing until it looks bad. There is a point where you stop saving meaningful bytes and start losing sales. A blurry product photo is a worse problem than a slow one. Test at actual display size and stop when you can see the difference.

Assuming the CDN fixes everything. It resizes and converts. It does not undo a bad source file.

Chasing a 100 PageSpeed score. You will not get one on a real store with real apps, and it is not the goal. LCP under 2.5 seconds on mobile is the goal, and that is achievable.

Ignoring the blog and content pages. Store owners obsess over product photos and then drop a 2MB screenshot into a blog post. Those pages rank too.

Frequently asked questions

Do I need to upload WebP files to Shopify? No. Shopify’s CDN converts JPEG and PNG to WebP automatically for browsers that support it. Uploading a well compressed JPEG at quality 85 is a clean, simple workflow. You can upload WebP directly if you want a little more control, but it is not required.

Can I change an image filename after uploading? No. The filename is locked into the CDN URL at upload. You have to delete the image and re upload it with the correct name. This is exactly why renaming before upload matters so much.

How much file size is too much for a product image? Aim for under 200KB. Above 300KB you are into territory where mobile shoppers on slow connections will notice. Above 500KB something has gone wrong in your export settings.

Does alt text actually help rankings? It helps Google understand and match your images to queries, which drives traffic through Google Images and increasingly through AI generated answers that pull in visuals. It is not a magic ranking lever for your main page, but it is one of the highest impact image changes because so many stores leave it empty or generic.

Should I use an image optimization app instead? Apps are useful for bulk work on an existing catalog, especially bulk alt text and compression across hundreds of products. They do not replace good habits going forward. If you fix your upload workflow, you need the app far less.

Where to start tomorrow

If this feels like a lot, do not try to do all ten steps at once. Pick the three that pay off fastest:

  1. Check whether your hero image is being lazy loaded, and fix it if it is. This is a five minute change with the biggest single impact on LCP.
  2. Compress and resize the images on your top ten selling products.
  3. Write real alt text for those same products.

Then come back for the rest. Image optimization is one of the few areas in ecommerce where the work is cheap, the rules are stable, and the results show up in both your speed report and your revenue. Very little else gives you that.