You're Sending 750px Images Into a 285px Space

Open your homepage on a phone, or in Chrome's device toolbar at 390 by 844. Right-click a product image, choose Inspect, then hover the img tag in the Elements panel. Chrome gives you two numbers: Rendered size and Intrinsic size.
"Rendered is the space the image occupies. Intrinsic is the file the browser actually downloaded."
Across the audits we run, those two numbers sit a long way apart on the homepage, and the homepage is the page Google measures first. The Web Almanac's 2025 crawl puts the median Lighthouse performance score for Shopify sites at 55 on mobile against 71 on desktop. Most of that gap is weight. Most of the weight is pictures.
The gap, by the numbers
55
Median mobile Lighthouse score for Shopify sites, against 71 on desktop
855px
Real pixels a 285px slot needs on a typical 3x phone screen
12x
Pixel data a 3000px upload sends into a 285px slot, versus what the screen can use
The number in the title is a trap
A 390px viewport is not a 390px screen. Most current phones report a device pixel ratio of 3, so a slot 285 CSS pixels wide needs about 855 real pixels before it stops looking soft. Send 285 and it's blurry. Send 750 and you're marginally under what the screen can resolve.
So the headline case is close to right, and that's exactly what makes it hard to catch by eye. The expensive version is the theme section or the app that ignores the slot altogether and hands the browser your original upload at 2400 or 3000 pixels wide, because someone wrote a plain img src with no srcset behind it.
Lighthouse catches it. The audit fails an image when a correctly sized version would be at least 4 KiB smaller than the one you served, and it does that maths with device pixel ratio already accounted for. In Lighthouse 13 the check lives inside the image delivery insight rather than under its old name, Properly size images. Either way, if Lighthouse calls an image oversized, it's oversized after allowing for the retina screen.
"We compressed the images" is a different fix
Shopify's CDN reads the browser's Accept header and serves AVIF or WebP where the browser supports it, falling back to the original format where it doesn't. That happens on every image the image_url filter touches, with no app and no setting to turn on. A compression app installed on top is largely re-solving a solved problem, and its script is more weight on every page.
"Compression changes bytes per pixel. Sizing changes how many pixels leave the CDN in the first place."
A 3000px image dropped into a 285px slot carries roughly twelve times the pixel data a 3x phone can use, and no compression ratio recovers that. It's packing the box more tightly when what you needed was a smaller box.
What the fix looks like in the theme
In Liquid, image_url sets the ceiling and image_tag describes the slot.
{{ product.featured_image | image_url: width: 1200 | image_tag: widths: '165, 360, 535, 750, 1070', sizes: '(min-width: 750px) 25vw, 50vw' }}
The width on image_url is the largest version the CDN will generate, capped at Shopify's 5760px maximum, and it never upscales past your original file. The widths list becomes the srcset candidates. The sizes string tells the browser how wide the image will really display, so it can choose a candidate before layout has been worked out.
Sizes is where most themes quietly leak. If it claims 100vw and the image renders at half the screen, the browser buys double what it needs on every card in the grid, and adding more srcset entries won't help. Check that string against the actual rendered CSS width before you touch anything else.
Two things image_tag gives you for free are worth keeping. It writes width and height attributes from the image's own dimensions, which reserves the space and stops the page jumping around as pictures arrive. And it sets loading="lazy" for images in sections further down the page. Your hero is the one image you don't want lazy-loaded, so pass preload on that one.
Two minutes to find yours:
- Open your homepage in Chrome, device toolbar at 390 by 844.
- Right-click your worst three images, choose Inspect, then hover each img tag in the Elements panel.
- Write down Rendered size against Intrinsic size for each one.
- Flag anything where intrinsic is more than about four times the rendered width. That's either a hardcoded src or a sizes attribute that isn't telling the truth. Both are theme work, not another subscription.
Then ask what those images are doing there at all. If the artwork above your product grid is filling space rather than selling anything, sizing it properly is a smaller win than removing it, which is the argument in Your Collection Pages Are Hiding the Products.
The bottom line
Sizing is free. It's already built into image_url and image_tag, and it takes two minutes to check on your worst three images. A compression app duplicates what Shopify's CDN already does on every request, and adds its own weight on top of the pages it's supposed to be speeding up.
At beCommerce, we check rendered against intrinsic on every theme and performance engagement we run. If you want a hand finding yours, book your free audit →.
Is your store making any of these mistakes?
We audit Shopify stores for exactly these kinds of conversion-killing patterns — the ones that have become normalised until you see them through a customer's eyes.
Book your free audit →

