EN JA ZH ES

Serving Optimal Images with Content Negotiation - Accept Headers and CDN Integration

· About 9 min read

What Is Content Negotiation - Selecting Optimal Formats via HTTP

Content Negotiation is a standard HTTP protocol feature where client and server negotiate the optimal response format. For image delivery, the browser communicates supported image formats to the server, which responds with the most efficient format available.

How it works:

  • Browser sends Accept: image/avif,image/webp,image/png,image/* in request headers
  • Server parses the Accept header and checks format support in priority order
  • Returns AVIF if supported, WebP if only WebP is supported, or JPEG/PNG as fallback
  • Includes Vary: Accept header in response to ensure cache correctness

Advantages: Unlike HTML <picture> element branching, formats can be switched without changing URLs. Existing <img src="photo.jpg"> tags remain unchanged while serving WebP or AVIF to supported browsers, requiring no HTML modifications.

Browser Accept header examples:

  • Chrome 100+: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
  • Firefox 93+: image/avif,image/webp,*/*
  • Safari 16+: image/webp,image/png,image/*;q=0.8,*/*;q=0.5

Safari added WebP support in iOS 16 / macOS Ventura (2023), and AVIF support from Safari 16.4 onwards.

Server-Side Implementation - Nginx and Apache Configuration Examples

Here's how to implement content negotiation on web servers, with configuration examples for both Nginx and Apache.

Nginx configuration:

map $http_accept $img_suffix {
default "";
"~image/avif" ".avif";
"~image/webp" ".webp";
}

server {
location ~* ^(.+)\.(jpe?g|png)$ {
set $base $1;
set $ext $2;
add_header Vary Accept;
try_files $base$img_suffix.$ext $uri =404;
}
}

This configuration returns the .avif version if image/avif is in the Accept header, the .webp version if image/webp is present, and falls back to the original JPEG/PNG if the alternative file doesn't exist.

Apache configuration (.htaccess):

RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/avif
RewriteCond %{REQUEST_FILENAME}.avif -f
RewriteRule ^(.+)\.(jpe?g|png)$ $1.$2.avif [T=image/avif,L]

RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_FILENAME}.webp -f
RewriteRule ^(.+)\.(jpe?g|png)$ $1.$2.webp [T=image/webp,L]

Header append Vary Accept

Critical note: Always include the Vary: Accept header. Without it, CDNs or proxies may cache the AVIF version and serve it to browsers that only support WebP, causing display failures.

Content Negotiation at the CDN Level - CloudFront and Cloudflare Setup

When using a CDN, implementing content negotiation at the CDN level is most efficient. Performing format detection at edge servers minimizes requests to the origin.

CloudFront configuration:

  • Cache policy: Create a custom policy including the Accept header in the cache key. However, Accept header values vary slightly between browsers, potentially reducing cache hit rates
  • Lambda@Edge: Normalize the Accept header in a Viewer Request trigger, consolidating into 3 patterns: image/avif, image/webp, other. This significantly improves cache hit rates
  • CloudFront Functions: Lighter and faster than Lambda@Edge. Ideal for Accept header parsing and request URI rewriting

CloudFront Functions implementation:

function handler(event) {
var request = event.request;
var accept = request.headers.accept ? request.headers.accept.value : '';
var uri = request.uri;
if (uri.match(/\.(jpe?g|png)$/i)) {
if (accept.includes('image/avif')) {
request.uri = uri + '.avif';
} else if (accept.includes('image/webp')) {
request.uri = uri + '.webp';
}
}
return request;
}

Cloudflare setup: Enabling Cloudflare's Polish feature performs automatic WebP conversion at the edge. Pro plan and above also offers AVIF conversion. Custom logic can also be implemented via Transform Rules.

Proper Vary Header Management - Preventing Cache Accidents

The Vary header is a critical element ensuring correct caching behavior for content negotiation. Misconfiguration can cause serious incidents where wrong formats are served from cache.

Role of the Vary header: Vary: Accept tells caches that "this response varies based on the Accept header value." CDNs and proxies use this information to maintain separate cache entries for each Accept header value.

Common accident patterns:

  • No Vary: CDN caches the first request's (Chrome) AVIF response and serves AVIF to the next request (Safari) too, causing images not to display in Safari
  • Vary: *: Don't cache if any request header differs. Effectively disables caching entirely, negating CDN benefits
  • Vary: Accept-Encoding, Accept: Correct but may create too many cache variations, reducing hit rates

Accept header normalization: Since Accept header values differ slightly between browsers (presence of quality values, ordering differences), using them directly as cache keys creates separate caches for browsers supporting the same format. Normalizing Accept headers at the CDN edge to 3 values (avif, webp, default) maximizes cache hit rates.

Testing method: Use curl -H "Accept: image/webp" -I https://example.com/photo.jpg to verify response headers return Content-Type: image/webp and Vary: Accept. Make multiple requests with different Accept headers to confirm correct formats are returned.

Comparison with picture Element - Client-Side vs Server-Side Approaches

Image format switching can be done via HTML <picture> element (client-side) or content negotiation (server-side). Understanding each approach's characteristics enables appropriate selection.

picture element (client-side):

<picture>
<source srcset="photo.avif" type="image/avif">
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="Photo">
</picture>

Comparison:

  • HTML changes: picture element requires modifying all page HTML. Content negotiation needs no HTML changes
  • URL structure: picture element uses different URLs per format. Content negotiation uses a single URL
  • Cache efficiency: picture element has independent caches per format. Content negotiation manages via Vary header
  • SEO: picture element allows each URL to be independently indexed. Content negotiation manages under 1 URL
  • Debugging: picture element is easily verified in browser DevTools. Content negotiation requires header inspection

Recommended usage:

  • New projects: <picture> element recommended. Explicit and predictable behavior
  • Improving existing projects: Content negotiation recommended. Deployable without HTML changes
  • CMS / UGC: Content negotiation recommended. Cannot modify HTML for user-uploaded images

Troubleshooting and Monitoring - Production Operations

Content negotiation works transparently when configured correctly, but issues can arise from configuration errors or CDN behavior changes. Here are monitoring and troubleshooting techniques for production environments.

Common problems and solutions:

  • Images not displaying: Bug in Accept header parsing logic returning unsupported formats. Simulate each browser's Accept header with curl to verify
  • Low cache hit rate: Insufficient Accept header normalization. Check per-Vary hit rates in CDN cache statistics
  • AVIF not being served: File doesn't exist or MIME type configuration missing. Verify image/avif is registered in web server MIME types
  • File size increase: Rare cases where WebP/AVIF is larger than original JPEG. Add logic to compare sizes during conversion and use the smaller one

Monitoring implementation:

  • Aggregate Content-Type distribution from CDN access logs to track AVIF/WebP delivery ratios
  • Measure image load times by format using Real User Monitoring (RUM)
  • Automatically test correct image display across major browsers periodically (Playwright / Puppeteer)

Fallback reliability: The most critical requirement of content negotiation is reliably falling back to original images (JPEG/PNG) when no supported format is available. Always test that fallback paths remain intact when adding new formats. As an edge case, verify correct responses to requests with empty Accept headers (some bots and proxies).

Related Articles

Image CDN Setup and Optimization - High-Speed Delivery with CloudFront and Cloudflare

Learn how image CDNs work and how to configure them. Covers high-speed image delivery, dynamic resizing, format conversion, and caching strategies using CloudFront and Cloudflare.

The Future of Image Formats - How JPEG XL and WebP2 Will Transform the Web

Compare the technical features and future potential of next-gen image formats including JPEG XL, WebP2, and AVIF. Detailed analysis of compression performance, browser support, and migration strategies.

WebP to AVIF Migration Decision - Cost-Benefit Analysis and Implementation Strategy

Decision framework for migrating from WebP to AVIF. Covers additional compression gains, migration costs, and phased implementation strategies with concrete data.

Image Delivery Architecture for Large-Scale Sites - Design Patterns and Implementation

Architecture patterns for image delivery at scale. Covers CDN design, origin configuration, dynamic transformation, and caching strategies for high-traffic sites.

Complete Guide to Image Caching Strategies - Cache-Control, ETag, and CDN Configuration

Learn how to accelerate web image delivery with Cache-Control, ETag, and CDN caching. Covers cache invalidation strategies and versioning implementation patterns with practical examples.

AVIF Adoption Guide - Browser Support, Fallback Strategies, and Implementation

A practical guide to adopting AVIF format. Covers browser compatibility, picture element fallbacks, optimal encoding settings, and build pipeline integration.

Related Terms