Image Optimization Strategy for Platforms with Heavy Visual Content

In platforms like auctions, marketplaces, real estate listings, or any product-based platforms, there can be tens of images per page, and each image might be high-resolution and large in size.

Usecase

  • Sellers upload large images (around 5MB each) while listing auctions.
  • Buyers view auction lots, which sometimes can have 500+ images per auction.
  • Since auctions involve valuable items, image quality must be preserved (no visible loss).
  • Pages need to load fast even with so many dynamic images.

Solution

We applied multiple optimization techniques:

1. WebP Conversion at Upload (Seller Application)

  • When sellers upload images, we convert them to WebP format using lossless compression.
  • WebP provides smaller file sizes while retaining the original quality.
  • This reduces the overall storage and transfer size dramatically without making the images blurry or pixelated.
export const convertToWebP = (file) => {
    return new Promise((resolve) => {
        const img = new Image();
        const reader = new FileReader();
        reader.onload = (e) => {
            img.src = e.target.result;
        };
        img.onload = () => {
            const canvas = document.createElement("canvas");
            const scale = 0.9;
            canvas.width = img.width * scale;
            canvas.height = img.height * scale;
            const ctx = canvas.getContext("2d");
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
            // lossless WebP conversion
            canvas.toBlob(
                (blob) => {
                    const webpFile = new File(
                        [blob],
                        file.name.replace(/\.\w+$/, ".webp"),
                        { type: "image/webp" }
                    );
                    resolve(webpFile);
                },
                "image/webp",
            );
        };
        reader.readAsDataURL(file);
    });
};
 

2. Image Component Optimization (Buyer Application)

  • Used the next/image component from Next.js where the images are small or thumbnail-sized.
  • The Image component automatically:
    • Serves responsive image sizes (srcset).
    • Uses lazy loading.
    • Optimizes images based on device screen size.
  • We configured a CDN domain in the next.config.js to serve images faster globally.
const nextConfig = {
   reactStrictMode: false,
   swcMinify: true,
   images: {
       unoptimized: false,
       domains: [`cdn.${process.env.NEXT_PUBLIC_AMPLIFY_DOMAIN_NAME}`],
       deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
       imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
       formats: ['image/webp'],
       minimumCacheTTL: 60,
   },
};
 module.exports = nextConfig;

3. Pre-fetching Lead Images

  • We preloaded the first auction image (lead image) to improve the LCP (Largest Contentful Paint) metric.
  • Helps in rendering the most important content quickly.

Why WebP?

  • WebP offers 25-35% smaller file sizes compared to JPEG without visible quality loss.
  • Supports lossless and lossy compression.
  • Faster load times lead to better SEO and higher engagement.
  • Unlike JPEG, WebP can also handle transparency and animation efficiently.

JPEG is purely lossy, and compressing large images using JPEG further results in noticeable quality loss, which is unacceptable for auction or product detail platforms.

Real Results After Optimization

Test Before Optimization After Optimization
6 lots (4.9MB each) Total page size: 39MB Total page size: 7MB
50 lots (1.4MB each) Total page size: 10.8MB Total page size: 5.4MB
5 Likes

Update / Learning from a Safari Edge Case

A small follow-up to my earlier post — found an interesting edge case while testing across browsers.

Initially, I assumed converting uploaded images to WebP on the client side would consistently reduce file size. That held true in Chrome and most Chromium-based browsers.

But while testing on Safari, I noticed something unexpected.

Our upload flow has a 5MB validation limit, and in Safari some converted images actually became larger than the original (for example, ~5MB turning into ~10MB), causing uploads to fail.

After digging into it, I learned that client-side compression libraries depend on the browser’s image/canvas implementation internally, and browser behavior can vary.

So the updated approach was:

  • Try WebP compression first

  • Check if the output is actually smaller

  • If not, try JPEG compression as a fallback

  • If neither helps, keep the original file

import imageCompression from "browser-image-compression";

export const convertToWebP = async (file) => {
    try {
        // Try WebP first
        const webpResult = await imageCompression(file, {
            maxSizeMB: 5,
            maxWidthOrHeight: 1920,
            useWebWorker: true,
            fileType: "image/webp",
            initialQuality: 0.85,
        });

        // Use only if it actually reduces size
        if (webpResult.size < file.size) {
            return new File(
                [webpResult],
                file.name.replace(/\.\w+$/, ".webp"),
                { type: "image/webp" }
            );
        }

        // Fallback to JPEG
        const jpegResult = await imageCompression(file, {
            maxSizeMB: 5,
            maxWidthOrHeight: 1920,
            useWebWorker: true,
            fileType: "image/jpeg",
            initialQuality: 0.85,
        });

        if (jpegResult.size < file.size) {
            return new File(
                [jpegResult],
                file.name.replace(/\.\w+$/, ".jpeg"),
                { type: "image/jpeg" }
            );
        }

        return file;
    } catch {
        return file;
    }
};

What I learned:
Client-side optimization is powerful, but it still depends on browser-specific implementations. A format that performs well in one browser may behave differently in another.

Long-term better approach:
Move compression to the server side. That makes compression behavior consistent and removes browser dependency entirely, leading to more predictable optimization.