Taming image bloat with permissions policy
Images are usually the heaviest resource on a page, both in bytes downloaded and in the visual space they occupy. Yet more than half the sites on the web still ship images that are poorly compressed or larger than they need to be. Getting image optimization right is a straightforward performance win, but knowing whether your images are actually optimized — and enforcing that across a codebase — is harder than it sounds.
A new set of experimental feature policies aims to close that gap. oversized-images, unoptimized-lossy-images, unoptimized-lossless-images, and unoptimized-lossless-images-strict are all available for origin trials, giving developers a declarative way to define what "good enough" means for images in their documents.
How the image policies behave
These policies use the Permissions Policy framework to restrict images, but with a development-friendly twist: images that violate a restriction are rendered as placeholder images, making them trivial to spot and fix during development. A report-only mode is also available, so you can observe violations via reports without changing how anything renders in production.
The policies apply to HTML image elements (<img>, <source>, and similar). Background images and generated content are not yet covered.
Restricting oversized images
The oversized-images policy places a limit on an image's intrinsic dimensions relative to its container size. When enforced, any <img> element whose intrinsic resolution is more than X times larger than its container in either dimension gets replaced with a placeholder.
This targets the common waste of serving large desktop-oriented images to mobile contexts, or sending high-pixel-density images to displays that can't use them. If you cut an image's display size in half, for example, a policy like the one below will flag it:
Permissions-Policy: oversized-images *(2);
Here, the threshold value 2 is the allowed downscaling ratio. A value of 2.0 or lower is recommended by the feature's authors. Responsive images with different resolutions per screen size remain the best way to handle varying display contexts.
The policy accepts different thresholds per origin. In Permissions-Policy: oversized-images *(inf) 'self'(1.5), the top-level site and same-origin frames are limited to a downscaling ratio of 1.5, while all other contexts are effectively unrestricted.
Enforcing file-size budgets
The unoptimized-{lossy,lossless}-images policies take a different approach: they set a byte-per-pixel budget on the actual image file. An image that exceeds the budget is replaced with a placeholder.
The threshold calculation includes a fixed overhead allowance, so small images aren't penalized for inevitable format overhead:
- lossy: file size must stay under
W × H × X + 1024bytes, with a 1KB allowance. - lossless: file size must stay under
W × H × X + 10240bytes, with a 10KB allowance. - lossless-strict: file size must stay under
W × H × X + 1024bytes, with a tighter 1KB allowance.
The rationale is straightforward: a larger file takes longer to download. Optimization means stripping metadata, choosing an efficient format, and applying compression. The policies make that work visible by measuring the outcome.
For instance, applying Permissions-Policy: unoptimized-lossy-images *(0.5) flags any lossy image that exceeds 0.5 bytes per pixel plus the 1KB overhead.
Applying the policies
All four policies can be delivered either through the Permissions-Policy HTTP header or via the allow attribute on an <iframe>. To declare one, you provide:
- The feature name (required): e.g.,
oversized-imagesorunoptimized-lossy-images. - A list of origins (optional).
- Threshold values per origin, set in parentheses (optional).
For the byte-per-pixel policies, recommended starting points are a ratio of 0.5 or lower for lossy formats, and 1 or lower for lossless formats. If you use WebP — generally the better-compressed choice — stricter thresholds are viable: around 0.2 for WebP lossy and 0.5 for WebP lossless.
A combined enforcement for all origins might look like:
Permissions-Policy: unoptimized-lossy-images *(0.5), unoptimized-lossless-images *(1)
Per-origin configurations work the same way as with oversized-images. And to test in production without breaking pages, switch the header to Permissions-Policy-Report-Only, which emits violation reports but does not swap images for placeholders.
Filing feedback
These policies are experimental and their specifics may evolve. The Chromium team is interested in knowing which thresholds prove useful in practice, and whether the two lossless variants — one with a 10KB overhead allowance and one with a 1KB allowance — feel intuitive. Feedback and comments go to [email protected].



