Client Hints and Feature Policies

Many moving parts related to Client Hints were enabled by default in Chrome version 84. Starting in this version, access to Client Hints can be delegated to 3rd parties. 🎉

Client Hints

Client Hints has been here for a while – since Chrome 35 in 2015, actually. However, support in most Chrome browsers got pulled due to privacy concerns in version 67. In short, there was concerns about that Client Hints could be used to fingerprint end users. As a result, access to Client Hints were limited to certain Chrome versions on Android and 1st party origins in other Chrome versions.

Still, specification work continued, and much of the Client Hints are moved into the Network Information API. Here is the list of client hints (not related to the user-agent hints, which I’ll cover in a later post):

  • Device-memory
  • Downlink
  • Ect
  • Rtt
  • Save-data
  • Width
  • Viewport-Width
  • DPR

Until recently, requests to sub resources at the origin will receive the above hints, provided that the site opts in:

Accept-CH: viewport-width, width, device-memory, dpr, rtt, downlink, ect

So far so good. If the server response for the web page contains this response header, the subsequent request ot the same origin, for images for example, the client hints will be added to the requests for resources.

Here is a glitch demoing the basic infrastructure:

For the glitch examples; make sure to test them using Chrome version 84 or higher.

Hint: look at the request headers of the image on the page above.

Client Hints to 3rd parties and sub-domains

When the full support for Client Hints was pulled in Chrome 67, the intention was to reintroduce it when Feature Policies could add a layer of security to it. With Chrome version 84, we’re finally there.

From Chrome version 84 onwards, resources located on 3rd party domains and sub domains is also able to receive Client Hints. This is good news of CDNS, in particular image optimization CDNs

Here’s now to delegate Client Hints to 3rd parties:

Feature Policies

At the time of writing, the mechanism for delegating Client Hints to 3rd parties is named Feature Policies. However, it’s about to be renamed to Permission Policies.

A Feature / Permission policy is a HTTP header specifying which origins (domains) have access to which browser features.

In the following example, I’ve specified this policy:

Feature-Policy: ch-viewport-width https://example.com;ch-width https://example.com;ch-dpr https://example.com;ch-device-memory https://example.com;ch-rtt https://example.com;ch-ect https://example.com;ch-downlink https://example.com

This policy grants resources located on https://example.com access to the specified hints.

Pitfall 1) Note the ch- prefix. The notation is ch- + client-hint name

Pitfall 2) Use lowercase! Even if docs and examples say for example Accept-CH: DPR, make sure to use ch-dpr in the your policy header! 

In the glicth above, client hints are now delegated to https://example.com/ and the image request for https://example.com/test.jpg receives the specified hints.

Note that the 3rd party being delegated to, doesn’t have to opt in or announce which hints it will respond to. All resources on example.com will receive the delegated hints. But only image requests will get the width hint. Moreover, it seems like viewport-width will have a default value for non-image requests.

Here are some captures from dev tools to demostrate:

Browser is requesting https://holly-imaginary-emoji.glitch.me/ and gets this response:

client hints permission feature policy headers. opt in
Note the accept-ch, and feature-policy response headers

The browser is rendering the response, acknowledging the feature headers, and finally seing the request for https://example.com/test.jpg. Then the browser knows that for this origin (https://example.com) the client hints specified in the accept-ch header should be a part of the request for https://example.com/test.jpg:

client hints request headers
The request to https://example.com/test.jpg contains client hints

Conclusion

It wasn’t obvious to me how this would end up being implemented in Chrome. Docs, specs and examples explains it differently. Then there is case sensitivity, prefixing and policy renaming. All moving targets right now. However, in Chrome v84 it’s being implemented like described here, so chances are good that this is how it will end up in the wild.

Comments are closed.