Web Performance Calendar

The speed geek's favorite time of year
2022 Edition
Amier Saleh photo

Amier Saleh, a Web Developer: Fixing bugs, writing new ones.

The Document-Policy response header, which you may know from the JS Self Profiling API, has experimental policies to enforce performance good practices. This is useful in your local development and eventually in production. The process for In-Browser Performance Linting was first described by Tim using Document-Policy’s predecessor, Feature-Policy. An academic paper on Document-Policy and mobile performance shows that violations covered by the available policies like poor font loading and unoptimized images are common in the top Alexa sites and interventions benefit mobile performance. I’ll go over the available performance policies, review the steps to get them working in a local setup and finally discuss how to use Report-Only mode in conjunction with the Reporting API to monitor production.


There are 10 performance related policy configurations that use the new structured headers syntax. The first six are boolean configurations that when set to false (?0) block features that have a negative effect on performance. The rest, Oversized Images and the three configurations related to image compression, are decimal configurations and block features beyond the specified threshold. As of this writing, the linked documentation isn’t up to date but still informative and provides good test cases.

Font Display Late Swap

All font-display css properties will be set to optional (except fallback) to prevent layout shift and late text rendering.


Layout Animations

Only allow css properties that can be GPU animated (opacity, transform, filter) so animations are performant.


Document Write

Prevents the use of document.write and related apis so that the JS parser isn’t blocked.


Sync Script

Prevents the use of inline scripts and external scripts without async/defer attribute so the JS parser isn’t blocked. Stoyan’s data uri hack and module hack for inline scripts would get around this.


Sync XHR

Prevents the use of synchronous XHR so the main thread isn’t blocked


Unsized Media

Sets default dimensions for media that doesn’t have dimensions explicitly set to prevent layout shift


Oversized Media

Blocks images whose dimensions exceed the specified allowed multiple of their container size so that images that are physically too large aren’t used.


Lossless Images Max BPP, Lossless Images Strict Max BPP, Lossy Images Max BPP

Prevents the use of poorly compressed (beyond the specified ratio) images. BPP (Bytes Per Pixel) is the ratio of file size over rendering area. The name of the policy configuration indicates which type of image it applies to. Each configuration allows a different amount of leeway in the file size. The formulas are as follows:

For lossless images, (image size – 10KB) / image resolution

For lossless images in strict mode, (image size – 1KB) / image resolution

For lossy images, (image size – 1KB) / image resolution

lossless-images-max-bpp=0.5, lossless-images-strict-max-bpp=0.5, lossy-images-max-bpp=0.5

Local Setup

  1. Enable the Experimental Web Platform features flag
  2. Use a plugin like modheaders to add the response header in the browser
Document-Policy: font-display-late-swap=?0, layout-animations=?0, document-write=?0, sync-script=?0, sync-xhr=?0, unsized-media=?0, oversized-images=1.0, lossless-images-max-bpp=0.5, lossless-images-strict-max-bpp=0.5, lossy-images-max-bpp=0.5

You can adjust the header value to include the policies you care about and enforce thresholds appropriate to your use case.

Policy violations can be seen in the devtools console.

[Violation] Document policy violation: Synchronous script execution is disabled by Document Policy, unsized-media is not allowed in this document, oversized-images is not allowed in this document

The ReportingObserver javascript api continues to work as Tim described with the only change being the types filter is now ‘document-policy-violation’.

Production Reporting

In Report-Only mode Document-Policy will not block anything so it can safely be used in production. Enforcing the policies in production may be too aggressive and may cause breakage. In the case of image related policies, the image needs to be downloaded to evaluate whether it violates a policy and gets replaced by a placeholder so the user has already paid some of the performance penalty without getting any of the benefit. Report-Only mode is the safest approach but you can use the header in enforce mode if it suits your use case like Rohan has done in his endeavour to have an inclusive textual website. Using Document-Policy-Report-Only with the Reporting API has the following benefits:

  • Adding a response header is straightforward and no js or libraries are required.
  • We don’t need to worry about beaconing because the browser will batch violation reports and send them in a background process.
  • Chrome provides tooling to view the reports to ensure things are working correctly.
  • Reports have a similar format to other reports you may already be collecting like csp and nel reports.

The steps involved are:

  1. Add a Reporting-Endpoints response header

Reporting-Endpoints: endpoint1=”https://reports.example/perf”

  1. Use Document-Policy-Report-Only
  2. Append the default policy configuration and set report-to to point at your reporting endpoint
Document-Policy-Report-Only: font-display-late-swap=?0, layout-animations=?0, document-write=?0, sync-script=?0, sync-xhr=?0, unsized-media=?0, oversized-images=1.0, lossless-images-max-bpp=0.5, lossless-images-strict-max-bpp=0.5, lossy-images-max-bpp=0.5, *;report-to=endpoint1

devtools Application panel Reporting Api view

The Document-Policy performance related policies are already useful in development. I look forward to them becoming standardised soon so we can also reap the benefits in production.