tooldura
Image & Media

Serving WebP on Your Site: picture, Accept Headers and the Vary Trap

T
tooldura editorial
8 min readUpdated October 29, 2026Open tool →

Converting your photos to WebP is the easy half. The other half is getting each visitor the right file: WebP to every browser that can show it, which today is all of them, and still a JPG to the email client, the link preview crawler and the old app that cannot. There are two established ways to do it, one in your HTML and one on your server, and each has a failure mode worth knowing before it bites.

What the Switch Actually Buys You

Google's comparison study measured lossy WebP at 25 to 34 percent smaller than JPEG at equal visual quality. On a page whose largest element is a hero photo, that photo often decides Largest Contentful Paint, the Core Web Vital that measures when the main content appears, with 2.5 seconds as the threshold for a good score. A quarter fewer bytes on that one request shortens the time to paint it on any connection where bandwidth is the limit.

The saving is not guaranteed per file, though. A JPG that was already compressed hard has little left to give, and converting it at a high WebP quality can produce a larger file. Measure each image rather than assuming, and keep the smaller one.

Option One: the picture Element

The HTML <picture> element lets a page offer several versions of an image and lets the browser pick. Each <source> names a format with its type attribute, and the browser takes the first one it supports. The <img> inside is both the fallback and the element that actually renders, so alt, width, height and loading all go on it.

The smallest working version is a <picture> holding <source type="image/webp" srcset="photo.webp"> followed by <img src="photo.jpg" alt="Harbour at dusk" width="1600" height="900">. A browser that reads WebP fetches only photo.webp, and one that does not skips the source and fetches only the JPG.

The strength of this approach is that it is completely explicit. Each URL always returns the same bytes, so every cache between your server and the visitor behaves correctly without configuration. The cost is markup: every image needs the wrapper, and responsive images multiply it, because each <source> carries its own srcset and sizes. A browser that skips a <source> also skips its srcset, so the WebP and JPG lists have to match size for size.

Option Two: Let the Server Decide

The alternative keeps a plain <img src="photo.jpg"> and moves the decision to the server. Every image request carries an Accept header listing the formats the browser takes, and every current browser includes image/webp. The server, or more often an image CDN in front of it, checks for that string and returns the WebP version under the same URL, with Content-Type: image/webp.

This is HTTP content negotiation as RFC 9110 describes it, and it needs no change to your HTML at all, which is why image CDNs offer it as a switch. It is also why images saved from many sites arrive as WebP even when the URL ends in .jpg.

⚠️

Without Vary: Accept, a cache can serve WebP to everyone

If one URL can return two different bodies, every cache on the way has to know that the choice depends on the Accept header, or it will store whichever version it saw first and hand it to everyone. The response must include Vary: Accept. Shared caches that ignore Vary, or that refuse to cache anything carrying it, then either serve the wrong format or stop caching your images at all. Check how your CDN handles Vary before turning negotiation on, and test by fetching the same URL with and without image/webp in the Accept header.

The Two Approaches Compared

picture elementServer negotiation
Change to HTMLEvery image wrappedNone
CachingPlain, one URL per fileNeeds Vary: Accept handled correctly
Who decidesThe browser, from typeThe server, from the Accept header
Saved imageName matches formatCan be WebP under a .jpg name
Best forStatic sites, hand-built pagesSites with an image CDN

Make the WebP versions of your photos

Quality 80 by default, the size change per file, and a full-size comparison with each JPG.

Open JPG to WebP →

Where the JPG Should Stay

Browsers are not the only things that fetch your images, and the others are less forgiving.

1

Open Graph and social previews

The og:image a platform fetches for a link card is read by that platform's crawler, not by a browser. Support for WebP there has historically been uneven, and a missing preview image is costly. A JPG or PNG is the safe choice for og:image and twitter:image.

2

Email

Email clients render HTML with their own engines, and several do not display WebP. Images in newsletters and transactional email should stay JPG or PNG.

3

Downloads people will open elsewhere

A photo offered for download, a press kit or a print-ready file goes into whatever software the visitor has. Offer the JPG there, even if the page itself displays WebP.

4

Your originals

Keep the source JPGs. Converting is a lossy step, and a future format such as AVIF should be made from the original rather than from the WebP, so the losses do not stack.

A Sensible Setup for Most Sites

Convert from the highest-quality original you have, at around quality 80, and compare a few representative photos at full size before converting the whole library. Skin, skies and fine texture such as foliage are where lossy WebP shows first, as slight smoothing rather than blocks.

Resize before converting. Format changes save a quarter to a third, while serving a 4000-pixel photo into an 800-pixel column wastes far more than that. Generate the widths your layout needs, convert each, and list them in srcset.

Then pick one delivery method. If an image CDN already sits in front of your site, negotiation with a correctly handled Vary: Accept is the least work. If the site is static or hand-built, <picture> is predictable and needs nothing from the server. Mixing both on the same images only adds a way for them to disagree.

Frequently Asked Questions

Found this guide useful? Pass it on.

Related Tools

Keep Reading