TL;DR — Quick checklist
- 1Choose the right format (WebP for photos, SVG for icons).
- 2Compress every image — quality 75–85 is usually invisible to the eye.
- 3Resize images to the display size — never serve a 4000px photo in a 400px slot.
- 4Use lazy loading: add loading="lazy" to all below-the-fold images.
- 5Serve responsive images with srcset for different screen densities.
- 6Strip EXIF metadata — saves extra bytes and protects user privacy.
- 7Set correct Cache-Control headers so images are cached aggressively.
Step 1 — Choose the right format
Format selection is the most important decision you'll make. Getting it wrong can cost you 50–80% extra file size before you even start compressing.
- Photographs and complex images → Use WebP (lossy). Fall back to JPEG for browsers that don't support WebP (very rare in 2026).
- Logos, icons, diagrams → Use SVG if the image is vector-based — it scales perfectly at zero extra cost. Use lossless WebP or PNG for raster icons.
- Screenshots and images with text → Use lossless WebP or PNG — lossy compression creates visible artefacts around sharp edges and text.
- Animations → Prefer video (MP4/WebM) over GIF. A 3 MB GIF is typically under 300 KB as a short silent video.
Step 2 — Compress at the right quality
Compression is a trade-off between file size and visual quality. For most photographs displayed on screen:
95
Visually lossless
80
Recommended
65
Good balance
40
Smallest size
Quality 80 is the sweet spot for most content — users almost never notice the difference compared to quality 100, but the file is often 3–5× smaller.
Tip: Always compare the original and compressed versions side by side at actual display size (not zoomed in). Artefacts that look terrible at 300% zoom are invisible at 100%.
Step 3 — Resize to the display dimensions
Serving a 3000×2000 px image in a 600×400 px container wastes bandwidth on pixels the browser immediately throws away. Always resize images to the largest size they'll actually be displayed.
For responsive sites, you can serve multiple sizes using srcset:
<img
src="photo-800w.webp"
srcset="photo-400w.webp 400w,
photo-800w.webp 800w,
photo-1600w.webp 1600w"
sizes="(max-width: 600px) 400px, 800px"
alt="Description"
/>The browser will automatically download only the image that matches the current viewport size and screen density.
Step 4 — Add lazy loading
Images that are off-screen when the page loads should be deferred until the user scrolls to them. This is a one-attribute change:
<img src="photo.webp" loading="lazy" alt="Description" />Only skip loading="lazy" for the Largest Contentful Paint (LCP) image — usually the hero image. That one should load eagerly (the default) to avoid hurting your LCP score.
Step 5 — Strip EXIF metadata
JPEG files shot on a camera or phone contain EXIF metadata: GPS coordinates, camera model, lens settings, timestamps, and sometimes even thumbnails embedded inside the file. This can add 10–50 KB to each image and, critically, may leak location data.
Stripping EXIF before publishing is both a performance win and a privacy best practice. PixelZip can do this for you — just enable the Strip Metadata toggle before downloading your compressed image.
Step 6 — Cache aggressively
Once images are optimised, make sure they stay cached in the browser. Set a long Cache-Control header and use content-hashed filenames so you can bust the cache when the image changes:
Cache-Control: public, max-age=31536000, immutableCloudflare Pages sets this automatically for static assets with hashed filenames. Most CDNs do too.
Measuring the impact
After optimising your images, measure the results with:
- Lighthouse (built into Chrome DevTools) — check the "Properly size images" and "Serve images in next-gen formats" audits.
- PageSpeed Insights — gives real-world field data alongside lab scores.
- WebPageTest — waterfall view shows exactly which images are blocking rendering.