Client Hints and Resource Hints is considered a best practice to achieve great performance on your website.
When enabled, client hints are used to resize images and determine the appropriate compression without compromising the visual quality of the image.
Resource Hints, will prepare the connection to your ImageEngine delivery address so that it is ready when the first image requests are being made, resulting in faster display of the images.
Not all browsers support client hints and resource hints, but the market share with support is significant enough to unlock the additional speed improvements for the segment.
In this article we'll have a look at how to enable client hints and resource hints in a few different CDNs, CMSs and servers. But first, a quick explanation of how these hints work.
How Do Client Hints and Resource Hints Work?
Put simply, these hints are additional information sent by the browser which the server - or image CDN - can use to tailor and optimize the response - or image. This is sometimes referred to as content negotiation. There is some plumbing involved to for the information to reach the image CDN, though:
First, the web page has to tell the browser that it would like to receive client hints. This is done with the accept-ch
response header. This header lists the hints the server wants. the accept-ch
header can be implemented as a HTML element or as a HTTP header. In the following we'll focus on implementation as HTTP headers, because delegating the hints to 3rd parties using HTML is not supported for security and privacy reasons.
Along with the accept-ch
header, the web page also informs the browser that the hints should also be shared - or delegated - to a specified 3rd party host. In our case, ImageEngine. This is done with the permissions-policy
header which specify each hint and which host(s) that should also receive them.
Next, the preconnect
hint is telling the browser to connect to the specified host as soon as possible so that the connection is ready to use. Preconnect
can also be implemented as a HTML element using the <link>
element.
Now, that the browser has received all this information, it will request assets from the server specified in the preconnect
hint and permissions-policy
with the appropriate hints.
With all this in place, ImageEngine is able to produce a pixel perfect image with great visual quality and the lowest possible byte size.
Responsive Images and Client Hints
It's worth noting that there is a relation between "responsive images syntax" and client hints. Especially the sec-ch-width
hint that holds information about the required pixel size of the image so that it fits perfectly onto the responsive page, regardless of the size of the browser window.
In order for the browser to be able to compute the required width of an image in a responsive page, it has to know the intrinsic size of it, before it's rendered to the screen. This is achieved by the sizes
attribute.
Hence, to make use of the sec-ch-width
client hint, always set sizes
on the <img>
elements. Combining client hints, responsive images and ImageEngine will significantly reduce complexity of the markup, be easier to maintain, and serve faster and better adapted images.
Note that ImageEngine will not always return the exact pixel size as requested. ImageEngine may resize images in "buckets" or steps of 100px each by rounding the size up to the closest 100.
WordPress - Image CDN plugin
It is highly recommended to use the ImageEngine plugin if you're using WordPress.
This plugin will set all the required headers to enable both resource hints and client hints properly.
You can also set the required headers by adding this snippet to your functions.php
file (swapping example.com
with your delivery address):
function add_ie_headers($headers) { $headers['accept-ch'] = 'sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect'; $headers['permissions-policy'] = 'ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")'; $headers['link'] = ' <https://example.com/>; rel=preconnect'; return $headers; } add_filter('wp_headers', add_ie_headers);
Magento ImageEngine Plugin
The official ImageEngine Magento plugin has client hints and resource hints support built in.
Once the plugin is installed and enabled on your Magento site, ImageEngine will automatically receive the hints.
Netlify Custom Headers
Netlify is a popular Jamstack hosting service and CDN for static sites built with common front-end frameworks or site builders like React, NextJS, Vue, Nuxt, Gatsby and more.
Even if Netlify only supports static sites with no access to server-side code, it's pretty straight forward to add custom headers to enable client hints and resource hints.
Netlify offers two options:
- Adding headers in a dedicated
_headers
file located in the publish directory of your site. - Add one or more headers tables to your Netlify configuration file (
netlify.toml
)
The latter is the recommended approach as it allows for more structured configuration and additional capabilities. Here is a snippet to add to your netlify.toml
file to enable resource hints and client hints (swap example.com
with your ImageEngine delivery address):
[[headers]] for = "/*" [headers.values] accept-ch = "sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect" link = "<https://example.com/>; rel=preconnect" permissions-policy = ''' ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")'''
Vercel Custom Headers
Similar to Netlify, Vercel is also a popular Jamstack service for static sites. The most generic way to control response headers in Vercel is to add the headers to the vercel.json
configuration file (swap example.com
with your ImageEngine delivery address):
{ "headers": [ { "source": "/(.*)", "headers" : [ { "key" : "accept-ch", "value" : "sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect" }, { "key" : "permissions-policy", "value" : "ch-viewport-width=('https://example.com'), ch-width=('https://example.com'), ch-dpr=('https://example.com'), ect=('https://example.com')" }, { "key" : "link", "value" : "<https://example.com/>; rel=preconnect" } ] } ] }
Cloudflare Pages and Workers
Cloudflare Pages, yet another Jamstack static site host, offers similar file-based control mechanism for HTTP response headers. Simply create a _headers
plain text file in the output folder of your project with this content:
/* accept-ch: sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect
link: <https://example.com/>;
rel=preconnect permissions-policy: ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")
A more powerful option is to use serverless functions with Cloudflare Workers. You can easily combine this with rewriting your image references to reference ImageEngine using workers. Here's a sample function which sets the proper response headers to enable both client hints and resource hints for ImageEngine:
addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { // This proxies your Pages application under the condition that your Worker script is deployed on the same custom domain as your Pages project const response = await fetch(request); // Clone the response so that it is no longer immutable const newResponse = new Response(response.body, response); newResponse.headers.set('accept-ch', 'sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect'); newResponse.headers.set('link', '<https://example.com/>; rel=preconnect'); newResponse.headers.set('permissions-policy', 'ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")'); return newResponse; }
Stackpath EdgeRules
With Stackpath custom response headers can be added by creating "Custom CDN EdgeRules" in the admin UI.
Make sure that the URL matching condition matches the requests that you want to respond with hints.
In the "Then" section, choose "Add Response Header" for each of the required headers and values:
accept-ch: sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect
link: <https://example.com/>; rel=preconnect
permissions-policy: ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")
Save the rule.
Fastly
Fastly offers an admin UI to manage response headers. Follow the guide to create new headers and repeat the action for each of the required headers.
The "Type/Action" setting must be "Response".
The "Destination" is the header name prefixed by "http.
".
The "Source" is the value of the header as listed below:
http.accept-ch: sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect
http.link: <https://example.com/>; rel=preconnect
http.permissions-policy: ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")
Cloudfront Response Headers Policies
For Amazon Cloudfront you'll have to create policies to manage the headers and connect them to a distribution.
Follow the instructions here and add the required headers and values:
accept-ch: sec-ch-viewport-width, sec-ch-width, sec-ch-dpr
link: <https://example.com/>; rel=preconnect
permissions-policy: ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com")
Next, following the instructions, attach a response headers policy to a distribution.
-
Open the Distributions page in the CloudFront console at https://console.aws.amazon.com/cloudfront/v3/home#/distributions.
-
Choose the distribution to update, then choose the Behaviors tab.
-
Select the cache behavior to update, then choose Edit.
Or, to create a new cache behavior, choose Create behavior.
-
For Response headers policy, choose the policy to add to the cache behavior.
-
Choose Save changes to update the cache behavior.
Drupal Modules to Enable Hints
For Drupal there are several modules in the directory that may help if your Drupal site isn't running on Apache or you're not able to edit the php code.
The CDN module will help you implement ImageEngine as well as setting the proper resource hints.
The HTTP Response Headers module will also enable you to manage other headers to enable client- and resource hints.
Apache .htaccess
Many hosting companies uses Apache. Most likely you'll have access to edit a file called .htaccess
wither through a web UI or directly on the server. .htaccess
is the configuration file of the Apache webserver. To configure Apache to opt in for- and delegate client hints, put the following snippet in .htaccess
replacing example.com
with your real hostname:
<IfModule mod_headers.c> Header set link '<https://example.com/>; rel=preconnect' Header set permissions-policy 'ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")' Header set accept-ch 'sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect' </IfModule>
NodeJS and ExpressJS
ExpressJS is a popular framework for NodeJS. Response headers are easily set with response.set()
in the example below:
const express = require("express"); const app = express(); app.use(express.static("public")); app.get("/", function(request, response) { response.set({ "accept-ch": 'sec-ch-viewport-width, sec-ch-width, sec-ch-dpr, ect' }); response.set({ "permissions-policy": 'ch-viewport-width=("https://example.com"), ch-width=("https://example.com"), ch-dpr=("https://example.com"), ect=("https://example.com")' }); response.set({ "link": '<https://example.com/>; rel=preconnect' }); response.send('<html><body><h1>Hello World</h1></body></html>'); });
Enable Client Hints with markup
Using HTTP headers to enable Client Hints support is recommended. However, it is also possible to opt-in and delegate using a <meta>
html tag inside <head>
.
<meta http-equiv="delegate-ch"
content="sec-ch-dpr https://example.com;
content="ch-viewport-width https://example.com;
content="ch-width https://example.com;
content="ect https://example.com;">
Similarly, preconnecting to the ImageEngine delivery address can be done using a <link>
element inside <head>
:
<link rel="preconnect" href="https://example.com" />
More Hints
By now your website should be requesting the browser to make use of client hints and resource hints.
User-Agent Client Hints
The observant reader may have noticed that User-Agent Client Hints (UA-CH) are not mentioned. (UA-CH) is an extension of client hints that moves information from the User-Agent header to dedicated client hints in an effort to deprecate the User-Agent header.
ImageEngine does not require UA-CH headers to be set. The other client hints like sec-ch-width
and sec-ch-dpr
and sec-ch-viewport-width
are more important in the image optimization process.
However, while fiddling with custom response headers already, it is recommended to also make use of UA-CH. Here is a good resource explaining how to implement User-Agent client hints.
Even if UA-CH is not strictly required by ImageEngine, it's good practice to make use of the functionality offered by the browsers. ImageEngine does rely on UA-CH in cases where other client hints are not available, and the built-in device detection is providing the input to the optimization algorithm. However, if UA-CH headers are set, but not the client hints covered above, you already know how to enable client hints in your tech stack.
Comments
0 comments
Please sign in to leave a comment.