There is already a thread about Detecting WebP support using client-side. How to detect WebP support using server side?
-
This assumes that the first time page is loaded it will load .jpg, which kind of breaks the purpose. – Gajus Aug 10 '13 at 16:41
-
You can get it out of the `$_SERVER['HTTP_ACCEPT']`? – putvande Aug 10 '13 at 16:52
-
See this post: http://stackoverflow.com/questions/15165311/if-chrome-use-webp/17664287#17664287 – Cícero Verneck Corrêa Aug 15 '13 at 01:48
4 Answers
Today, you should check the accept
header for image/webp
. All browsers which support WebP will send this as part of their accept string for all requests (images and non-images). In short:
if( strpos( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false ) {
// webp is supported!
}
(you might want to use preg_match
instead and add word boundary checks and case insensitivity, but in the real world this should be fine)
Here's my original answer from several years ago, when the above was not reliable
The "proper" way is to check the accept
header which is sent, but a bug in Chrome means that it won't list image/webp
even though it does support it.
This is a relevant forum thread: https://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/6nYUpcSAORs
which links to this bugtracker: https://code.google.com/p/chromium/issues/detail?id=169182 which in turn links to this one: https://code.google.com/p/chromium/issues/detail?id=267212
End result? While it isn't implemented just yet, soon Google Chrome will explicitly list image/webp
as an accepted type for both image and non-image requests. So your script which serves the HTML can check for that. Opera already sends image/webp
as part of its standard accept
header (again regardless of whether it is an image request or not).
So, you could check like so:
if( strpos( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false || strpos( $_SERVER['HTTP_USER_AGENT'], ' Chrome/' ) !== false ) {
// webp is supported!
}
(you might want to use preg_match
instead and add word boundary checks and case insensitivity, but in the real world this should be fine. You might also want to check for at least version 6 of Chrome, but there's pretty much nobody running an out-of-date version so there's not a lot of point)

- 44,275
- 12
- 65
- 105
-
Does anyone know if Chrome supports this yet. The original answer was in August of last year. – Maelish Apr 16 '14 at 13:56
-
@Maelish The thread on the first bug tracker finishes with "I'm seeing the image/webp header for http requests now too" (dated Feb.), so I'd guess so. Well, simplest way to check is to try it! – Dave Apr 16 '14 at 15:15
-
-
Works good! I know it is out of scope of the question, but I would like to add that you can check for server support of WebP aswell with `gd_info()["WebP Support"]`, it returns a neat boolean. That way when you have an application that could be deployed on any server you make sure it works both ways ;-) – Ogier Schelvis Mar 20 '18 at 09:07
-
2Firefox supports WebP images since version 65 but they decided to remove image/webp from Accept header to main document since version 66. – Māris Kiseļovs Oct 04 '19 at 09:45
-
1
-
If using `flask`, something like this will do: `'image/webp' in request.headers.get('Accept')` – learn2day Jun 28 '20 at 13:43
-
3Note! Safari on a Mac running Big Sur does currently not send image/webp in the accept header. This is how the accept header looks like for me now in Safari: `Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8` – Andreas Heintze Sep 04 '21 at 05:51
Dave answer is good but not working with all browsers. I use this method:
function GetBrowserAgentName($user_agent) {
if (strpos($user_agent, 'Opera') || strpos($user_agent, 'OPR/')) return 'Opera';
elseif (strpos($user_agent, 'Edge')) return 'Edge';
elseif (strpos($user_agent, 'Chrome')) return 'Chrome';
elseif (strpos($user_agent, 'Safari')) return 'Safari';
elseif (strpos($user_agent, 'Firefox')) return 'Firefox';
elseif (strpos($user_agent, 'MSIE') || strpos($user_agent, 'Trident/7')) return 'Internet Explorer';
return 'Other';
}
So after checking browser:
$BrowserAgentName = GetBrowserAgentName($_SERVER['HTTP_USER_AGENT']);
If ($BrowserAgentName == 'Chrome' || $BrowserAgentName =='Opera') {
// webp is supported!
}
Here I just add Opera and Chrome, you can use deeper detector for browser version and add more agents to your if{}. But you need update this code as browsers update to support image/webp.

- 686
- 1
- 13
- 30
-
9You should avoid checking for features by checking the browser; this leads to brittle code which must be manually maintained (as well as being the main reason behind the current insanely complex & self-contradictory user agent headers sent by browsers). That's why I suggest checking the feature directly by looking for "image/webp" in the accept header. All browsers which support webp will list this. The only reason to have a browser check is to temporarily work around a specific, known (and ideally, reported) bug, as in my original answer. – Dave Aug 27 '16 at 07:50
Just a small thing I've noticed with Facebook - Their facebookexternalhit bot (The one that crawls your website when someone is posting an address to it) doesn't recognizes webp images yet. So i've added the following check to disable the webp images in my client's website for Facebook's bots:
if (strstr(strtolower($_SERVER["HTTP_USER_AGENT"]), "facebook"))
return false;
Otherwise, when a webpage is shared, it will display the wrong image (the first JPG it will find in the page).

- 91
- 4
In my case I was using C# Asp.Net MVC. The SO didn't specify tech so I found myself looking at this thread. For anyone else who happens to come across this looking for similar here is the solution I came up with:
bool acceptsWebP = Request.AcceptTypes.Contains("image/webp");
string ext = Path.GetExtension(image.ImagePath);
string webP = image.ImagePath.Replace(ext, ".webp");
if (acceptsWebP)
{
<img class="img-fluid lazy" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-src="\Uploads\@webP" alt="@item.ProductName">
}
else
{
<img class="img-fluid lazy" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-src="\Uploads\@image.ImagePath" alt="@item.ProductName">
}

- 1,469
- 2
- 17
- 39