Here’s is a recurring topic at both Cloudflare’s Community forum and WordPress.org Support forums: How can I serve WebP images on a Cloudflare Free plan without breaking my website for some visitors?

You want to serve the new-new image optimization format called WebP, which squeezes some bytes out of your pretty JPEG and PNG images, to speed up the loading of your website. But since you are on a Cloudflare Free Plan, things don’t go as planned. As soon as you enable WebP optimization in your preferred optimization plugin, users start complaining that images have gone amiss. These users are using non-WebP compatible browsers, such as such as Safari for iPad or iPhone, Safari for MacOS, or good, old Internet Explorer.

Summary

Cloudflare Polish or Workers

If you are on a Cloudflare paid plan, such as Pro or Business, you can use Cloudflare’s Polish feature that converts images to WebP format on the fly. Polish will serve WebP images only to browsers that are compatible with the new format.

Also, you can also use Cloudflare’s Workers, a paid service that starts a lot cheaper than the Pro Plan, to smartly deliver WebP images. All you need to do is enable Workers, and grab one of the recipes that make the magic happen.

But if you’re on a dime and must behave within the limits of the Free Plan, and want to serve WebP images out of your origin server, Cloudflare will not test if or not your visitor’s web browser can handle the format. In case they can’t, your visitors will see a few blank spaces where WebP images were supposed to be in the page. Not good!

Non-Compatible Browsers

Not all browsers are compatible with WebP, most notably Apple Safari and Microsoft Internet Explorer. You can check the current compatibility by visiting https://caniuse.com/#search=webp.

Apple has recently announced that its Safari browser for MacOS and iOS will finally be WebP compatible starting with iOS 14 and MacOS 11. And once they become compatible, so will other browsers for iOS, such as Firefox and Chrome. (Currently, they are for all practical purposes only shells to Safari.) But it may take a while until Apple’s announcement becomes a reality. And even after it does many older Mac devices’s browsers may still not be compatible.

Which brings us back to our central topic: How to serve WebP images at your origin while on a Cloudflare Free Plan.

Cloudflare Free Plan

When your site is on Cloudflare, visitors’s browsers will send a request that first reaches one of Cloudflare’s over 200 datacenters. Without any further instruction coming from your origin, Cloudflare will serve whatever images are requested by the HTML of your pages to any visitor. If the first visitor has a WebP-compatible browser, the origin server may send an HTML that requests WebP images, sometimes under a JPG filename, which are then cached by Cloudflare and served to subsequent visitors. Visitors with non-WebP-compatible browsers will fetch the HTML with the image URLs pointing to WebP files, not JPG ones.

To be sure, Cloudflare does not bar you from serving WebP to compatible browsers. It just won’t do the work for you in terms of verifying that a browser is compatible and rewriting the URLs accordingly.

You need to code at your origin to let Cloudflare know how and when to resize each image. Similarly, if you intend to serve images in the WebP format, you need to develop a solution, pay someone to do it for you, or count on a plugin with a solution for the problem.

To show how you can serve images on the WebP format while on a Cloudflare Free Plan, we present here two solutions, one for HTML sites that illustrates on a proof-of-concept basis how it can be done, and another for WordPress sites with a suggested plugin.

How-to Examples

For the purposes of the HTML examples given here, you need to keep both JPG and WebP files at the origin, so that Cloudflare caches both, one for WebP-enabled devices, the other for non-compatible devices.

Then you’d need to count on an inline JavaScript on the HTML that will replace URLs in IMG tags with another URL for those browsers that can’t handle WebP. The HTML examples below are simple implementations of this idea. If you are interested in learning about a more robust solution, Google developers suggest a few ways of testing WebP compatibility, which involves adding minuscule base64-encoded WebP images to the HTML/JavaScript.

HTML Site

JavaScript Rewriting

The example below was tested on an HTML site as a proof-of-concept page, with just one image. The inline JavaScript simply checks for the user agent to see if the request comes from either an Internet Explorer or an iOS browser, and replaces the URL of the image tags based on that:

<html>
<head>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>HTML WebP Test Page</title>
	<link rel="icon" href="/favicon.ico" type="image/x-icon">
</head>
<body>
<h1>Code is WebPoetry</h1>
<img id="myImage" src="img/webp-test.webp">
<script>
if( navigator.userAgent.match(/MSIE|Trident|iPhone|iPad|iPod|FiOS|CriOS/i) )
	{ 
	var newsrc;
	newsrc=document.getElementById("myImage").src.replace(".webp", ".jpg");
	document.getElementById("myImage").src=newsrc;
	}
</script>
</body>
</html>

You can check see how the above HTML works here at oba!press:

https://obapress.com/html/webp-test.html

The HTML and JavaScript assume there are two files with identical paths, but different file type suffixes (.jpg and .webp) at your website origin server. The JavaScript goes inside the HTML, and it should work whether or not Cloudflare caches the HTML under a “cache everything” page rule.

There would be a negligible performance downgrade for all HTML pages, but a slight performance impact on browsers with user agents that match the JavaScript if condition, that is, the non-WebP-compatible browsers.

You could then iterate the replace the action for the IMG tags, as well as other tags, and make other appropriate adjustments. Code well, don’t be a bum like me!

<html>
<head>
  <title>HTML WebP Test Page 2</title>
</head>
<body>
<h1>Code is WebPoetry</h1>
  <p>Test image 1</p>
    <img src="img/test-img-1.webp">
  <p>Test image 2</p>
    <img src="img/test-img-2.webp">
  <p>Test image 3</p>
    <img src="img/test-img-3.webp">
<script>
// check for non-compatible browsers. Edit as needed
if( navigator.userAgent.match(/Trident|iPhone|iPad|iPod/i) )
	{ 
	// then replace .webp images with jpg
	var allImages = document.body.getElementsByTagName("img");
	var length = allImages.length;
	var i;
	for(i = 0; i < length; i++){
	  allImages[i].src = allImages[i].src.replace(".webp", ".jpg");
	  console.log(allImages[i]);
	}
}
</script>
</body>
</html>

You can check an implementation of the above HTML here at oba!press:

https://obapress.com/html/webp-test-2.html

The <picture> HTML5 Element

Another approach is to use the <picture> element and its <source> attribute. It lists images in more than one format, but the browser will request only the images it can render. I quote here from html5rocks.com:

Load alternative image file formats

The type attribute of <source> can be used to load alternative image file formats that might not be supported in all browsers. For example, you can serve an image in WebP format to browsers that support it, while falling back to a JPEG on other browsers:

<picture>
  <source type="image/webp" srcset="images/butterfly.webp">
  <img src="images/butterfly.jpg" alt="a butterfly">
</picture>

WordPress Example

Things get a bit more complex when you think about a WordPress site. For one thing, you don’t have control of where image requests will show up on your page’s HTML. Elementor, for instance, a highly popular WYSIWYG page builder, places many image requests inside CSS files, making the replacement model proposed above non-realistic. It would involve waiting for some CSS file to be fetched before any replacement could be performed.

So adding a homemade JavaScript to your pages, though possible for some, won’t be enough for most of us.

Thankfully there are already solutions available in the WordPress plugin repository, including some created by image optimization plugins, that will add a more complete and robust JavaScript WebP compatibility test to your pages. We will talk about one such solution, but you should search the WordPress plugin repository for similar solutions if what’s presented below somehow doesn’t work on your site.

EWWW Image Optimizer

Ewww Image Optmizer is a freemium plugin for WordPress that has a “JS Rewriting” option. When properly configured, it inserts a JavaScript code along with a tiny (around 80 bytes) and invisible WebP test image into the HTML of every page. The JavaScript then uses the image to test whether the browser is capable of handling WebP images, and changes the URLs in each image request accordingly.

EWWW Image Optimizer also offers a <picture> rewriting option, but it comes with a caveat:

<picture> WebP Rewriting  A JavaScript-free rewriting method using picture tags. Use this if Apache rewrite rules do not work for your site. Some themes may not display <picture> tags properly, and does not support CSS background images.

For the JavaScript rewriting solution to work, you need to:

  1. Install and activate Ewww Image Optimizer plugin
  2. Follow its instructions to obtain and activate an Optimization API Key. The first 300 images are free.
  3. At the WebP tab, checkmark WebP Conversion and JS WebP Rewriting
  4. At the Easy Mode tab, checkmark Lazy Load

Also, make sure you use the plugin’s “Bulk Optimize” action in your Media Library to optimize and convert to WebP any images that were there before you installed the plugin.

Important! Keep in mind that other website optimization plugins like Autoptimize and Clearfy have optional settings that may remove the inline JavaScript and combine it into an external file, something that would defeat the purpose of testing WebP-compatibility on the fly. Make sure you turn these settings off.

Performance Considerations

With the solution given here, the flow of events will be something like this:

  • Visitor’s browser requests a page on your website;
  • Your origin (or Cloudflare cache) returns the HTML page containing an inline JavaScript code that tests the browser’s compatibility with WebP images;
  • The HTML at the browser requests the images on the page. The inline JavaScript rewrites the URLs of image requests for browsers that are not WebP compatible, so that they request instead images in their original format (JPG, PNG, GIF, etc);
  • As visitors come in, Cloudflare will cache both the WebP and the original version of your images, and send them as requested to the browsers that can handle them.

I’ve tested this solution in two WordPress installations, one of them using Elementor with some background images inserted by CSS, and it worked fine in both of them. The speed impact was significant and it made me earn many PageSpeed brownie points, yay!

Test, test, test. Then test again!

It’s important to understand that every WordPress website is a unique collection of theme plus plugins, addon plugins, customized functions added to the functions.php file etc. For that reason, only testing can help you assess the real benefit of converting images to the WebP format. And the testing of course has to be done by you on your website.

Consider for example two different websites: One is a real estate site with many images in each of its listing pages. The other is an informational, non-profit website with lots of images on the homepage, and a lot of text in most other pages.

For the real estate website, the “cost” of adding an inline JavaScript block and a tiny, base64-encoded WebP image in each of its pages is small given the potential benefit of reducing the size of its pages with many images. For the small non-profit site, its mostly-text pages perhaps will become unnecessarily heavier by the addition of the JS and WebP test image, while the benefit may be limited to the home page.

Each site is like a caterpillar in terms of optimization. There are way too many variables to discuss here. Only site owners can decide whether the performance impact of having the extra JavaScript code is worth the while, by A/B testing it.

Comments

Please send any comments as replies to the tweet below. Click on the date of the tweet to open it on Twitter.

By cbrandt