Content Negotiation
Server-side selection of the best response variant based on client Accept headers. The server picks the optimal encoding (gzip, br), format (WebP, AVIF), or language based on what the client supports.
Full Explanation
Content negotiation lets a single URL serve different content based on what the client can handle. The browser sends Accept: image/avif, image/webp, image/* and the CDN returns AVIF to modern browsers, WebP to slightly older ones, and JPEG to the rest. Same URL, optimal format for each client.
The catch for CDNs is caching. If you cache the AVIF response and serve it to a browser that only supports JPEG, things break. The Vary header is the solution: Vary: Accept tells the cache to store separate versions per Accept header value. But be careful—there are hundreds of unique Accept header combinations, which can fragment your cache and tank hit ratios.
Smart CDNs normalize the Accept header into buckets (supports-avif, supports-webp, legacy) rather than caching per exact header value. This keeps cache efficiency high while still serving the right format. Cloudflare's Polish and CloudFront's content negotiation features handle this automatically.
Examples
Nginx content negotiation for images:
map $http_accept $img_suffix {
default "";
"~image/avif" ".avif";
"~image/webp" ".webp";
}
server {
location ~* ^(.+)\.(jpe?g|png)$ {
# Try AVIF/WebP version first, fall back to original
try_files $1$img_suffix $uri =404;
# Critical: tell caches this varies by Accept
add_header Vary Accept;
add_header Cache-Control "public, max-age=31536000";
}
}
Checking what format the CDN serves:
# Request with AVIF support
curl -sI -H "Accept: image/avif,image/webp,*/*" \
https://cdn.example.com/photo.jpg | grep content-type
# content-type: image/avif
# Request without modern format support
curl -sI -H "Accept: image/jpeg" \
https://cdn.example.com/photo.jpg | grep content-type
# content-type: image/jpeg
Frequently Asked Questions
Server-side selection of the best response variant based on client Accept headers. The server picks the optimal encoding (gzip, br), format (WebP, AVIF), or language based on what the client supports.
Nginx content negotiation for images:
map $http_accept $img_suffix {
default "";
"~image/avif" ".avif";
"~image/webp" ".webp";
}
server {
location ~* ^(.+)\.(jpe?g|png)$ {
# Try AVIF/WebP version first, fall back to original
try_files $1$img_suffix $uri =404;
# Critical: tell caches this varies by Accept
add_header Vary Accept;
add_header Cache-Control "public, max-age=31536000";
}
}
Checking what format the CDN serves:
# Request with AVIF support
curl -sI -H "Accept: image/avif,image/webp,*/*" \
https://cdn.example.com/photo.jpg | grep content-type
# content-type: image/avif
# Request without modern format support
curl -sI -H "Accept: image/jpeg" \
https://cdn.example.com/photo.jpg | grep content-type
# content-type: image/jpeg
Related CDN concepts include:
- Content-Encoding — An HTTP response header indicating the compression algorithm applied to the response body. Common values: …
- Vary Header — A response header that tells caches which request headers should be included in the cache …