惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
量子位
B
Blog RSS Feed
Schneier on Security
Schneier on Security
L
LINUX DO - 最新话题
博客园 - 三生石上(FineUI控件)
Recent Announcements
Recent Announcements
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google DeepMind News
Google DeepMind News
N
News | PayPal Newsroom
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tailwind CSS Blog
MongoDB | Blog
MongoDB | Blog
大猫的无限游戏
大猫的无限游戏
PCI Perspectives
PCI Perspectives
aimingoo的专栏
aimingoo的专栏
D
Docker
T
The Exploit Database - CXSecurity.com
Last Week in AI
Last Week in AI
W
WeLiveSecurity
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
J
Java Code Geeks
O
OpenAI News
C
Cisco Blogs
Hacker News - Newest:
Hacker News - Newest: "LLM"
爱范儿
爱范儿
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Threat Research - Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Help Net Security
Help Net Security
Scott Helme
Scott Helme
The Hacker News
The Hacker News
Y
Y Combinator Blog
A
Arctic Wolf
V
V2EX
P
Proofpoint News Feed
Simon Willison's Weblog
Simon Willison's Weblog
A
About on SuperTechFans
S
Securelist
G
Google Developers Blog
Cyberwarzone
Cyberwarzone
The GitHub Blog
The GitHub Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Optimize Product Images for Amazon, Shopify, and the Web
Iteration La · 2026-04-30 · via DEV Community

Product Images Need to Work for Marketplaces and the Web

If you sell on Amazon or Shopify, image optimization is not just a performance task, it is also a requirements task. Amazon cares about white backgrounds, square dimensions, and JPEG output. Shopify cares about storefront clarity, fast load times, and consistent product presentation. Then your own site still needs responsive image delivery, modern formats, and smaller files for Core Web Vitals.

This guide covers the broad image optimization workflow behind all of those requirements: format selection, compression, responsive delivery, and automation. If you want the marketplace-specific implementations, start with Optimize Product Image for Amazon or Optimize Product Image for Shopify, then come back here for the deeper optimization framework.

Images Are the Heaviest Part of the Web

The median web page transfers over 2 MB of images. For media-heavy sites — e-commerce, real estate, travel, news — that number climbs to 5-10 MB. On a 4G mobile connection, that's 3-8 seconds of loading just for images.

Google measures this. Largest Contentful Paint (LCP) — the time until the largest visible element renders — is a Core Web Vital that directly affects search ranking. For most pages, the largest element is an image. Slow images mean lower rankings, higher bounce rates, and fewer conversions.

Image optimization isn't a nice-to-have. It's the single highest-impact performance improvement for most websites. This guide covers the complete workflow: choosing formats, compressing effectively, sizing for different screens, and building automated pipelines.

Image Formats: Choosing the Right One

Four formats dominate the web. Each has a specific use case.

JPEG

The workhorse of web images since 1992. Lossy compression with a quality parameter (1-100) that controls the size-quality tradeoff. Universal browser support.

Use for: photographs, complex images with many colors, images where a small quality loss is acceptable.

Quality guidelines: 80-90 for hero images, 70-80 for thumbnails and cards, 60-70 for background images.

Limitations: no transparency, no lossless mode, compression artifacts visible at low quality settings (blocky patterns around edges).

PNG

Lossless compression. Supports transparency (alpha channel). Files are significantly larger than JPEG for photographs.

Use for: screenshots, graphics with sharp edges and text, images requiring transparency, icons and logos.

Limitations: large file sizes for photos (3-5x larger than equivalent JPEG), no lossy mode for size reduction.

WebP

Developed by Google, now supported by 97%+ of browsers. Offers both lossy and lossless modes, plus transparency. 25-34% smaller than JPEG at equivalent quality.

Use for: everything on the web where browser support isn't a concern. WebP should be your default format.

Quality guidelines: 80-85 for general web images, 75 for thumbnails, 85-90 for hero images.

Limitations: slightly less saturated colors than JPEG at very low quality settings, some older tools don't support it.

AVIF

The newest contender. Based on the AV1 video codec. 50% smaller than JPEG in many cases. Supports transparency, HDR, and wide color gamut. 92%+ browser support.

Use for: hero images and product photos where maximum compression matters. Best results on photographic content.

Quality guidelines: 65-75 for general use (AVIF maintains quality at lower numbers than JPEG), 75-80 for hero images.

Limitations: slower to encode than WebP, slightly less browser support, some edge cases with very detailed textures.

The Decision Framework

For most websites, the hierarchy is:

  1. Serve AVIF when the browser supports it (hero images, product photos)
  2. Fall back to WebP for broad compatibility
  3. Fall back to JPEG for legacy contexts (email, old systems)
  4. Use PNG only when you need lossless quality or transparency

Implement this with the <picture> element:

<picture>
  <source srcset="/images/hero.avif" type="image/avif">
  <source srcset="/images/hero.webp" type="image/webp">
  <img src="/images/hero.jpg" alt="Hero image" width="1200" height="800">
</picture>

Enter fullscreen mode Exit fullscreen mode

Compression: Finding the Quality Sweet Spot

Compression quality has diminishing returns. The difference between quality 100 and quality 90 is invisible to most viewers. The file size difference is 40-60%.

The Quality Curve

At quality 100, you're storing nearly every pixel perfectly. At quality 90, you're losing imperceptible detail. At quality 80, most viewers can't tell the difference from the original. Below quality 60, artifacts become visible — blocky patterns in JPEG, color banding in WebP.

The practical sweet spots by format:

Format High quality Standard web Thumbnails Background
JPEG 90 80-85 70-75 60-70
WebP 90 80-85 75 65-70
AVIF 80 65-75 60-65 50-60

AVIF maintains visual quality at lower numbers than JPEG and WebP — a quality 70 AVIF often looks as good as a quality 85 JPEG.

Compress to a Target File Size

Sometimes the requirement isn't "quality 85" — it's "under 500KB." Email attachment limits, mobile app asset budgets, CMS upload restrictions.

The Iteration Layer's Image Transformation API has a compress_to_size operation that handles this:

import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({ apiKey: "YOUR_API_KEY" });

const result = await client.transformImage({
  file: {
    type: "url",
    name: "photo.jpg",
    url: sourceUrl,
  },
  operations: [
    {
        type: "compress_to_size",
        max_file_size_in_bytes: 500_000,
    },
  ],
});

Enter fullscreen mode Exit fullscreen mode

{
  "success": true,
  "data": {
    "buffer": "iVBORw0KGgoAAAANSUhEUg...",
    "mime_type": "image/jpeg"
  }
}

Enter fullscreen mode Exit fullscreen mode

The operation uses a quality-first strategy: it reduces JPEG quality from 85 down to 50. If the image is still over the target, it reduces dimensions. Quality-first preserves visual quality better than dimension-first because quality reduction removes imperceptible detail, while dimension reduction removes visible content.

Resizing: Never Serve Larger Than Display Size

A 4000x3000 photo displayed at 800x600 wastes 96% of its pixels. The browser downloads 5 MB to display 300 KB worth of content. This is the most common image performance mistake.

Resize to Display Size

If your hero image displays at 1200px wide on desktop, serve a 1200px wide image. Not the 4000px original from the photographer.

const result = await client.transformImage({
  file: {
    type: "url",
    name: "hero.jpg",
    url: sourceUrl,
  },
  operations: [
    {
      type: "resize",
      width_in_px: 1200,
      height_in_px: 800,
      fit: "cover",
    },
    {
      type: "convert",
      format: "webp",
      quality: 85,
    },
  ],
});

Enter fullscreen mode Exit fullscreen mode

{
  "success": true,
  "data": {
    "buffer": "iVBORw0KGgoAAAANSUhEUg...",
    "mime_type": "image/webp"
  }
}

Enter fullscreen mode Exit fullscreen mode

Fit Strategies

The fit parameter controls how the image fills the target dimensions:

  • cover — scales to fill the target, crops overflow. Result is exactly the target dimensions. Best for thumbnails, cards, hero images — anything needing exact dimensions.
  • contain — scales to fit within the target, adds letterboxing. Result is at most the target dimensions. Best when the full image must be visible.
  • inside — scales down to fit within the target, preserves aspect ratio, never upscales. Best for constraining maximum dimensions.
  • fill — stretches to exactly the target dimensions. Distorts the image. Rarely what you want.
  • outside — scales to cover the target, preserves aspect ratio, never downscales. Best for guaranteeing minimum dimensions.

For most web use cases, cover (exact dimensions, cropped) and inside (constrained, not cropped) handle everything.

Responsive Images: Different Sizes for Different Screens

A 4K monitor needs a larger image than a phone screen. Serving the desktop image to mobile wastes bandwidth. Serving the mobile image to desktop looks blurry.

srcset and sizes

HTML's responsive image attributes let the browser choose the right image size:

<img
  srcset="/images/hero-320.webp 320w,
          /images/hero-640.webp 640w,
          /images/hero-960.webp 960w,
          /images/hero-1280.webp 1280w,
          /images/hero-1920.webp 1920w"
  sizes="100vw"
  src="/images/hero-960.webp"
  alt="Hero image"
  width="1920"
  height="1080"
>

Enter fullscreen mode Exit fullscreen mode

The srcset tells the browser which sizes are available. The sizes tells the browser how wide the image will be at the current viewport. The browser picks the smallest image that covers the display area.

Generating Responsive Variants

Generate all variants from a single source image:

import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({ apiKey: "YOUR_API_KEY" });

const widths = [320, 640, 960, 1280, 1920];

const variants = await Promise.all(
  widths.map(async (width) => {
    const result = await client.transformImage({
      file: {
    type: "url",
    name: "hero.jpg",
    url: sourceUrl,
  },
      operations: [
        {
          type: "resize",
          width_in_px: width,
          height_in_px: Math.round(width * 0.5625),
          fit: "cover",
        },
        {
            type: "sharpen",
            sigma: 0.5,
        },
        {
      type: "convert",
      format: "webp",
      quality: 85,
    },
      ],
    });
  })
);

Enter fullscreen mode Exit fullscreen mode

Five sizes, WebP format, optimized quality, sharpened after downscaling. Each variant is a single API call.

Art Direction with picture

When different aspect ratios are needed for different screen sizes — landscape on desktop, square on mobile — use the <picture> element:

<picture>
  <source media="(max-width: 768px)" srcset="/images/hero-mobile.webp" type="image/webp">
  <source media="(min-width: 769px)" srcset="/images/hero-desktop.webp" type="image/webp">
  <img src="/images/hero-desktop.jpg" alt="Hero image">
</picture>

Enter fullscreen mode Exit fullscreen mode

Generate the mobile variant with different dimensions or a different crop. The smart_crop operation is useful here — it detects the subject and crops around it, so the focal point is preserved across aspect ratios.

// Mobile: square crop, subject-centered
const mobileResult = await client.transformImage({
  file: {
    type: "url",
    name: "hero.jpg",
    url: sourceUrl,
  },
  operations: [
    {
      type: "smart_crop",
      width_in_px: 640,
      height_in_px: 640,
    },
    {
      type: "convert",
      format: "webp",
      quality: 85,
    },
  ],
});

// Desktop: landscape, standard resize
const desktopResult = await client.transformImage({
  file: {
    type: "url",
    name: "hero.jpg",
    url: sourceUrl,
  },
  operations: [
    {
      type: "resize",
      width_in_px: 1920,
      height_in_px: 1080,
      fit: "cover",
    },
    {
      type: "convert",
      format: "webp",
      quality: 85,
    },
  ],
});

Enter fullscreen mode Exit fullscreen mode

{
  "success": true,
  "data": {
    "buffer": "iVBORw0KGgoAAAANSUhEUg...",
    "mime_type": "image/webp"
  }
}

Enter fullscreen mode Exit fullscreen mode

Sharpening After Downscaling

Downscaling images softens them slightly — a 4000px image resized to 800px loses some perceived sharpness even though the content is identical. A light sharpen pass after resizing restores crispness without introducing artifacts.

const result = await client.transformImage({
  file: {
    type: "url",
    name: "photo.jpg",
    url: sourceUrl,
  },
  operations: [
    {
      type: "resize",
      width_in_px: 800,
      height_in_px: 600,
      fit: "cover",
    },
    {
        type: "sharpen",
        sigma: 0.5,
    },
    {
      type: "convert",
      format: "webp",
      quality: 85,
    },
  ],
});

Enter fullscreen mode Exit fullscreen mode

{
  "success": true,
  "data": {
    "buffer": "iVBORw0KGgoAAAANSUhEUg...",
    "mime_type": "image/webp"
  }
}

Enter fullscreen mode Exit fullscreen mode

Keep the sigma low — 0.3 to 0.7. Higher values create visible halos around edges that look worse than the softness you're trying to fix.

Order matters: sharpen after resize, convert last. Sharpening before resize wastes effort (the resize will soften it again). Converting before the final step may introduce artifacts that get amplified by later operations.

Smart Cropping for Responsive Thumbnails

Traditional center-cropping works when the subject is centered. It fails when the subject is off to one side — a portrait where the person stands left of frame, a product photo with the item in the lower-right corner.

The smart_crop operation uses AI object detection to find the main subject before cropping:

const result = await client.transformImage({
  file: {
    type: "url",
    name: "photo.jpg",
    url: sourceUrl,
  },
  operations: [
    {
      type: "smart_crop",
      width_in_px: 400,
      height_in_px: 400,
    },
    {
      type: "convert",
      format: "webp",
      quality: 80,
    },
  ],
});

Enter fullscreen mode Exit fullscreen mode

{
  "success": true,
  "data": {
    "buffer": "iVBORw0KGgoAAAANSUhEUg...",
    "mime_type": "image/webp"
  }
}

Enter fullscreen mode Exit fullscreen mode

The result is a 400x400 image with the subject centered, regardless of where it was in the original. No coordinate math, no face detection library, no per-image manual adjustment.

Automated Pipelines

The Basic Pipeline

A production image optimization pipeline combines resizing, sharpening, and conversion:

import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({ apiKey: "YOUR_API_KEY" });

const result = await client.transformImage({
  file: {
    type: "url",
    name: "image.jpg",
    url: sourceUrl,
  },
  operations: [
    {
      type: "resize",
      width_in_px: 800,
      height_in_px: 533,
      fit: "cover",
    },
    { type: "auto_contrast" },
    {
        type: "sharpen",
        sigma: 0.5,
    },
    {
      type: "convert",
      format: "webp",
      quality: 85,
    },
  ],
});

Enter fullscreen mode Exit fullscreen mode

{
  "success": true,
  "data": {
    "buffer": "iVBORw0KGgoAAAANSUhEUg...",
    "mime_type": "image/webp"
  }
}

Enter fullscreen mode Exit fullscreen mode

Four operations, one API call. Resize, auto-contrast, sharpen, convert. No server to maintain.

The Complete Pipeline with Variants

For a production content pipeline, generate multiple formats and sizes from each source image:

import { IterationLayer } from "iterationlayer";
const client = new IterationLayer({ apiKey: "YOUR_API_KEY" });

const generateImageSet = async (sourceUrl: string) => {
  const widths = [320, 640, 960, 1280, 1920];
  const formats = ["webp", "avif"] as const;

  const variants = await Promise.all(
    formats.flatMap((format) =>
      widths.map(async (width) => {
        const quality = format === "avif" ? 70 : 85;
        const result = await client.transformImage({
          file: {
    type: "url",
    name: "image.jpg",
    url: sourceUrl,
  },
          operations: [
            {
              type: "resize",
              width_in_px: width,
              height_in_px: Math.round(width * 0.667),
              fit: "cover",
            },
            {
                type: "sharpen",
                sigma: 0.5,
            },
            {
              type: "convert",
              format,
              quality,
            },
          ],
        });
      })
    )
  );

  return variants;
};

Enter fullscreen mode Exit fullscreen mode

This generates 10 variants (5 widths x 2 formats) from a single source image. Upload each variant to your CDN and reference them in srcset and <source> elements.

Measuring Performance

Core Web Vitals

Three metrics that matter for image optimization:

Largest Contentful Paint (LCP) — time until the largest element renders. Smaller images load faster. Target: under 2.5 seconds.

Cumulative Layout Shift (CLS) — layout instability caused by elements loading and shifting content. Set width and height on <img> tags so the browser reserves space before the image loads. Target: under 0.1.

First Contentful Paint (FCP) — time until any content renders. Large images on the critical rendering path delay FCP. Lazy-load below-the-fold images.

Lighthouse

Run Lighthouse audits regularly. The "Opportunities" section flags specific images that could be resized, compressed, or converted to modern formats. It estimates the byte savings for each suggestion.

Real User Monitoring

Lab tools like Lighthouse test under controlled conditions. Real user monitoring (Vercel Analytics, web-vitals library, Google CrUX) shows actual performance across real devices and connections. An image that loads fine on fiber may be the bottleneck on 3G.

Lazy Loading

Images below the fold — not visible when the page first loads — should lazy-load. The browser fetches them only when they scroll into view.

<img src="/images/product.webp" alt="Product" loading="lazy" width="400" height="400">

Enter fullscreen mode Exit fullscreen mode

The loading="lazy" attribute is supported by all modern browsers. No JavaScript needed.

Do NOT lazy-load the hero image or any above-the-fold content. Those images are on the critical rendering path — they need to load immediately.

CDN Delivery

Serve optimized images from a CDN (Content Delivery Network). The CDN caches images at edge locations close to the user, reducing latency.

Most CDNs support cache headers. Set a long Cache-Control max-age on image URLs that include a content hash — the URL changes when the image changes, so stale cache isn't a concern:

Cache-Control: public, max-age=31536000, immutable

Enter fullscreen mode Exit fullscreen mode

This tells the browser and CDN to cache the image for one year without revalidation.

Putting It All Together

A complete image optimization workflow:

  1. Upload — accept the original image (any format, any size)
  2. Process — resize to target dimensions, sharpen, convert to WebP and AVIF
  3. Generate variants — multiple sizes for responsive delivery
  4. Store — upload processed variants to object storage (S3, R2, GCS)
  5. Serve — deliver through a CDN with long cache headers
  6. Reference — use srcset, sizes, and <picture> in your HTML

Steps 2-3 are the API calls. Steps 4-6 are your infrastructure. The processing itself is one API call per variant — no servers to scale, no libraries to patch, no image processing infrastructure to maintain.

Get Started

Check the docs for the full operation reference and format-specific quality guidelines. The TypeScript and Python SDKs handle file input and response parsing.

Sign up for a free account — no credit card required. Take your heaviest page image, run it through the pipeline, and measure the before-and-after file size.