Image optimization best practices


Images are usually the biggest bytes on your pages. That makes them one of the fastest levers for improving mobile load time, protecting conversions, and avoiding expensive "site feels slow" complaints – especially on category pages and product detail pages where you load many thumbnails plus a large hero.

Image optimization best practices means delivering the right image (dimensions and format) at the lowest acceptable bytes, loaded at the right time, with stable layout and strong caching. Done well, it improves LCP (your "main content shows up" moment), helps prevent CLS, and reduces bandwidth and CDN/origin cost.

Stacked bar chart of image byte savings from resizing, modern formats, and compression across key e-commerce templatesStacking the biggest wins (resize, modern formats, compression) shows why image work often delivers large byte savings quickly on revenue-driving templates.

Which images to fix first

If you try to optimize every image everywhere, you'll stall. Website owners get the fastest results by prioritizing images that directly influence key user-perceived moments and templates.

Start with the LCP image

On many sites, the LCP element is an image (hero banner, featured product photo, large carousel slide). If that image is heavy, slow to discover, or deprioritized, LCP suffers.

Focus checks:

  • Is the LCP image too large in dimensions (served at 2000px wide but displayed at 390px)?
  • Is it a legacy format (JPEG/PNG) that could be smaller as WebP/AVIF?
  • Is it lazy-loaded or injected late by JavaScript?
  • Is it coming from a slow host (third-party, uncached, redirects)?

Related reading: Above-the-fold optimization and Critical rendering path.

The Website Owner's perspective
If your hero image is your LCP, optimizing it is often a direct conversion lever: faster first impression, faster product discovery, and fewer bounces from mobile shoppers on cellular connections.

Next, fix "death by thumbnails"

Category pages and search results often load dozens of images. Each one might be "small," but the total can overwhelm:

  • Too many requests (HTTP requests)
  • Too much total transfer
  • CPU decode overhead on low-end phones

Your goal is not perfect quality on every thumbnail – it's "good enough" clarity at the smallest bytes.

Then, clean up hidden waste

Common sources of wasted image bytes:

  • Retina overserving (always 2x/3x even when not needed)
  • PNG used for photographs
  • Original uploads served directly (camera photos, 4000px wide)
  • Multiple carousels/sliders all loading immediately

How to right-size images

Right-sizing is usually the #1 image optimization win because it removes "invisible bytes" users never see.

What right-sizing really means

An image has:

  • Displayed size: how large it appears in CSS (e.g., 360px wide)
  • Delivered size: the actual pixel dimensions downloaded (e.g., 2000px wide)
  • Device pixel ratio factor: many devices benefit from 2x sources (not always 3x)

If you deliver 2000px for a 360px slot, you pay for bytes that don't improve the visible result.

Use responsive images (properly)

Responsive images let the browser choose the smallest adequate file based on viewport and DPR.

  • Use srcset with multiple widths.
  • Use sizes so the browser knows how wide the image will be in the layout.
  • Use <picture> when you need format switching (AVIF/WebP fallback).

If you want the deeper mechanics and patterns, see Responsive images.

Practical srcset guidance for commerce:

  • Product grid cards: 200w, 320w, 480w, 640w (most sites don't need more)
  • Hero images: 640w, 960w, 1280w, 1536w, 1920w (depending on layout)
  • Keep the number of candidates reasonable; each additional variant increases storage/processing complexity.

Beware the "sizes omitted" trap

If you provide srcset but omit (or misstate) sizes, browsers often assume the image will be full viewport width and download a larger candidate than necessary – especially painful on mobile.

Don't confuse "retina" with "always ship 2x"

A common compromise:

  • Default to ~1x candidates for most thumbnails and non-critical images.
  • Provide 2x where it matters (PDP gallery, zoom entry image, hero).
  • Avoid 3x unless you have a clear visual requirement.

Which formats and compression to use

Format choice determines how efficiently you represent the same visual information.

Choose formats based on content type

Use this as a starting point:

  • Photos (products, lifestyle): AVIF (best) or WebP, fallback to JPEG
  • UI graphics with transparency: PNG or WebP (sometimes AVIF), or SVG if vector
  • Logos and icons: SVG (usually best)
  • Animations: prefer video (MP4/WebM) over GIF when possible

More detail: WebP vs AVIF and Image compression.

Decision tree for choosing image formats and fallbacks for photos, transparency, vector art, and animationFormat choice is a decision tree: photos, transparency, vectors, and animation each have different "best" formats and fallbacks.

Compression is a business decision (quality vs bytes)

Compression isn't "maximize quality" or "minimize bytes." It's: minimize bytes while preserving the visual cues that sell.

Practical rules:

  • Product detail images: keep textures and edges; avoid blotchy artifacts on labels and fabric.
  • Thumbnails: compress aggressively; users need recognition, not detail.
  • Background/hero photography: watch for banding in gradients (sky, studio backdrops).

A simple operational approach:

  1. Pick a few representative images (dark, bright, high detail, gradients).
  2. Test a small set of quality settings.
  3. Lock defaults per use case (thumbnail vs PDP vs hero).
  4. Periodically re-check after design changes.

The Website Owner's perspective
Customers don't abandon a purchase because your thumbnail is 92 quality instead of 78. But they do abandon when the page feels slow. Use quality where it affects trust (PDP), and chase bytes where it doesn't (lists and supporting images).

Don't ignore decode and rendering costs

Even if transfer size is small, very large pixel dimensions can cost CPU to decode and render, hurting smoothness and responsiveness (related to INP indirectly through main-thread contention). Right-sizing helps here twice: less network, less CPU.

How to load images without breaking LCP

A lot of "image optimization" work fails because the bytes are smaller but the browser still loads the image late, or layout shifts when it appears.

Protect the LCP image (do not lazy load it)

For the image that is likely to become LCP:

  • Do not use loading="lazy".
  • Ensure it's discovered early in HTML (not injected late).
  • Consider priority hints and preloading when appropriate.

Good supporting concepts:

In practice, the biggest LCP image problems are:

  • Carousels that load the first slide as a background image in CSS
  • Hero images loaded after JS renders
  • Lazy-loading everything by default

Line chart showing how LCP increases as hero image transfer size grows, comparing prioritized vs lazy-loaded hero imagesLCP is not just bytes. The same hero image can land under or over the 2.5s "good" line depending on whether it's prioritized or delayed by lazy loading and late discovery.

Lazy load the rest (carefully)

For below-the-fold images:

  • loading="lazy" is usually a net win.
  • Avoid JS-heavy lazy-loading libraries unless you truly need features.
  • Watch out for "lazy loading above the fold" on short screens (some mobile viewports are smaller than you expect).

Also, lazy loading can increase request bursts later during scroll. That's typically acceptable, but on image-heavy pages it can cause jank if decode work spikes. If you see issues, reduce pixel dimensions further and consider staggering.

Prevent CLS from images

Images cause layout shift when the browser doesn't know how much space to reserve.

Fixes:

  • Always include width and height attributes (or CSS aspect-ratio) so the browser can reserve space.
  • Avoid swapping to a different aspect ratio after load (e.g., responsive art direction without stable sizing).
  • Be careful with client-side image placeholders that change height.

More: Layout instability and Zero layout shift.

How to cache and deliver images well

Once you've shrunk images and loaded them correctly, caching and delivery makes sure you don't pay the cost repeatedly.

Use long-lived caching for versioned URLs

Best practice for static images:

  • Cache-Control: public, max-age=31536000, immutable
  • Use versioned file names (hashes or version query strings you actually change on updates)

If your cache headers are weak, every repeat visitor (and every multi-page session) re-downloads images, inflating both load time and bandwidth cost.

See: Browser caching, Cache-Control headers, and Cache TTL.

Deliver from the edge

Serving images from a CDN reduces latency and improves throughput, especially on mobile.

Related reading:

Operational checklist:

  • Avoid redirects on image URLs.
  • Ensure HTTP/2 or HTTP/3 where possible (HTTP/2 performance, HTTP/3 performance).
  • Separate cookie-heavy domains from static assets when feasible (cookies increase request bytes).
  • Confirm correct Content-Type and compression settings on the server side (not for already-compressed formats like AVIF/WebP, but for SVG and text assets).

The Website Owner's perspective
Image caching and CDN delivery is "profit protection." It reduces repeat-load time for returning shoppers, lowers bandwidth bills, and prevents performance regressions when traffic spikes (promotions, email campaigns, seasonal launches).

How to measure results and avoid regressions

Image work should show up in both lab and field data – but not always immediately.

What to track (and what changes mean)

Tie image changes to outcomes you actually care about:

What you trackWhat it tells youWhat a change usually means
LCP (LCP)Main content speedHero image weight/priority improved or got worse
CLS (CLS)Visual stabilityMissing dimensions, placeholders, or late-loading media
Total image transfer (per page)Bandwidth and load pressureResizing/format/compression is working (or not applied)
Image request countOverfetchingToo many thumbnails, carousels, or duplicate assets
Cache hit behaviorRepeat-view speedCache headers and CDN configuration are correct

To understand why lab and field differ, see Field vs lab data and Measuring Web Vitals. For external validation, PageSpeed Insights is useful, and CrUX data helps you interpret real-user trends.

Debug with a waterfall and LCP identification

When an image change "should have helped" but didn't, the culprit is usually:

  • wrong image still being selected (bad sizes)
  • late discovery (JS rendering, background images)
  • priority inversions (lazy load, low priority)
  • caching not effective

If you use PageVitals, the Network request waterfall view is designed for this kind of root-cause work: /docs/features/network-request-waterfall/.

For field monitoring of LCP specifically, see the docs for the LCP report: /docs/features/field-testing/web-vitals/lcp-report/.

Add performance budgets for images

Image regressions are common: a designer uploads a new hero, a plugin changes thumbnail sizes, a CMS starts serving originals.

Budgets help you catch that early. If you use PageVitals, review Performance budgets: /docs/features/budgets/.

A practical budget approach for image-heavy templates:

  • Budget the LCP image transfer size (e.g., keep under 250 KB on mobile)
  • Budget total image transfer per template
  • Budget image request count on category pages

Common mistakes that undo image gains

A quick "don't do this" list that shows up constantly in audits:

  • Lazy-loading the hero/LCP image (LCP gets worse even if bytes are smaller)
  • No width/height on images (CLS spikes)
  • Using CSS background images for critical content (harder to preload and prioritize)
  • Uploading originals and relying on CSS scaling
  • Serving PNG for photos (often 2–10x larger than necessary)
  • Forgetting caching (every page view pays the full cost again)

A practical rollout plan

If you want a low-risk sequence that typically delivers results in days, not months:

  1. Identify the LCP image on your top 3 templates (home, category, product).
  2. Right-size it to the maximum displayed size (plus reasonable DPR).
  3. Switch to modern formats with fallback (AVIF/WebP).
  4. Do not lazy load the LCP image; lazy load the rest.
  5. Add dimensions everywhere to eliminate image-driven CLS.
  6. Fix caching so repeat views are fast and cheap.

This sequence avoids the common trap of "we compressed images but LCP didn't move."


Frequently asked questions

A practical starting target is under 1 MB total image transfer on key landing pages and under 1.5 to 2 MB on product detail pages, with the LCP image ideally under 150 to 250 KB on mobile. The right target depends on product imagery needs and traffic mix.

Convert photographic images where you get meaningful savings without visible artifacts. AVIF can be smaller than WebP, but encoding is heavier and rare cases decode slower on low end devices. A safe approach is AVIF with WebP fallback for photos, and keep PNG or SVG for UI graphics.

LCP often is the hero image. If you lazy load it, the browser delays fetching until after layout and some scripts run, pushing the render later. Fix by not lazy loading the LCP image, giving it high priority, and ensuring the correct responsive source is selected immediately.

Find the page LCP element and confirm whether it is an image, then check its request priority, transfer size, and whether it is being resized by CSS. Next identify the top image bytes by URL and check if they are uncompressed originals, missing srcset, or loaded off domain with poor caching.

Start with the top templates that drive revenue and SEO: homepage, category, and product pages. Fix the LCP image first by resizing and switching formats, then implement responsive images for listings, and finally add long cache headers. These steps usually reduce bounce and lift conversion fastest.