Detailed guide

Webp Avif Implementation Guide

View contents

WebP and AVIF Implementation Guide: Complete Format Conversion Strategy

Introduction

This comprehensive guide walks you through implementing WebP and AVIF image formats on your website. You’ll learn conversion strategies, quality optimization, server configuration, and how to build an automated image pipeline.

What you’ll learn:

  • Converting images to WebP and AVIF
  • Optimal quality settings for different image types
  • Server configuration for correct MIME types
  • Building automated conversion workflows
  • Testing and validating implementation
  • Measuring performance improvements

Table of Contents

  1. Understanding Format Differences
  2. Conversion Tools and Methods
  3. Quality Settings Optimization
  4. HTML Implementation
  5. Server Configuration
  6. Automated Build Pipelines
  7. CDN and Edge Delivery
  8. Testing and Validation
  9. Measuring Impact
  10. Troubleshooting Common Issues

1. Understanding Format Differences

Before implementing, understand when each format excels:

WebP Characteristics

  • Encoding speed: Fast (good for on-the-fly conversion)
  • Decoding speed: Fast (good for client performance)
  • Compression: 25-35% smaller than JPEG
  • Progressive loading: Supported
  • Browser support: 97%+ globally

AVIF Characteristics

  • Encoding speed: Slow (CPU-intensive, best for pre-processing)
  • Decoding speed: Moderate
  • Compression: 50%+ smaller than JPEG
  • Progressive loading: Not supported
  • Browser support: 85%+ globally

Decision Matrix

Scenario Recommended Format Reason
General photos WebP + JPEG fallback Best balance of compression and compatibility
Maximum compression needed AVIF + WebP + JPEG fallback Smallest files for modern browsers
Real-time generation WebP only Faster encoding
HDR content AVIF Only format with full HDR support
Animation WebP Better support than AVIF for animated images

2. Conversion Tools and Methods

Online Tools

Squoosh (squoosh.app)

  • Browser-based, no installation needed
  • Side-by-side quality comparison
  • Multiple format output
  • Excellent for testing quality settings

Cloudinary

  • URL-based transformation
  • Automatic format selection based on browser
  • Good for dynamic images

Command-Line Tools

cwebp (WebP)

# Convert single image
cwebp -q 80 input.jpg -o output.webp

# Batch convert all JPEGs in directory
for f in *.jpg; do cwebp -q 80 "$f" -o "${f%.jpg}.webp"; done

avifenc (AVIF)

# Convert single image
avifenc --min 20 --max 30 input.png output.avif

# With specific quality (0-63, lower = better quality)
avifenc -a cq-level=25 input.jpg output.avif

Programmatic Conversion (Node.js)

Sharp.js is the gold standard for server-side image processing:

const sharp = require('sharp');

async function convertImage(inputPath) {
  const image = sharp(inputPath);

  // Generate WebP
  await image
    .webp({ quality: 80 })
    .toFile(inputPath.replace(/\.(jpg|png)$/, '.webp'));

  // Generate AVIF
  await image
    .avif({ quality: 60 }) // AVIF quality scale differs
    .toFile(inputPath.replace(/\.(jpg|png)$/, '.avif'));

  console.log(`Converted: ${inputPath}`);
}

// Batch conversion
const glob = require('glob');
glob('images/**/*.{jpg,png}', (err, files) => {
  files.forEach(convertImage);
});

3. Quality Settings Optimization

Quality settings significantly impact both file size and visual appearance. Here are recommended starting points:

WebP Quality Settings

Image Type Quality (0-100) Notes
Photos 75-85 Good balance for most photos
Product images 85-90 Higher quality for detail
Thumbnails 70-75 Smaller display size tolerates lower quality
Screenshots 90-100 (lossless) Preserve text clarity

AVIF Quality Settings

AVIF uses a different quality scale (cq-level 0-63 where lower = better):

Image Type cq-level Sharp quality Notes
Photos 25-30 55-65 Excellent compression
Product images 20-25 65-75 Higher quality
Thumbnails 35-40 45-55 Acceptable for small sizes
Screenshots 10-15 80-90 Preserve detail

Finding Optimal Quality

Use SSIM (Structural Similarity Index) to compare quality programmatically:

const sharp = require('sharp');

async function findOptimalQuality(inputPath, targetSSIM = 0.95) {
  const original = await sharp(inputPath).raw().toBuffer();

  for (let quality = 90; quality >= 50; quality -= 5) {
    const compressed = await sharp(inputPath)
      .webp({ quality })
      .toBuffer();

    // Calculate SSIM here
    // If SSIM >= targetSSIM, this quality is acceptable
  }
}

4. HTML Implementation

Basic Picture Element

<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Description" width="800" height="600">
</picture>

Responsive Images with Modern Formats

Combine format switching with responsive images:

<picture>
  <!-- AVIF with multiple sizes -->
  <source
    type="image/avif"
    srcset="image-400.avif 400w,
            image-800.avif 800w,
            image-1200.avif 1200w"
    sizes="(max-width: 600px) 400px,
           (max-width: 1200px) 800px,
           1200px">

  <!-- WebP with multiple sizes -->
  <source
    type="image/webp"
    srcset="image-400.webp 400w,
            image-800.webp 800w,
            image-1200.webp 1200w"
    sizes="(max-width: 600px) 400px,
           (max-width: 1200px) 800px,
           1200px">

  <!-- JPEG fallback with multiple sizes -->
  <img
    src="image-800.jpg"
    srcset="image-400.jpg 400w,
            image-800.jpg 800w,
            image-1200.jpg 1200w"
    sizes="(max-width: 600px) 400px,
           (max-width: 1200px) 800px,
           1200px"
    alt="Description"
    width="1200"
    height="800"
    loading="lazy">
</picture>

Art Direction with Modern Formats

Different crops for different viewports:

<picture>
  <!-- Mobile: square crop, AVIF -->
  <source
    media="(max-width: 600px)"
    type="image/avif"
    srcset="image-mobile.avif">
  <source
    media="(max-width: 600px)"
    type="image/webp"
    srcset="image-mobile.webp">

  <!-- Desktop: wide crop, AVIF -->
  <source
    type="image/avif"
    srcset="image-desktop.avif">
  <source
    type="image/webp"
    srcset="image-desktop.webp">

  <img src="image-desktop.jpg" alt="Description">
</picture>

5. Server Configuration

Your server must send correct Content-Type headers.

Apache (.htaccess)

# Add MIME types for modern formats
AddType image/webp .webp
AddType image/avif .avif

# Enable content negotiation (optional)
<IfModule mod_negotiation.c>
  Options +MultiViews
</IfModule>

Nginx

# Add MIME types
types {
    image/webp webp;
    image/avif avif;
}

# Optional: Serve WebP automatically when supported
map $http_accept $webp_suffix {
    default "";
    "~*webp" ".webp";
}

location ~* ^(.+)\.(jpg|jpeg|png)$ {
    try_files $1$webp_suffix $uri =404;
}

Node.js (Express)

const express = require('express');
const app = express();

// Set MIME types
express.static.mime.define({
  'image/webp': ['webp'],
  'image/avif': ['avif']
});

app.use(express.static('public'));

6. Automated Build Pipelines

Vite Plugin

// vite.config.js
import { defineConfig } from 'vite';
import viteImagemin from 'vite-plugin-imagemin';

export default defineConfig({
  plugins: [
    viteImagemin({
      webp: {
        quality: 80,
      },
      avif: {
        quality: 60,
      },
    }),
  ],
});

Webpack Configuration

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g)$/i,
        use: [
          {
            loader: 'responsive-loader',
            options: {
              adapter: require('responsive-loader/sharp'),
              format: 'webp',
              quality: 80,
            },
          },
        ],
      },
    ],
  },
};

GitHub Actions Workflow

# .github/workflows/optimize-images.yml
name: Optimize Images

on:
  push:
    paths:
      - 'images/**'

jobs:
  optimize:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install Sharp
        run: npm install sharp

      - name: Convert Images
        run: node scripts/convert-images.js

      - name: Commit Changes
        run: |
          git config --local user.email "[email protected]"
          git config --local user.name "GitHub Action"
          git add -A
          git commit -m "Auto-optimize images" || exit 0
          git push

7. CDN and Edge Delivery

Modern CDNs can transform images on-the-fly:

Cloudflare Image Resizing

<!-- Automatic format selection -->
<img src="/cdn-cgi/image/format=auto,quality=80/images/photo.jpg">

Cloudinary

<!-- Automatic format and quality -->
<img src="https://res.cloudinary.com/demo/image/upload/f_auto,q_auto/sample.jpg">

Imgix

<!-- WebP with fallback -->
<img src="https://example.imgix.net/image.jpg?auto=format&q=80">

8. Testing and Validation

Browser DevTools

  1. Open Network tab
  2. Filter by “Img”
  3. Check “Type” column for format served
  4. Verify file sizes are reduced

Command-Line Validation

# Check file type
file image.webp
# Output: image.webp: RIFF (little-endian) data, Web/P image

# Check MIME type served
curl -I https://example.com/image.webp | grep content-type
# Output: content-type: image/webp

Lighthouse Audit

Run Lighthouse and check “Serve images in next-gen formats” audit.


9. Measuring Impact

Before/After Comparison

Track these metrics:

  • Total image bytes transferred
  • LCP (Largest Contentful Paint)
  • Page load time on 3G/4G

Google Search Console

Monitor Core Web Vitals improvements in Search Console > Experience > Core Web Vitals.

Real User Monitoring

// Track LCP improvements
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP:', entry.startTime, entry.element);
    // Send to analytics
  }
}).observe({ entryTypes: ['largest-contentful-paint'] });

10. Troubleshooting Common Issues

Images Not Loading

Problem: Browser shows broken image icon Solution: Check MIME types are configured correctly on server

Wrong Format Served

Problem: JPEG served even when browser supports WebP Solution: Verify <picture> element order (AVIF first, then WebP, then JPEG)

Quality Too Low

Problem: Visible compression artifacts Solution: Increase quality setting; use lossless for screenshots

AVIF Encoding Too Slow

Problem: Build times are very long Solution: Pre-generate AVIF files; use WebP for dynamic images

Safari Compatibility

Problem: Older Safari versions don’t support WebP Solution: Always include JPEG/PNG fallback in <img> element


Implementation Checklist

  • [ ] Audit existing images and identify candidates for conversion
  • [ ] Choose conversion tools (Squoosh for testing, Sharp for automation)
  • [ ] Determine optimal quality settings for each image type
  • [ ] Convert images to WebP and AVIF
  • [ ] Update HTML to use <picture> elements
  • [ ] Configure server MIME types
  • [ ] Set up automated build pipeline
  • [ ] Test in multiple browsers (Chrome, Firefox, Safari, Edge)
  • [ ] Validate with Lighthouse
  • [ ] Monitor Core Web Vitals for improvements


References

  1. MDN Web Docs - Image file type and format guide
  2. web.dev - Serve images in next-gen formats
  3. Chrome Developers - Lighthouse: Serve images in modern formats
  4. Sharp.js - High performance Node.js image processing
  5. Squoosh - Image compression web app

Related articles

Related version

Introduction

Modern Image Formats Explained

If you're still serving images only in JPEG and PNG formats, you're likely sending 25-50% more data than necessary

Category hub

Hub

Images Seo Hub

Images are critical to user engagement—but they can also be your website's biggest performance bottleneck

In the same category

Detailed guide

Image Optimization Guide

Images typically account for the largest portion of bytes downloaded on a webpage

Detailed guide

Responsive Images Implementation Guide

Responsive images are one of the most impactful performance optimizations you can implement