Most devs reach for Cloudinary, Squoosh CLI, or a Node backend to optimize images.

But what if you could do production-grade image compression — including WebP and MozJPEG — directly in the browser, using WebAssembly? No server, no upload, no cost.

Here’s how to build your own browser-based image optimizer using WebAssembly and wasm-bindgen.


Step 1: Use precompiled WASM codecs via Squoosh

Google’s Squoosh project exposes production-ready WASM image codecs like MozJPEG, WebP, and AVIF — and you can use them in your own app.

Install the core codecs:

npm install @squoosh/lib

Then load a codec like MozJPEG:

import { ImagePool } from '@squoosh/lib';

const imagePool = new ImagePool();

Step 2: Accept user uploads and compress in-browser

Set up an input to handle image uploads:


Now optimize the file:

async function handleFile(event) {
  const file = event.target.files[0];
  const arrayBuffer = await file.arrayBuffer();
  
  const image = imagePool.ingestImage(arrayBuffer);
  await image.encode({
    mozjpeg: {
      quality: 70,
    },
  });

  const encoded = await image.encodedWith.mozjpeg;
  const blob = new Blob([encoded.binary], { type: 'image/jpeg' });

  // Optionally download it
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'optimized.jpg';
  a.click();
}

Step 3: Support Other Codecs (WebP, AVIF, etc.)

Swap mozjpeg for webp or avif to support modern formats:

await image.encode({
  webp: {
    quality: 80,
  },
});

You can even expose a UI to let users choose the output format.


Step 4: Optional React Hook for Integration

To make this reusable across your app, extract it into a hook:

function useImageOptimizer() {
  const imagePool = useMemo(() => new ImagePool(), []);

  const optimize = async (file, format = 'mozjpeg') => {
    const arrayBuffer = await file.arrayBuffer();
    const image = imagePool.ingestImage(arrayBuffer);
    await image.encode({ [format]: { quality: 75 } });
    const encoded = await image.encodedWith[format];
    return new Blob([encoded.binary], { type: \`image/\${format}\` });
  };

  return { optimize };
}

Pros:

  • Completely serverless — all image processing happens client-side
  • Supports WebP, MozJPEG, and AVIF with production-quality compression
  • Great for PWAs, CMS apps, or privacy-first tools (no upload)

⚠️ Cons:

  • WASM codecs are large (~1MB+), so initial load is heavier
  • Processing is memory/CPU intensive — slower on low-end devices
  • Not ideal for batch-processing large volumes

Summary

With just a few lines of JavaScript and Google’s prebuilt WASM codecs, you can build a browser-based image optimizer that rivals many SaaS tools. This approach keeps images private, requires no backend infrastructure, and provides full control over format and quality. It’s ideal for privacy-sensitive apps, PWAs, or anytime you want to offload work to the client without sacrificing performance.

Next time you consider reaching for a third-party API or spinning up a Lambda just to optimize images, remember — the browser can do it all.


If this was helpful, you can support me here: Buy Me a Coffee