Patu

AVIF vs WebP vs JPEG: real numbers at equal quality

Most “AVIF is 50% smaller than JPEG” claims compare a JPEG at quality 75 to an AVIF at some other setting. That is not a comparison — a -q 75 in one encoder is not the same picture as -q 75 in another. The only honest question is: at a fixed perceptual quality, how many bytes does each format need?

We measured it. Not on a handful of hero images, but across 1,900+ real photographs, with the actual encoders, scored by a perceptual metric rather than a guessed quality number.

How we measured it

That last point matters: comparing cwebp -q 80 to avifenc -q 80 is meaningless. Comparing “the WebP that looks as good as the AVIF” is the whole game.

The numbers

At ssimulacra2 85 (high quality, hard to tell from the original) — the 548 photos where all four formats reach it:

Format Median per photo vs JPEG
JPEG (libjpeg-turbo) 833 KB —
WebP 708 KB −16%
AVIF 605 KB −28%
JPEG XL 553 KB −33%

At the same quality, AVIF is 16% smaller than WebP, and both beat JPEG comfortably.

At ssimulacra2 80 (good quality, a common web target) — across 1,884 photos:

Format Median per photo vs JPEG
JPEG 510 KB —
WebP 471 KB −11%
AVIF 368 KB −29%
JPEG XL 351 KB −32%

AVIF’s lead widens at 80 (−29% vs JPEG, −21% vs WebP): it holds detail at lower bitrates where JPEG and WebP start to fall apart.

These figures line up with the independent literature — AVIF landing roughly 25–30% under JPEG at matched quality is a well-replicated result. What this run adds is that it is measured perceptually, at equal quality, on a large and un-cherry-picked photo set.

The caveats, stated plainly

What this means in practice

Serve AVIF with a WebP and JPEG fallback, and target a perceptual score, not a quality number. A fixed -q ships inconsistent quality across images — some over-compressed and visibly bad, some wastefully large. Searching each image’s encoder quality to hit a target ssimulacra2 score is what gives you both the smallest bytes and a quality you can actually promise.

That is what Patu does: it searches encoder quality per image to hit a perceptual target, and returns AVIF and WebP with a JPEG fallback, behind a CDN. The numbers above are why the default is AVIF-first.

curl -X POST "https://patu.dev/v1/compress?formats=avif,webp,fallback&target=85" \
  -H "X-Api-Key: $PATU_KEY" \
  --data-binary @photo.jpg -o photo.avif

You give it a target quality; it gives you the smallest file at that quality, in the formats a browser can actually use.


Method and data: the Patu benchmark harness over the photo category; ssimulacra2 via the rust-av implementation; encoders libjpeg-turbo, libwebp, libaom, libjxl at their released versions. Sizes are the median across photos where every format reaches the target score.