# mod_pagespeed 2.1 > Self-hosted web performance optimization for Apache and nginx. Open source under the Apache License 2.0. mod_pagespeed 2.1 converges the mod_pagespeed lineage and the engine from the 2.0 re-architecture into one product: a native web-server module with a separate optimizer worker. We-Amp B.V. develops mod_pagespeed 2.1, the converged continuation of the open-source mod_pagespeed project, originally developed at Google. It automatically optimizes web content (images, CSS, JavaScript, HTML): a native in-process module for Apache and nginx handles serving, and a separate optimizer worker does the heavy optimization work outside the web server. Drop-in compatible with the classic module: the same configuration directives and filters carry over, and no application code changes are required. mod_pagespeed 2.1 converges the 1.15 module line (renumbered from 1.1, the forward-semver successor to the last upstream release, 1.14.36.1) with the ModPageSpeed 2.0 engine, which continues as the optimizer worker; both predecessor lines upgrade to it in place. Heritage: mod_pagespeed, the open-source optimization core this product continues, powers 231,341 live sites (per BuiltWith, May 2026; 1.9 million+ across its history). These are not We-Amp customers; they are the proof the optimization core works at scale. What it does: - Image optimization in the optimizer worker: WebP, AVIF and SVG transcoding, viewport-aware resizing, learned per-format quality prediction with SSIMULACRA2 verification, content-aware classification and denoising, up to 37 variants per image (36 raster plus one SVG) - CSS optimization: minification, heuristic critical-CSS extraction with an optional headless-browser pipeline, non-blocking stylesheet loading - JavaScript optimization: safe minification and browser-analysis-driven script deferral, no AST transforms - HTML optimization: critical CSS injection, 103 Early Hints, lazy-loading attributes, image dimensions, LCP image preload, font preloading, preconnect hints - Variant-aware caching keyed on a 32-bit capability mask (image format, viewport, pixel density, Save-Data, transfer encoding), served zero-copy from the shared Cyclone cache - The module's classic filter set: CSS and JavaScript combining, image spriting, in-place resource optimization, domain mapping, and the built-in admin console mod_pagespeed 2.1 is open source under the Apache License 2.0: free to install and run, in development and in production, with free standard signed packages. What We-Amp sells is support, in three tiers; Priority and Enterprise add a private package repository (being set up): - Standard support — a direct channel to the engineers who build the product, for up to 5 production servers; €490 a year; First response within 2 business days - Priority support — everything in Standard plus a private package repository (being set up), for up to 25 production servers; €1,900 a year; First response next business day; severity 1 (production down) within 8 business hours - Enterprise — everything in Priority plus a named engineer, custom build targets and backports, for unlimited servers and sites in one organization; from €7,500 a year; Severity 1 (production down) within 4 business hours; other severities per agreement - Prices are per year, billed annually, excl. VAT. The price you sign at holds for one year. Existing customers keep their current rate; nobody is repriced mid-term. Response targets are first-response times. Support runs on CET business days, and business hours are CET. - Standard and Priority are bought at checkout; Enterprise runs on a master agreement. A fixed-price agent-readiness audit is also available: one site, one written report, one review call, €950 per site excl. VAT. - No bandwidth fees, no per-request charges, no feature gates; the software itself costs nothing. Support terms: https://we-amp.com/licensing/ Every documentation page and every filter reference page below is also served as Markdown at its URL with a `.md` suffix (for example https://modpagespeed.com/docs/getting-started.md and https://modpagespeed.com/docs/filters/rewrite_images.md; the filters table is https://modpagespeed.com/docs/filters.md), and https://modpagespeed.com/llms-full.txt carries this index followed by the full text of every one of those pages. Every blog post is served as Markdown the same way (https://modpagespeed.com/blog/.md) and is listed in the Blog section below, but its text is not in llms-full.txt: the posts are dated commentary, so fetch one when you need it. We-Amp B.V., The Netherlands (founded 2012, KvK 57898138); info@we-amp.com for support, partnerships and consulting; security@modpagespeed.com for vulnerability reports only. License: Apache License 2.0; the LICENSE, NOTICE and THIRD-PARTY-NOTICES files ship with every distribution. mod_pagespeed is an open-source project originally developed at Google. mod_pagespeed 2.1 is developed by We-Amp B.V. and is not affiliated with or endorsed by Google. ## Start here - [Getting started](https://modpagespeed.com/docs/getting-started/): Pick an integration and get mod_pagespeed 2.1 serving optimized pages: Apache or nginx module, Docker, IIS or ASP.NET Core, then run the same check. - [Is it working?](https://modpagespeed.com/docs/is-it-working/): Confirm mod_pagespeed 2.1 is active: the response header per server, MISS then HIT, ?PageSpeed=off, the admin console and the worker health endpoint. ## Install - [Install the module on Apache and nginx](https://modpagespeed.com/docs/installation-module/): Install the native mod_pagespeed 2.1 module for Apache and nginx from the signed package repository: distributions, nginx compatibility, worker pairing. - [Install with Docker](https://modpagespeed.com/docs/installation-docker/): Run mod_pagespeed 2.1 with Docker Compose: the nginx module, the worker and a shared Cyclone cache. A one-container quick try, then a production stack. - [Deploy with Helm](https://modpagespeed.com/docs/helm-deployment/): Install mod_pagespeed 2.1 on Kubernetes with the official Helm chart: a two-container pod (module + optimizer worker), values, autoscaling and upgrades. - [cPanel / EasyApache 4](https://modpagespeed.com/docs/cpanel/): Install, uninstall and maintain mod_pagespeed on cPanel / EasyApache 4: the signed EA4 RPM, WHM setup, the cpanel/elevate runbook and ea-apache24 updates. - [Install on IIS](https://modpagespeed.com/docs/install-iis/): Install the mod_pagespeed IIS module on Windows Server: requirements, the signed MSI, IIS Express, the optional optimizer service and the first check. - [Envoy HTTP filter (experimental)](https://modpagespeed.com/docs/install-envoy/): PageSpeed for Envoy is an experimental HTTP filter built from the public source repository, not a packaged release: configuration, checks, known limits. - [Install ASP.NET Core middleware](https://modpagespeed.com/docs/aspnet-getting-started/): Install the mod_pagespeed 2.1 ASP.NET Core middleware via NuGet — the same optimization pipeline (image transcoding, critical CSS) inside your .NET app. - [Install with a coding agent](https://modpagespeed.com/docs/agent-install/): Machine-readable install recipes for coding agents, one per server: prerequisites, install, configure, verify and roll back, plus an install skill. ## Upgrade and migrate - [Migrate from ModPageSpeed 2.0](https://modpagespeed.com/docs/migrating-to-2-1/): Move a ModPageSpeed 2.0 Docker Compose or Helm deployment to mod_pagespeed 2.1: unprivileged worker, loopback-bound API, configuration carries over. - [Upgrade](https://modpagespeed.com/docs/upgrade/): Upgrade mod_pagespeed 2.1 per shape: apt or dnf, Docker tag, Helm, the Windows installer and NuGet; what to read first, security updates, rollback. - [Migrate from mod_pagespeed 1.15](https://modpagespeed.com/docs/migrate-from-1-15/): Move a 1.15 install to mod_pagespeed 2.1 in place: one package upgrade brings the optimizer worker, configuration carries over, the old cache stays. - [Migrate from ngx_pagespeed](https://modpagespeed.com/docs/migrate-from-ngx-pagespeed/): Replace an open-source ngx_pagespeed build, compiled in or from a third-party package, with the signed mod_pagespeed 2.1 nginx module: what carries over. - [Migrate from IISpeed](https://modpagespeed.com/docs/migrate-from-iispeed/): Move an IISpeed install to the mod_pagespeed IIS module: save the configuration, uninstall IISpeed, run the MSI, keep the cache, verify, roll back. - [Migrate from the archived Google module](https://modpagespeed.com/docs/migrate-from-google-mod-pagespeed/): Move from the archived mod_pagespeed or ngx_pagespeed binaries to mod_pagespeed 2: package swap, what maps to what, cache, rollback. ## Configure - [Configuration reference: Apache and nginx directives](https://modpagespeed.com/docs/configuration/): Every mod_pagespeed 2.1 directive for the native Apache and nginx module, generated from the source: syntax, default, context and description. - [Set Cache-Control headers](https://modpagespeed.com/docs/cache-control/): Which Cache-Control headers to set on your origin, by content type and by framework, for correct caching with mod_pagespeed 2.1. - [Worker and reverse-proxy configuration](https://modpagespeed.com/docs/worker-configuration/): Every optimizer worker flag and thin nginx module directive of mod_pagespeed 2.1 (the Docker and reverse-proxy shape), generated from the source. - [Choose a cache mode: safe vs aggressive](https://modpagespeed.com/docs/cache-modes/): Safe or aggressive Cache-Control for optimized responses in mod_pagespeed 2.1, plus the module cache reference: Cyclone, memcached, Redis, purging, IPRO. - [Integrate with a CDN](https://modpagespeed.com/docs/cdn-integration/): Run mod_pagespeed 2.1 behind Cloudflare, CloudFront or Fastly: how Vary headers affect edge caching, per-CDN cache-key settings and keeping hit rates high. - [Domain configuration](https://modpagespeed.com/docs/domain-configuration/): Domain mapping in mod_pagespeed 2.1 on nginx, Apache and IIS: Domain, MapOriginDomain, MapRewriteDomain, MapProxyDomain, ShardDomain and LoadFromFile. - [HTTPS configuration](https://modpagespeed.com/docs/https-configuration/): Fetch HTTPS resources on nginx, Apache and IIS with mod_pagespeed 2.1: FetchHttps with certificate checks, MapOriginDomain to HTTP, or LoadFromFile. - [IIS configuration](https://modpagespeed.com/docs/iis-configuration/): mod_pagespeed on IIS via pagespeed.config, the native IIS module and successor to IISpeed: directive syntax, path matching, server and site-level config. - [ASP.NET Core settings](https://modpagespeed.com/docs/aspnet-configuration/): Configuration reference for the mod_pagespeed 2.1 ASP.NET Core middleware: appsettings.json PageSpeed options, cache and worker settings, and hot reload. ## Filters - [Filter selection](https://modpagespeed.com/docs/filter-selection/): Choose which mod_pagespeed 2.1 filters run: RewriteLevel presets, the CoreFilters default, EnableFilters, DisableFilters, ForbidFilters and thresholds. - [Image filters](https://modpagespeed.com/docs/image-filters/): Image filters in mod_pagespeed 2.1 for Apache, nginx and IIS: recompression, WebP and opt-in AVIF conversion, resizing, lazy loading and responsive images. - [CSS filters](https://modpagespeed.com/docs/css-filters/): CSS filters in mod_pagespeed 2.1: minify, combine, inline and flatten @import CSS, plus critical-CSS extraction. Apache, nginx and IIS syntax with tuning. - [JavaScript filters](https://modpagespeed.com/docs/javascript-filters/): Minify, combine, inline, and defer JavaScript in mod_pagespeed 2.1. Directives, defaults, and the trade-offs for each JS filter on Apache, nginx, and IIS. - [HTML filters](https://modpagespeed.com/docs/html-filters/): HTML optimization filters in mod_pagespeed 2.1: collapse whitespace, strip comments, elide attributes, DNS prefetch, and resource preload hints. - [Rule packs](https://modpagespeed.com/docs/rule-packs/): Rule packs for Apache, nginx and IIS: JSON rules for the canonical, title, description, hreflang and JSON-LD of your pages, in report mode first. - [Collapse whitespace (collapse_whitespace)](https://modpagespeed.com/docs/filters/collapse_whitespace/): Removes excess whitespace from HTML. - [Combine CSS (combine_css)](https://modpagespeed.com/docs/filters/combine_css/): Combines multiple CSS files into one. - [Combine heads (combine_heads)](https://modpagespeed.com/docs/filters/combine_heads/): Merges multiple elements. - [Combine JavaScript (combine_javascript)](https://modpagespeed.com/docs/filters/combine_javascript/): Combines multiple JS files into one. - [Convert GIF to PNG (convert_gif_to_png)](https://modpagespeed.com/docs/filters/convert_gif_to_png/): Converts GIF to PNG. - [Convert JPEG to WebP (convert_jpeg_to_webp)](https://modpagespeed.com/docs/filters/convert_jpeg_to_webp/): Converts JPEG to WebP for capable browsers. - [Convert PNG to JPEG (convert_png_to_jpeg)](https://modpagespeed.com/docs/filters/convert_png_to_jpeg/): Converts PNG to JPEG when no transparency. - [Deduplicate inlined images (dedup_inlined_images)](https://modpagespeed.com/docs/filters/dedup_inlined_images/): Replaces repeated inlined images with JS reference. - [Defer JavaScript (defer_javascript)](https://modpagespeed.com/docs/filters/defer_javascript/): Defers JS execution until after page load. - [In-place browser optimization (in_place_optimize_for_browser)](https://modpagespeed.com/docs/filters/in_place_optimize_for_browser/): Browser-specific in-place optimization. - [Inline CSS (inline_css)](https://modpagespeed.com/docs/filters/inline_css/): Inlines small external CSS into HTML. - [Inline images (inline_images)](https://modpagespeed.com/docs/filters/inline_images/): Inlines small images as data: URIs. - [Inline JavaScript (inline_javascript)](https://modpagespeed.com/docs/filters/inline_javascript/): Inlines small external JS into HTML. - [Inline preview images (inline_preview_images)](https://modpagespeed.com/docs/filters/inline_preview_images/): Inserts low-quality image placeholders. - [Insert DNS prefetch (insert_dns_prefetch)](https://modpagespeed.com/docs/filters/insert_dns_prefetch/): Adds for third-party domains. - [Insert image dimensions (insert_image_dimensions)](https://modpagespeed.com/docs/filters/insert_image_dimensions/): Adds width and height attributes to tags. - [Insert speculation rules (insert_speculation_rules)](https://modpagespeed.com/docs/filters/insert_speculation_rules/): Injects a same-origin prefetch speculation-rules script. - [Lazy-load images (lazyload_images)](https://modpagespeed.com/docs/filters/lazyload_images/): Defers offscreen image loading. - [Local storage cache (local_storage_cache)](https://modpagespeed.com/docs/filters/local_storage_cache/): Caches inlined resources in localStorage. - [Move CSS above scripts (move_css_above_scripts)](https://modpagespeed.com/docs/filters/move_css_above_scripts/): Moves CSS above ``` The mechanism is per-resource and expiry-aware: each stored entry carries the resource's cache expiration, expired entries are dropped from storage and from the cookie, and an element whose entry is missing or expired is restored by fetching the resource from the network. The filter needs JavaScript to run: since v1.15.0+r18, with `HonorCsp` (default on) it stands down on pages whose `Content-Security-Policy` disallows the inline script it relies on. Not recommended for most deployments. Browser `localStorage` has size limits (typically 5-10 MB per origin) and can be cleared by the user at any time. Sites with many inlined resources may exceed these limits, and pages then pay the storing overhead without the repeat-view saving. A page whose HTML is already cached by the browser gains little: the inlined bytes ride inside a cached document either way. Compare it against `extend_cache`, which gets the same repeat-view saving by keeping resources in external, content-hashed URLs with a one-year lifetime and no scripts at all; that is the recommended path. ```apache # Apache ModPagespeedEnableFilters local_storage_cache ``` ```nginx # Nginx pagespeed EnableFilters local_storage_cache; ``` On IIS the same directives use the syntax described in [IIS configuration](https://modpagespeed.com/docs/iis-configuration/). ## Auditing your origin The [web console](https://we-amp.com/console/) flags URLs where the origin sends no `Cache-Control` header. Use the URL inspector to check freshness status and identify origins that need explicit headers. --- # Worker and reverse-proxy configuration Every optimizer worker flag and thin nginx module directive of mod_pagespeed 2.1 (the Docker and reverse-proxy shape), generated from the source. Canonical URL: https://modpagespeed.com/docs/worker-configuration/ > **Running the native module?** > > This page is for the **Docker / reverse-proxy shape**: the thin nginx module in > front of your origin plus the optimizer worker beside it, as the > `pagespeed-nginx` and `pagespeed-worker` images and the Helm chart run them. If > you installed the in-process module into Apache or nginx from the package > repository, its directives (`ModPagespeed…` / `pagespeed …`) are on the > [configuration reference](https://modpagespeed.com/docs/configuration/). This shape has a small configuration surface: two required nginx directives (`pagespeed on;` and `pagespeed_cache_path`), a shared configuration file the worker writes, and the worker's command-line flags. The reference below is generated from the product's source, so it lists exactly what the shipped binaries accept: the 16 directives of the thin module from its command table, and every flag of the worker from its own `--help` text, each as a fixed Syntax / Default block (the directives also list their context). Everything past the two required directives is optional tuning. To work out which flags your own pages need, run them through a [PageSpeed Insights test](https://modpagespeed.com/analyze/): every failing audit is mapped to the transform that fixes it, so the report doubles as a configuration checklist. ## Which nginx version Three things on this site bundle or target an nginx, and they are not the same version. This table is the one place that says which applies to which shape; the Docker and sidecar rows come from the version files in the source tree, the package rows from the signed repository's distribution matrix. | Shape | nginx version | Configuration surface | | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------- | | Docker / reverse proxy (`ghcr.io/we-amp/pagespeed-nginx`, the combined image, Helm) | nginx 1.30.6, bundled in the image | Thin module + worker | | Native module package, Debian 12 bookworm | nginx 1.22.1 (the distribution's stock nginx; exact-version pin) | Native module | | Native module package, Debian 13 trixie | nginx 1.26.3 (the distribution's stock nginx; exact-version pin) | Native module | | Native module package, Ubuntu 22.04 jammy | nginx 1.18.0 (the distribution's stock nginx; exact-version pin) | Native module | | Native module package, Ubuntu 24.04 noble | nginx 1.24.0 (the distribution's stock nginx; exact-version pin) | Native module | | Native module package, AlmaLinux 9 (yum) | nginx 1.20.1 (stock nginx; exact-version pin) | Native module | | NuGet sidecar `WeAmp.PageSpeed.Sidecar` | nginx 1.30.4, bundled in the package | Thin module + worker | The native module is built per distribution and pinned to that distribution's exact nginx version (nginx's `--with-compat` does not relax the check), so an nginx version that is not in the table needs a matching pinned build. The Docker image and the NuGet sidecar ship their own nginx, so the host's nginx version does not matter for them. ## Thin module directives The thin module's directives are available in the `http`, `server` and `location` contexts; a value set at a higher level is inherited by nested blocks. The module reads everything else (the worker socket, the HTML toggle, URL normalization, the cache mode when no directive sets it) from the [shared configuration file](https://modpagespeed.com/docs/worker-configuration/#shared-configuration-file). [`pagespeed`](https://modpagespeed.com/docs/worker-configuration/#pagespeed), [`pagespeed_cache_path`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_cache_path), [`pagespeed_disallow`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_disallow), [`pagespeed_hot_threshold`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_hot_threshold), [`pagespeed_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_max_age), [`pagespeed_immutable_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_immutable_max_age), [`pagespeed_synthesize_swr`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_synthesize_swr), [`pagespeed_conditional_revalidation`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_conditional_revalidation), [`pagespeed_stale_if_error_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_stale_if_error_max_age), [`pagespeed_html_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_html_max_age), [`pagespeed_css_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_css_max_age), [`pagespeed_image_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_image_max_age), [`pagespeed_force_refresh_html`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_force_refresh_html), [`pagespeed_force_refresh`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_force_refresh), [`pagespeed_trust_x_forwarded_proto`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_trust_x_forwarded_proto), [`pagespeed_cache_mode`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_cache_mode) #### pagespeed - **Syntax:** `pagespeed on | off;` - **Default:** `off` - **Context:** http, server, location When on, the module intercepts responses, serves optimized variants from the cache, notifies the worker on a miss and adds the `X-PageSpeed` response header (`HIT` or `MISS`). `pagespeed off;` inside a `location` block switches the module off for that path; see [Disabling per location](https://modpagespeed.com/docs/worker-configuration/#disabling-pagespeed-per-location). The thin module's switch is a plain flag; the native module's `on`, `standby` and `unplugged` states are on the [configuration reference](https://modpagespeed.com/docs/configuration/#modpagespeed). ```nginx pagespeed on; ``` #### pagespeed_cache_path - **Syntax:** `pagespeed_cache_path path;` - **Default:** `(empty)` - **Context:** http, server, location Path of the Cyclone cache volume file. ```nginx pagespeed_cache_path /var/lib/pagespeed/cache.vol; ``` Caching is disabled while this is unset. The path must be the same file the worker opens (`--cache-path`, or the volume stem inside `--cache-dir`). Both processes open the file with memory-mapped directory sharing, so writes from either side are immediately visible to the other. The worker creates the file if it does not exist. For sharing to work the file must be readable and writable by both the nginx worker processes and the optimizer worker. The packaged worker takes care of this: it runs as the unprivileged `pagespeed` user and sets every shared file to 0660 owner+group, so the only setup the web side needs is membership in group `pagespeed` (the module package's postinst adds it). The module also checks that the worker beside this path uses the same cache format, by comparing its own cache-directory generation with the `cache_dir_generation` the worker publishes in the [shared configuration file](https://modpagespeed.com/docs/worker-configuration/#shared-configuration-file). See [Cache-directory generation check](https://modpagespeed.com/docs/worker-configuration/#cache-directory-generation-check). #### pagespeed_disallow - **Syntax:** `pagespeed_disallow pattern;` - **Default:** — - **Context:** http, server, location Excludes URLs from caching and optimization while the module stays active for everything else. Repeatable; the first matching pattern wins. ```nginx pagespeed_disallow /api/; # prefix match pagespeed_disallow *.woff2; # suffix match pagespeed_disallow admin; # substring match ``` A pattern starting with `/` matches a URL prefix, a pattern starting with `*` matches a suffix, any other pattern matches as a substring. See [URL pattern exclusions](https://modpagespeed.com/docs/worker-configuration/#url-pattern-exclusions). #### pagespeed_hot_threshold - **Syntax:** `pagespeed_hot_threshold count;` - **Default:** `5` - **Context:** http, server, location Number of fallback hits before a URL counts as "hot" and triggers a warmup notification to the worker. Only relevant when the worker runs with [`--enable-warmup`](https://modpagespeed.com/docs/worker-configuration/#--enable-warmup). #### pagespeed_max_age - **Syntax:** `pagespeed_max_age seconds;` - **Default:** `86400` - **Context:** http, server, location Cap in seconds on the `max-age` taken from the origin's `Cache-Control`. See the [cache-control guide](https://modpagespeed.com/docs/cache-control/). #### pagespeed_immutable_max_age - **Syntax:** `pagespeed_immutable_max_age seconds;` - **Default:** `604800` - **Context:** http, server, location Cap in seconds for responses the origin marks `Cache-Control: immutable`. #### pagespeed_synthesize_swr - **Syntax:** `pagespeed_synthesize_swr on | off;` - **Default:** `on` - **Context:** http, server, location Synthesizes `stale-while-revalidate` on cache-served (`HIT`) responses. Safe mode suppresses the synthesis regardless of this flag; see [`pagespeed_cache_mode`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_cache_mode). #### pagespeed_conditional_revalidation - **Syntax:** `pagespeed_conditional_revalidation on | off;` - **Default:** `on` - **Context:** http, server, location Answers `If-None-Match` and `If-Modified-Since` requests with `304 Not Modified` when the cached body still matches. #### pagespeed_stale_if_error_max_age - **Syntax:** `pagespeed_stale_if_error_max_age seconds;` - **Default:** `86400` - **Context:** http, server, location Window in seconds during which a stale cached response may be served when the origin fails; `0` disables it. The default matches the `stale-if-error=86400` that aggressive mode advertises to downstream caches. #### pagespeed_html_max_age - **Syntax:** `pagespeed_html_max_age seconds;` - **Default:** `0` - **Context:** http, server, location Default `max-age` in seconds for HTML the origin serves without a `Cache-Control` header. `0` keeps such HTML uncached; set it to opt an origin into [HTML caching](https://modpagespeed.com/docs/worker-configuration/#html-caching). #### pagespeed_css_max_age - **Syntax:** `pagespeed_css_max_age seconds;` - **Default:** `300 (safe) / 86400 (aggressive)` (depends on the resolved cache mode) - **Context:** http, server, location Default `max-age` in seconds for CSS and JavaScript the origin serves without a `Cache-Control` header. The default follows the cache mode. #### pagespeed_image_max_age - **Syntax:** `pagespeed_image_max_age seconds;` - **Default:** `1800 (safe) / 86400 (aggressive)` (depends on the resolved cache mode) - **Context:** http, server, location Default `max-age` in seconds for images the origin serves without a `Cache-Control` header. The default follows the cache mode. #### pagespeed_force_refresh_html - **Syntax:** `pagespeed_force_refresh_html on | off;` - **Default:** `on` - **Context:** http, server, location Revalidates HTML at the origin when the browser force-refreshes (Ctrl+F5 / `Cache-Control: no-cache` on the request). #### pagespeed_force_refresh - **Syntax:** `pagespeed_force_refresh on | off;` - **Default:** `off` - **Context:** http, server, location Revalidates every non-HTML type at the origin on a browser force-refresh. #### pagespeed_trust_x_forwarded_proto - **Syntax:** `pagespeed_trust_x_forwarded_proto on | off;` - **Default:** `off` - **Context:** http, server, location Reads the `X-Forwarded-Proto` request header to decide the request scheme (`http` or `https`) instead of connection-level TLS detection. Use it when nginx sits behind a TLS-terminating reverse proxy, load balancer or CDN that sets the header. Only lowercase `http` and `https` values are accepted; any other value falls back to connection-level detection. > **Caution** > > Only enable this when the upstream proxy strips and re-sets the > `X-Forwarded-Proto` header. If clients can set the header directly, they can > manipulate scheme detection. ```nginx # Upstream nginx (TLS termination) server { listen 443 ssl; location / { proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://backend; } } # Backend nginx (PageSpeed) server { listen 80; pagespeed on; pagespeed_trust_x_forwarded_proto on; pagespeed_cache_path /var/lib/pagespeed/cache.vol; } ``` #### pagespeed_cache_mode - **Syntax:** `pagespeed_cache_mode safe | aggressive;` - **Default:** `safe` (unless the worker shared configuration sets aggressive) - **Context:** http, server, location Controls how `Cache-Control` headers are assembled on optimized responses. ```nginx pagespeed_cache_mode safe; # default: short TTLs, must-revalidate pagespeed_cache_mode aggressive; # long TTLs, public, stale-if-error ``` In safe mode, `must-revalidate` is added to all non-HTML responses, SWR synthesis is suppressed, and `immutable` is stripped from transformed content. In aggressive mode, `public` and `stale-if-error=86400` are added, and SWR synthesis is allowed. HTML always gets `no-cache` in both modes. The per-type defaults of [`pagespeed_css_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_css_max_age) and [`pagespeed_image_max_age`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_image_max_age) follow the mode. See [Cache modes](https://modpagespeed.com/docs/cache-modes/) for the full reference. ### Cache-Control directives `pagespeed_max_age`, `pagespeed_immutable_max_age`, the per-type `pagespeed_*_max_age` directives, `pagespeed_synthesize_swr`, `pagespeed_conditional_revalidation` and the two `pagespeed_force_refresh*` directives together decide the `Cache-Control` and `Age` headers on cache-served responses. The [cache-control guide](https://modpagespeed.com/docs/cache-control/) walks through the resulting headers per content type, and [Cache modes](https://modpagespeed.com/docs/cache-modes/) through `pagespeed_cache_mode`. ### Cache-directory generation check A cache directory holds one cache format, and the format is part of the volume file's name. A module and a worker built for different formats would open two different files in the same directory and never share a cache. So the module compares its compiled-in generation with the worker's `cache_dir_generation`: at start, on every reload, and whenever the worker rewrites its shared config (the ~1s poll). | Result | What the module does | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `match` | Uses the cache as normal. | | `mismatch` | Keeps serving with its cache **off**: requests go to the origin, nothing is read or stored, and the worker is not notified. Logs one `[error]` naming both generations and the older side. | | `unknown` | The worker publishes no generation (older than 2.1.0), or there is no shared config yet. Uses the cache as before and logs one `[warn]`. | A mismatch clears itself: once the worker publishes the matching generation, the module turns its cache back on without a reload and logs "now matches". The fix is to run the same release of both, from packages or from one image tag. Three variables expose the result, as this nginx worker last saw it: | Variable | Value | | --------------------------------------- | ------------------------------------------------- | | `$pagespeed_cache_generation` | `match`, `mismatch` or `unknown` | | `$pagespeed_cache_generation_module` | The module's generation | | `$pagespeed_cache_generation_optimizer` | The worker's published generation (empty if none) | ```nginx log_format pagespeed_gen '$remote_addr "$request" $status ' 'cache_generation=$pagespeed_cache_generation'; location = /pagespeed-generation { allow 127.0.0.1; deny all; return 200 "$pagespeed_cache_generation module=$pagespeed_cache_generation_module optimizer=$pagespeed_cache_generation_optimizer\n"; } ``` ## Shared configuration file The worker writes a `pagespeed-shared.conf` file next to the cache file (in the parent directory of `--cache-path`). Nginx reads this file automatically using `pagespeed_cache_path` to locate it. The file is polled every ~1 second for changes. **Format:** `key=value` (one per line) **Fields:** | Key | Description | Worker flag | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | | `socket_path` | Unix socket path for nginx-to-worker notifications | `--socket PATH` | | `disable_html` | Whether HTML optimization is disabled (`true`/`false`) | `--disable-html` | | `cache_dir_generation` | Cache-directory generation N (skew = loud handshake failure; nginx turns its cache off, see [the check](https://modpagespeed.com/docs/worker-configuration/#cache-directory-generation-check)) | (compiled in) | The file is written atomically at mode 0640 `pagespeed:pagespeed`: readable by the worker and its group-`pagespeed` peers, not by the world. The shared config file is written on worker startup and whenever settings change via `PATCH /v1/config`. This eliminates the need to duplicate configuration between the nginx config and worker flags. On a cache miss, nginx reads the `socket_path` from the shared config and sends a fire-and-forget notification to the worker. If the socket is not available (worker not running, socket not yet created), the notification is silently dropped. The original content continues to be served from the cache. ## Worker flags The `factory_worker` binary accepts the flags below. The blocks are generated from the worker's own usage text, so a flag listed here is a flag the shipped binary accepts, and `--help` on your installed version shows the same list. Boolean `--no-…` flags switch off a transform that is on by default; the `(default: …)` in a description is the worker's own wording. Sections: [General options](https://modpagespeed.com/docs/worker-configuration/#flags-general-options) (88) · [Windows service](https://modpagespeed.com/docs/worker-configuration/#flags-windows-service) (2) · [Cache key normalization](https://modpagespeed.com/docs/worker-configuration/#flags-cache-key-normalization) (4) · [SVG auto-vectorization](https://modpagespeed.com/docs/worker-configuration/#flags-svg-auto-vectorization) (11) · [Agent optimize (experimental, off by default)](https://modpagespeed.com/docs/worker-configuration/#flags-agent-optimize-experimental-off-by-default) (8) · [Web Bot Auth (observe-only, off by default)](https://modpagespeed.com/docs/worker-configuration/#flags-web-bot-auth-observe-only-off-by-default) (4). ### General options [`--socket`](https://modpagespeed.com/docs/worker-configuration/#--socket), [`--cache-dir`](https://modpagespeed.com/docs/worker-configuration/#--cache-dir), [`--cache-path`](https://modpagespeed.com/docs/worker-configuration/#--cache-path), [`--cache-size`](https://modpagespeed.com/docs/worker-configuration/#--cache-size), [`--ram-cache-size`](https://modpagespeed.com/docs/worker-configuration/#--ram-cache-size), [`--read-lease-duration`](https://modpagespeed.com/docs/worker-configuration/#--read-lease-duration), [`--lease-wrap-ceiling`](https://modpagespeed.com/docs/worker-configuration/#--lease-wrap-ceiling), [`--num-threads`](https://modpagespeed.com/docs/worker-configuration/#--num-threads), [`--max-connections`](https://modpagespeed.com/docs/worker-configuration/#--max-connections), [`--max-buffer-size`](https://modpagespeed.com/docs/worker-configuration/#--max-buffer-size), [`--connection-timeout`](https://modpagespeed.com/docs/worker-configuration/#--connection-timeout), [`--shutdown-timeout`](https://modpagespeed.com/docs/worker-configuration/#--shutdown-timeout), [`--disable-html`](https://modpagespeed.com/docs/worker-configuration/#--disable-html), [`--disable-css`](https://modpagespeed.com/docs/worker-configuration/#--disable-css), [`--disable-js`](https://modpagespeed.com/docs/worker-configuration/#--disable-js), [`--disable-image`](https://modpagespeed.com/docs/worker-configuration/#--disable-image), [`--proactive-image-variants`](https://modpagespeed.com/docs/worker-configuration/#--proactive-image-variants), [`--no-proactive-viewport-variants`](https://modpagespeed.com/docs/worker-configuration/#--no-proactive-viewport-variants), [`--no-proactive-savedata-variants`](https://modpagespeed.com/docs/worker-configuration/#--no-proactive-savedata-variants), [`--no-proactive-density-variants`](https://modpagespeed.com/docs/worker-configuration/#--no-proactive-density-variants), [`--enable-warmup`](https://modpagespeed.com/docs/worker-configuration/#--enable-warmup), [`--no-lazy-load-images`](https://modpagespeed.com/docs/worker-configuration/#--no-lazy-load-images), [`--no-image-dimensions`](https://modpagespeed.com/docs/worker-configuration/#--no-image-dimensions), [`--no-lcp-preload`](https://modpagespeed.com/docs/worker-configuration/#--no-lcp-preload), [`--no-preconnect-injection`](https://modpagespeed.com/docs/worker-configuration/#--no-preconnect-injection), [`--no-async-css`](https://modpagespeed.com/docs/worker-configuration/#--no-async-css), [`--async-css-min-coverage`](https://modpagespeed.com/docs/worker-configuration/#--async-css-min-coverage), [`--async-css-min-deferred-bytes`](https://modpagespeed.com/docs/worker-configuration/#--async-css-min-deferred-bytes), [`--enable-speculation-rules`](https://modpagespeed.com/docs/worker-configuration/#--enable-speculation-rules), [`--no-content-analysis`](https://modpagespeed.com/docs/worker-configuration/#--no-content-analysis), [`--no-preserve-c2pa`](https://modpagespeed.com/docs/worker-configuration/#--no-preserve-c2pa), [`--c2pa-carry`](https://modpagespeed.com/docs/worker-configuration/#--c2pa-carry), [`--denoise-threshold`](https://modpagespeed.com/docs/worker-configuration/#--denoise-threshold), [`--denoise-sigma-spatial`](https://modpagespeed.com/docs/worker-configuration/#--denoise-sigma-spatial), [`--denoise-sigma-range`](https://modpagespeed.com/docs/worker-configuration/#--denoise-sigma-range), [`--no-quality-verify`](https://modpagespeed.com/docs/worker-configuration/#--no-quality-verify), [`--target-ssimulacra2`](https://modpagespeed.com/docs/worker-configuration/#--target-ssimulacra2), [`--ssimulacra2-tolerance`](https://modpagespeed.com/docs/worker-configuration/#--ssimulacra2-tolerance), [`--no-learned-quality`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality), [`--no-learned-quality-jpeg`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality-jpeg), [`--no-learned-quality-webp`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality-webp), [`--no-learned-quality-avif`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality-avif), [`--savedata-score-reduction`](https://modpagespeed.com/docs/worker-configuration/#--savedata-score-reduction), [`--gzip-level`](https://modpagespeed.com/docs/worker-configuration/#--gzip-level), [`--brotli-level`](https://modpagespeed.com/docs/worker-configuration/#--brotli-level), [`--no-css-import-flattening`](https://modpagespeed.com/docs/worker-configuration/#--no-css-import-flattening), [`--mobile-width`](https://modpagespeed.com/docs/worker-configuration/#--mobile-width), [`--tablet-width`](https://modpagespeed.com/docs/worker-configuration/#--tablet-width), [`--desktop-width`](https://modpagespeed.com/docs/worker-configuration/#--desktop-width), [`--jpeg-quality`](https://modpagespeed.com/docs/worker-configuration/#--jpeg-quality), [`--webp-quality`](https://modpagespeed.com/docs/worker-configuration/#--webp-quality), [`--avif-quality`](https://modpagespeed.com/docs/worker-configuration/#--avif-quality), [`--savedata-jpeg-quality`](https://modpagespeed.com/docs/worker-configuration/#--savedata-jpeg-quality), [`--savedata-webp-quality`](https://modpagespeed.com/docs/worker-configuration/#--savedata-webp-quality), [`--savedata-avif-quality`](https://modpagespeed.com/docs/worker-configuration/#--savedata-avif-quality), [`--max-url-length`](https://modpagespeed.com/docs/worker-configuration/#--max-url-length), [`--max-html-size`](https://modpagespeed.com/docs/worker-configuration/#--max-html-size), [`--max-css-size`](https://modpagespeed.com/docs/worker-configuration/#--max-css-size), [`--max-js-size`](https://modpagespeed.com/docs/worker-configuration/#--max-js-size), [`--max-image-size`](https://modpagespeed.com/docs/worker-configuration/#--max-image-size), [`--log-level`](https://modpagespeed.com/docs/worker-configuration/#--log-level), [`--log-format`](https://modpagespeed.com/docs/worker-configuration/#--log-format), [`--api-socket`](https://modpagespeed.com/docs/worker-configuration/#--api-socket), [`--api-port`](https://modpagespeed.com/docs/worker-configuration/#--api-port), [`--api-bind`](https://modpagespeed.com/docs/worker-configuration/#--api-bind), [`--api-allow-remote`](https://modpagespeed.com/docs/worker-configuration/#--api-allow-remote), [`--api-no-auth`](https://modpagespeed.com/docs/worker-configuration/#--api-no-auth), [`--api-token`](https://modpagespeed.com/docs/worker-configuration/#--api-token), [`--api-read-open`](https://modpagespeed.com/docs/worker-configuration/#--api-read-open), [`--no-security-headers`](https://modpagespeed.com/docs/worker-configuration/#--no-security-headers), [`--console-dir`](https://modpagespeed.com/docs/worker-configuration/#--console-dir), [`--enable-browser-analysis`](https://modpagespeed.com/docs/worker-configuration/#--enable-browser-analysis), [`--browser-sandbox`](https://modpagespeed.com/docs/worker-configuration/#--browser-sandbox), [`--browser-user-data-dir`](https://modpagespeed.com/docs/worker-configuration/#--browser-user-data-dir), [`--chrome-binary`](https://modpagespeed.com/docs/worker-configuration/#--chrome-binary), [`--chrome-recycle-interval`](https://modpagespeed.com/docs/worker-configuration/#--chrome-recycle-interval), [`--chrome-page-timeout`](https://modpagespeed.com/docs/worker-configuration/#--chrome-page-timeout), [`--chrome-max-memory`](https://modpagespeed.com/docs/worker-configuration/#--chrome-max-memory), [`--chrome-startup-timeout`](https://modpagespeed.com/docs/worker-configuration/#--chrome-startup-timeout), [`--no-browser-critical-css`](https://modpagespeed.com/docs/worker-configuration/#--no-browser-critical-css), [`--no-browser-lazy-loading`](https://modpagespeed.com/docs/worker-configuration/#--no-browser-lazy-loading), [`--no-browser-lcp-preload`](https://modpagespeed.com/docs/worker-configuration/#--no-browser-lcp-preload), [`--no-browser-image-sizing`](https://modpagespeed.com/docs/worker-configuration/#--no-browser-image-sizing), [`--browser-queue-size`](https://modpagespeed.com/docs/worker-configuration/#--browser-queue-size), [`--browser-profile-ttl`](https://modpagespeed.com/docs/worker-configuration/#--browser-profile-ttl), [`--allow-private-urls`](https://modpagespeed.com/docs/worker-configuration/#--allow-private-urls), [`--version`](https://modpagespeed.com/docs/worker-configuration/#--version), [`--help`](https://modpagespeed.com/docs/worker-configuration/#--help) #### --socket - **Syntax:** `--socket PATH` - **Default:** `/run/pagespeed-optimizer/notify.sock` Unix socket path (default: /run/pagespeed-optimizer/notify.sock) ```bash factory_worker --socket /run/pagespeed-optimizer/notify.sock ``` The socket path reaches nginx automatically through the [shared configuration file](https://modpagespeed.com/docs/worker-configuration/#shared-configuration-file); no nginx directive is needed. The worker creates the socket at startup with an explicit 0660 owner+group mode, never umask-derived, so the web side reaches it through group `pagespeed` membership rather than world permissions. The directory must exist and be writable by the worker's user (the packaged unit uses a systemd `RuntimeDirectory`, 0750 `pagespeed:pagespeed`). #### --cache-dir - **Syntax:** `--cache-dir DIR` - **Default:** `/var/cache/pagespeed-optimizer/v3` Cache directory; the volume, shared config and serve-stats live inside it (default: /var/cache/pagespeed-optimizer/v3) ```bash factory_worker --cache-dir /var/cache/pagespeed-optimizer/v3 ``` The `v3` in the default is the compiled-in cache-directory generation. The directory must exist, be writable by the worker, and contain only files owned by the worker's user; otherwise the worker refuses to start and names the cause. The packaged tmpfiles.d drop-in creates the default as 3770 `pagespeed:pagespeed` (setgid so the group is inherited, sticky so one group member cannot remove another's files). #### --cache-path - **Syntax:** `--cache-path PATH` - **Default:** — Expert override: full cache volume file STEM (deliberately extensionless); wins over --cache-dir ```bash factory_worker --cache-path /var/cache/pagespeed-optimizer/v3/cache ``` Must match the nginx [`pagespeed_cache_path`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_cache_path) directive. The worker reads original content from this file and writes optimized variants back to it. #### --cache-size - **Syntax:** `--cache-size BYTES` - **Default:** `1073741824` Cache size in bytes (default: 1073741824) ```bash factory_worker --cache-size 536870912 # 512 MB ``` Total size of the Cyclone cache volume. The cache evicts least recently used entries when full. See [Sizing the cache](https://modpagespeed.com/docs/worker-configuration/#sizing-the-cache). #### --ram-cache-size - **Syntax:** `--ram-cache-size BYTES` - **Default:** `67108864` RAM cache size in bytes, 0 to disable (default: 67108864) The RAM tier uses write-around semantics: writes go to the volume, reads populate the RAM cache on a miss, so nginx and the worker never see stale copies of each other's writes. See [Threading and memory](https://modpagespeed.com/docs/worker-configuration/#threading). #### --read-lease-duration - **Syntax:** `--read-lease-duration MS` - **Default:** `5000` Cache read-lease duration for wrap deferral, 0 to disable leases (default: 5000) ```bash factory_worker --read-lease-duration 0 # disable read leases ``` While a lease is live the cache defers overwriting that region, so in-flight zero-copy responses are never served corrupted bytes. `0` disables leases (writes are never deferred). On a full cache under sustained read traffic, leases can delay new writes to a hot region; lowering or disabling them favors write throughput over zero-copy read protection. #### --lease-wrap-ceiling - **Syntax:** `--lease-wrap-ceiling MS` - **Default:** `60000` Max continuous wrap deferral before a wrap is forced (default: 60000) ```bash factory_worker --lease-wrap-ceiling 30000 ``` Only relevant when read leases are enabled. Lower values favor write admission at a full cache; responses that hold cache content longer than this ceiling fall back to copying. #### --num-threads - **Syntax:** `--num-threads N` - **Default:** `auto` Thread pool size for notification processing (default: auto) `auto` sizes the pool from the available CPU cores. See [Threading and memory](https://modpagespeed.com/docs/worker-configuration/#threading). #### --max-connections - **Syntax:** `--max-connections N` - **Default:** `128` Max simultaneous connections (default: 128) ```bash factory_worker --max-connections 256 ``` When the limit is reached, new connections are accepted and immediately closed. Monitor the [health check](https://modpagespeed.com/docs/worker-configuration/#health-check) to track connection usage. #### --max-buffer-size - **Syntax:** `--max-buffer-size BYTES` - **Default:** `1048576` Max per-client buffer size (default: 1048576) ```bash factory_worker --max-buffer-size 2097152 # 2 MB ``` Connections exceeding this buffer size are disconnected, so a malformed or oversized message cannot exhaust memory. #### --connection-timeout - **Syntax:** `--connection-timeout MS` - **Default:** `30000` Idle connection timeout in ms (default: 30000) ```bash factory_worker --connection-timeout 60000 # 60 seconds ``` Connections that send no data within the timeout are closed. #### --shutdown-timeout - **Syntax:** `--shutdown-timeout MS` - **Default:** `5000` Graceful shutdown timeout in ms (default: 5000) ```bash factory_worker --shutdown-timeout 10000 # 10 seconds ``` On SIGTERM or SIGINT the worker stops accepting new connections and waits up to this long for active connections to drain before force-closing them. #### --disable-html - **Syntax:** `--disable-html` - **Default:** — Disable HTML optimization HTML notifications from nginx are ignored: no critical-CSS inlining, no HTML transforms, no HTML caching. #### --disable-css - **Syntax:** `--disable-css` - **Default:** — Disable CSS minification CSS notifications are ignored. #### --disable-js - **Syntax:** `--disable-js` - **Default:** — Disable JS minification JavaScript notifications are ignored. #### --disable-image - **Syntax:** `--disable-image` - **Default:** — Disable image transcoding Image notifications are ignored. #### --proactive-image-variants - **Syntax:** `--proactive-image-variants` - **Default:** `off` Enable proactive multi-format image generation (default: off) Without this flag the worker produces only the single format the notification asked for (for example only WebP). With it, one decode yields WebP, AVIF and an optimized original. See [Proactive variant generation](https://modpagespeed.com/docs/worker-configuration/#proactive-variant-generation). #### --no-proactive-viewport-variants - **Syntax:** `--no-proactive-viewport-variants` - **Default:** — Disable proactive viewport sibling generation By default variants for all three viewport classes (mobile, tablet, desktop) are generated from one decode, resized to each viewport's target width. With this flag only the viewport in the notification is produced. #### --no-proactive-savedata-variants - **Syntax:** `--no-proactive-savedata-variants` - **Default:** — Disable proactive Save-Data sibling generation By default both normal-quality and Save-Data (lower-quality) variants are generated from each decode. With this flag only the notification's Save-Data preference is produced. The Save-Data quality levels are the `--savedata-*-quality` flags. #### --no-proactive-density-variants - **Syntax:** `--no-proactive-density-variants` - **Default:** — Disable proactive pixel density sibling generation By default variants for both 1x and 2x+ pixel density are generated from each decode; for 2x+ the viewport target width is doubled before resizing (a mobile/2x variant targets 960px instead of 480px). With this flag only the density in the notification is produced. #### --enable-warmup - **Syntax:** `--enable-warmup` - **Default:** `off` Enable hot URL variant warmup (default: off) When nginx detects a URL exceeding [`pagespeed_hot_threshold`](https://modpagespeed.com/docs/worker-configuration/#pagespeed_hot_threshold) it sends a warmup sentinel to the worker. With warmup enabled, the worker pre-generates all missing variants for that URL; without it, warmup notifications are ignored. #### --no-lazy-load-images - **Syntax:** `--no-lazy-load-images` - **Default:** — Disable loading="lazy" injection See [Lazy load images](https://modpagespeed.com/docs/worker-configuration/#lazy-load-images) for what is skipped (the LCP candidate, the first body images, the first iframe, invisible images). #### --no-image-dimensions - **Syntax:** `--no-image-dimensions` - **Default:** — Disable image width/height injection See [Image dimensions](https://modpagespeed.com/docs/worker-configuration/#image-dimensions). #### --no-lcp-preload - **Syntax:** `--no-lcp-preload` - **Default:** — Disable LCP image preload injection See [LCP preload](https://modpagespeed.com/docs/worker-configuration/#lcp-preload). #### --no-preconnect-injection - **Syntax:** `--no-preconnect-injection` - **Default:** — Disable preconnect hint injection See [Preconnect injection](https://modpagespeed.com/docs/worker-configuration/#preconnect-injection). #### --no-async-css - **Syntax:** `--no-async-css` - **Default:** — Disable async CSS loading (keep stylesheets render-blocking) Enabled does not mean applied: see [Async CSS](https://modpagespeed.com/docs/worker-configuration/#async-css) for the per-page conditions deferral requires. #### --async-css-min-coverage - **Syntax:** `--async-css-min-coverage F` - **Default:** `0.10` Min critical/total CSS coverage to defer a stylesheet, 0-1 (default: 0.10; 0 disables the gate) A stylesheet is deferred only when the critical rules cover at least this share of it; `0` disables the gate. See [Async CSS](https://modpagespeed.com/docs/worker-configuration/#async-css). #### --async-css-min-deferred-bytes - **Syntax:** `--async-css-min-deferred-bytes N` - **Default:** `15000` Sheets below this size always defer regardless of coverage (default: 15000) Stylesheets below this size defer regardless of coverage. See [Async CSS](https://modpagespeed.com/docs/worker-configuration/#async-css). #### --enable-speculation-rules - **Syntax:** `--enable-speculation-rules` - **Default:** `off` Enable speculation rules injection (default: off) #### --no-content-analysis - **Syntax:** `--no-content-analysis` - **Default:** — Disable content-aware quality presets Falls back to the `Unknown` content class for every image. See [Content analysis and denoising](https://modpagespeed.com/docs/worker-configuration/#content-analysis-and-denoising). #### --no-preserve-c2pa - **Syntax:** `--no-preserve-c2pa` - **Default:** — Disable C2PA/Content Credentials provenance preservation (on by default) #### --c2pa-carry - **Syntax:** `--c2pa-carry` - **Default:** — Recompress manifest-bearing PNGs and re-splice C2PA chunks (PNG only; default: off, serve original) #### --denoise-threshold - **Syntax:** `--denoise-threshold LEVEL` - **Default:** `0.3` Noise level threshold 0.0-1.0 (default: 0.3, 0=disable) Range 0.0-1.0; `0` disables denoising. See [Content analysis and denoising](https://modpagespeed.com/docs/worker-configuration/#content-analysis-and-denoising). #### --denoise-sigma-spatial - **Syntax:** `--denoise-sigma-spatial F` - **Default:** `3.0` Bilateral filter spatial sigma, max 10.0 (default: 3.0) Range 0.0-10.0. #### --denoise-sigma-range - **Syntax:** `--denoise-sigma-range F` - **Default:** `25.0` Bilateral filter range sigma (default: 25.0) #### --no-quality-verify - **Syntax:** `--no-quality-verify` - **Default:** — Disable SSIMULACRA2 quality verification Skips the SSIMULACRA2 measurement pass entirely, saving CPU at the risk of inconsistent visual quality. #### --target-ssimulacra2 - **Syntax:** `--target-ssimulacra2 SCORE` - **Default:** `70` Target SSIMULACRA2 score 0-100 (default: 70) Range 0-100. See [SSIMULACRA2 quality tuning](https://modpagespeed.com/docs/worker-configuration/#ssimulacra2-quality-tuning). #### --ssimulacra2-tolerance - **Syntax:** `--ssimulacra2-tolerance F` - **Default:** `5.0` Acceptable score deviation (default: 5.0) The band is asymmetric: `[target - 0.6 * tolerance, target + 1.6 * tolerance]`. See [SSIMULACRA2 quality tuning](https://modpagespeed.com/docs/worker-configuration/#ssimulacra2-quality-tuning). #### --no-learned-quality - **Syntax:** `--no-learned-quality` - **Default:** — Disable ML quality prediction Falls back to the heuristic quality calculation for every format. See [Learned quality prediction](https://modpagespeed.com/docs/worker-configuration/#learned-quality-prediction). #### --no-learned-quality-jpeg - **Syntax:** `--no-learned-quality-jpeg` - **Default:** — Disable ML prediction for JPEG See [Learned quality prediction](https://modpagespeed.com/docs/worker-configuration/#learned-quality-prediction). #### --no-learned-quality-webp - **Syntax:** `--no-learned-quality-webp` - **Default:** — Disable ML prediction for WebP See [Learned quality prediction](https://modpagespeed.com/docs/worker-configuration/#learned-quality-prediction). #### --no-learned-quality-avif - **Syntax:** `--no-learned-quality-avif` - **Default:** — Disable ML prediction for AVIF See [Learned quality prediction](https://modpagespeed.com/docs/worker-configuration/#learned-quality-prediction). #### --savedata-score-reduction - **Syntax:** `--savedata-score-reduction F` - **Default:** `15.0` Target SSIMULACRA2 reduction for Save-Data (default: 15.0) SSIMULACRA2 points subtracted from the target for Save-Data variants. #### --gzip-level - **Syntax:** `--gzip-level N` - **Default:** `6` Gzip compression level 1-9 (default: 6, 0=disable) Range 1-9; `0` disables gzip alternates. See [Pre-compressed text variants](https://modpagespeed.com/docs/worker-configuration/#pre-compressed-text-variants). #### --brotli-level - **Syntax:** `--brotli-level N` - **Default:** `6` Brotli compression quality 1-11 (default: 6, 0=disable) Range 1-11; `0` disables brotli alternates. See [Pre-compressed text variants](https://modpagespeed.com/docs/worker-configuration/#pre-compressed-text-variants). #### --no-css-import-flattening - **Syntax:** `--no-css-import-flattening` - **Default:** — Disable CSS @import flattening See [CSS import flattening](https://modpagespeed.com/docs/worker-configuration/#css-import-flattening). #### --mobile-width - **Syntax:** `--mobile-width PIXELS` - **Default:** `480` Mobile viewport resize width (default: 480, 0=disable) Images wider than the target are downscaled, preserving aspect ratio; images already smaller are not resized. `0` disables resizing for the viewport. See [Viewport resize widths](https://modpagespeed.com/docs/worker-configuration/#viewport-resize-widths). #### --tablet-width - **Syntax:** `--tablet-width PIXELS` - **Default:** `768` Tablet viewport resize width (default: 768, 0=disable) See [Viewport resize widths](https://modpagespeed.com/docs/worker-configuration/#viewport-resize-widths). #### --desktop-width - **Syntax:** `--desktop-width PIXELS` - **Default:** `0 (no resize)` Desktop viewport resize width (default: 0=no resize) The default `0` means desktop images are not resized. See [Viewport resize widths](https://modpagespeed.com/docs/worker-configuration/#viewport-resize-widths). #### --jpeg-quality - **Syntax:** `--jpeg-quality N` - **Default:** `85` JPEG output quality 1-100 (default: 85) Range 1-100. See [Image quality](https://modpagespeed.com/docs/worker-configuration/#image-quality-flags). #### --webp-quality - **Syntax:** `--webp-quality N` - **Default:** `75` WebP output quality 0-100 (default: 75) Range 0-100. See [Image quality](https://modpagespeed.com/docs/worker-configuration/#image-quality-flags). #### --avif-quality - **Syntax:** `--avif-quality N` - **Default:** `60` AVIF output quality 0-100 (default: 60) Range 0-100. See [Image quality](https://modpagespeed.com/docs/worker-configuration/#image-quality-flags). #### --savedata-jpeg-quality - **Syntax:** `--savedata-jpeg-quality N` - **Default:** `60` Save-Data JPEG quality (default: 60) Used when the request carries `Save-Data: on`. Range 1-100. #### --savedata-webp-quality - **Syntax:** `--savedata-webp-quality N` - **Default:** `50` Save-Data WebP quality (default: 50) Used when the request carries `Save-Data: on`. Range 0-100. #### --savedata-avif-quality - **Syntax:** `--savedata-avif-quality N` - **Default:** `45` Save-Data AVIF quality (default: 45) Used when the request carries `Save-Data: on`. Range 0-100. #### --max-url-length - **Syntax:** `--max-url-length BYTES` - **Default:** `8192` Max URL length (default: 8192) Notifications with longer URLs are rejected. #### --max-html-size - **Syntax:** `--max-html-size BYTES` - **Default:** `5242880` Max HTML size (default: 5242880) Larger HTML documents are skipped. #### --max-css-size - **Syntax:** `--max-css-size BYTES` - **Default:** `2097152` Max CSS size (default: 2097152) #### --max-js-size - **Syntax:** `--max-js-size BYTES` - **Default:** `2097152` Max JS size (default: 2097152) #### --max-image-size - **Syntax:** `--max-image-size BYTES` - **Default:** `10485760` Max image size (default: 10485760) #### --log-level - **Syntax:** `--log-level LEVEL` - **Default:** `info` Log level: debug|info|warning|error (default: info) ```bash factory_worker --log-level warning ``` #### --log-format - **Syntax:** `--log-format FORMAT` - **Default:** `text` Log format: text|json (default: text) ```bash factory_worker --log-format json ``` `text` is human-readable (`[INFO] message text`); `json` is one object per line (`{"timestamp":"...","level":"INFO","message":"..."}`) and is the better choice with log aggregation. #### --api-socket - **Syntax:** `--api-socket [PATH]` - **Default:** `/run/pagespeed-optimizer/api.sock` Serve the management API over a unix socket, mode 0660 (default path: /run/pagespeed-optimizer/api.sock) The recommended local transport: filesystem permission (group `pagespeed`) is the credential, the worker binds no TCP port, and no bearer token is asked for on the socket. See [HTTP management API](https://modpagespeed.com/docs/worker-configuration/#http-management-api). #### --api-port - **Syntax:** `--api-port PORT` - **Default:** `0 (disabled)` HTTP management API TCP port (default: 0=disabled) `0` keeps the TCP API off. `--api-socket` and `--api-port` are mutually exclusive: the worker serves exactly one transport. See [HTTP management API](https://modpagespeed.com/docs/worker-configuration/#http-management-api). #### --api-bind - **Syntax:** `--api-bind ADDRESS` - **Default:** `127.0.0.1` API bind address (default: 127.0.0.1) An IPv4 literal; `localhost`, `::1` and other IPv6 forms are rejected by name. A non-loopback bind also needs `--api-allow-remote` and a token. #### --api-allow-remote - **Syntax:** `--api-allow-remote` - **Default:** — Permit a non-loopback --api-bind (a token is still required) Confirms a deliberate non-loopback bind. Remote is never unauthenticated: a token is still required. See [One invariant, enforced at startup](https://modpagespeed.com/docs/worker-configuration/#one-invariant-enforced-at-startup). #### --api-no-auth - **Syntax:** `--api-no-auth` - **Default:** — Permit a tokenless API on loopback or the unix socket Confirms a deliberate tokenless API on loopback or the unix socket; the worker prints a warning banner at startup. #### --api-token - **Syntax:** `--api-token TOKEN` - **Default:** — API auth token (or set PAGESPEED_API_TOKEN env var) Prefer the `PAGESPEED_API_TOKEN` environment variable: anything on the command line is readable by any local user through `/proc//cmdline`. Package installs generate a token into `/etc/pagespeed-optimizer/daemon.env`. #### --api-read-open - **Syntax:** `--api-read-open` - **Default:** — Allow unauthenticated access to the allow-listed GET routes and the stats/events streams (public console reads; the log stays token-only) Opens an explicit allow-list of GET endpoints and WebSocket streams (the cached-URL inventory, origin hosts, the cooldown table, the live stats and events streams) without the token; the log endpoint and stream stay token-only. Use it only behind a reverse proxy that does its own authentication. #### --no-security-headers - **Syntax:** `--no-security-headers` - **Default:** — Omit security headers on console responses (reverse proxy handles them) Omit the security headers the worker otherwise adds to console responses, for deployments where a reverse proxy sets them. #### --console-dir - **Syntax:** `--console-dir PATH` - **Default:** — Web console SPA directory (optional) Path of the web console's static files. See [the admin console](https://modpagespeed.com/docs/admin-console/). #### --enable-browser-analysis - **Syntax:** `--enable-browser-analysis` - **Default:** `off` Enable browser-based analysis (default: off) Chrome (or `chrome-headless-shell`) must be available at `--chrome-binary`. See [Browser analysis](https://modpagespeed.com/docs/worker-configuration/#browser-analysis) and the [browser analysis guide](https://modpagespeed.com/docs/browser-analysis/). #### --browser-sandbox - **Syntax:** `--browser-sandbox MODE` - **Default:** `require` Headless Chrome sandbox: require|off (default: require; `require` refuses browser analysis rather than running an unsandboxed browser -- the worker keeps serving) There is no `auto`. With `require` the worker probes at startup and refuses browser analysis, rather than running an unsandboxed browser, when the sandbox is unavailable; the worker keeps serving without it. `off` is a deliberate opt-out and logs a warning at startup and on every browser start. See [Headless browser sandbox](https://modpagespeed.com/docs/worker-configuration/#headless-browser-sandbox). #### --browser-user-data-dir - **Syntax:** `--browser-user-data-dir PATH` - **Default:** `/chrome` Chrome profile directory (default: <runtime dir>/chrome) Chrome profile directory; defaults to a `chrome` directory under the worker's runtime directory. #### --chrome-binary - **Syntax:** `--chrome-binary PATH` - **Default:** `/usr/bin/chrome-headless-shell` Chrome executable path (default: /usr/bin/chrome-headless-shell) #### --chrome-recycle-interval - **Syntax:** `--chrome-recycle-interval N` - **Default:** `100` Pages before Chrome restart (default: 100) Chrome is restarted after this many pages to bound memory growth. See [Chrome memory management](https://modpagespeed.com/docs/worker-configuration/#chrome-memory-management). #### --chrome-page-timeout - **Syntax:** `--chrome-page-timeout MS` - **Default:** `60000` Per-page CDP timeout (default: 60000) #### --chrome-max-memory - **Syntax:** `--chrome-max-memory MB` - **Default:** `512` Chrome RSS kill threshold (default: 512) On Linux the worker watches Chrome's RSS through `/proc` and kills the process above this threshold; elsewhere only page-count recycling applies. #### --chrome-startup-timeout - **Syntax:** `--chrome-startup-timeout MS` - **Default:** `10000` Chrome startup timeout (default: 10000) #### --no-browser-critical-css - **Syntax:** `--no-browser-critical-css` - **Default:** — Disable browser CSS (keep heuristic) Keeps the heuristic critical-CSS extraction even when browser analysis runs. #### --no-browser-lazy-loading - **Syntax:** `--no-browser-lazy-loading` - **Default:** — Disable browser fold detection #### --no-browser-lcp-preload - **Syntax:** `--no-browser-lcp-preload` - **Default:** — Disable browser LCP detection #### --no-browser-image-sizing - **Syntax:** `--no-browser-image-sizing` - **Default:** — Disable browser image dimensions #### --browser-queue-size - **Syntax:** `--browser-queue-size N` - **Default:** `1000` Max pending analysis items (default: 1000) #### --browser-profile-ttl - **Syntax:** `--browser-profile-ttl SEC` - **Default:** `86400` Profile expiry in seconds (default: 86400) Optimization profiles expire after this many seconds and are re-analyzed. #### --allow-private-urls - **Syntax:** `--allow-private-urls` - **Default:** — Allow capture endpoints to target private/loopback URLs Off by default for security. Enable only in development, or when the worker has to analyze sites on private networks. #### --version - **Syntax:** `--version` - **Default:** — Show version and exit #### --help - **Syntax:** `--help` - **Default:** — Show this help ### Windows service [`--service`](https://modpagespeed.com/docs/worker-configuration/#--service), [`--log-file`](https://modpagespeed.com/docs/worker-configuration/#--log-file) #### --service - **Syntax:** `--service` - **Default:** — - **Platform:** Windows service only Run under the Service Control Manager Runs the worker under the Windows Service Control Manager; used by the IIS installer's service registration. #### --log-file - **Syntax:** `--log-file PATH` - **Default:** — - **Platform:** Windows service only With --service: append the log to PATH With `--service`: appends the log to the given file instead of standard error. ### Cache key normalization [`--strip-query-extensions`](https://modpagespeed.com/docs/worker-configuration/#--strip-query-extensions), [`--strip-query-groups`](https://modpagespeed.com/docs/worker-configuration/#--strip-query-groups), [`--strip-query-params`](https://modpagespeed.com/docs/worker-configuration/#--strip-query-params), [`--host-alias`](https://modpagespeed.com/docs/worker-configuration/#--host-alias) #### --strip-query-extensions - **Syntax:** `--strip-query-extensions EXT` - **Default:** — Comma-separated extensions (e.g., .jpg,.png,.css) ```bash factory_worker --strip-query-extensions css,js,png,jpg,webp ``` Consolidates cache entries for static assets that differ only by a cache-busting query string. See [URL normalization](https://modpagespeed.com/docs/worker-configuration/#url-normalization). #### --strip-query-groups - **Syntax:** `--strip-query-groups GROUPS` - **Default:** — Comma-separated group names (e.g., images,static) #### --strip-query-params - **Syntax:** `--strip-query-params PARAMS` - **Default:** — Comma-separated param names (e.g., utm_source,fbclid) ```bash factory_worker --strip-query-params utm_source,utm_medium,fbclid ``` #### --host-alias - **Syntax:** `--host-alias SRC=DST` - **Default:** — Host alias mapping (repeatable) ```bash factory_worker --host-alias www.example.com=example.com ``` Requests for the source host are treated as the destination host in cache lookups. Repeatable. ### SVG auto-vectorization [`--svg-mode`](https://modpagespeed.com/docs/worker-configuration/#--svg-mode), [`--svg-candidacy-threshold`](https://modpagespeed.com/docs/worker-configuration/#--svg-candidacy-threshold), [`--svg-max-pixels`](https://modpagespeed.com/docs/worker-configuration/#--svg-max-pixels), [`--svg-max-paths`](https://modpagespeed.com/docs/worker-configuration/#--svg-max-paths), [`--svg-max-svg-bytes`](https://modpagespeed.com/docs/worker-configuration/#--svg-max-svg-bytes), [`--svg-fidelity-threshold`](https://modpagespeed.com/docs/worker-configuration/#--svg-fidelity-threshold), [`--svg-exclude-lcp`](https://modpagespeed.com/docs/worker-configuration/#--svg-exclude-lcp), [`--svg-timeout-ms`](https://modpagespeed.com/docs/worker-configuration/#--svg-timeout-ms), [`--svg-preset`](https://modpagespeed.com/docs/worker-configuration/#--svg-preset), [`--svg-color-precision`](https://modpagespeed.com/docs/worker-configuration/#--svg-color-precision), [`--svg-filter-speckle`](https://modpagespeed.com/docs/worker-configuration/#--svg-filter-speckle) #### --svg-mode - **Syntax:** `--svg-mode MODE` - **Default:** `detect` detect, preview, or auto (default: detect) Start with `detect` to see which images qualify, move to `preview` to inspect the stored SVGs, then `auto` to serve them. See [SVG auto-vectorization](https://modpagespeed.com/docs/worker-configuration/#svg-auto-vectorization). #### --svg-candidacy-threshold - **Syntax:** `--svg-candidacy-threshold N` - **Default:** `50` Score threshold 0-100 (default: 50) #### --svg-max-pixels - **Syntax:** `--svg-max-pixels N` - **Default:** `65536` Max decoded pixels (default: 65536) #### --svg-max-paths - **Syntax:** `--svg-max-paths N` - **Default:** `500` Max <path> elements (default: 500) #### --svg-max-svg-bytes - **Syntax:** `--svg-max-svg-bytes N` - **Default:** `262144` Max uncompressed SVG bytes (default: 262144) #### --svg-fidelity-threshold - **Syntax:** `--svg-fidelity-threshold F` - **Default:** `55.0` SSIMULACRA2 minimum (default: 55.0) [reserved] Reserved for a later release; accepted but not yet applied. #### --svg-exclude-lcp - **Syntax:** `--svg-exclude-lcp BOOL` - **Default:** `true` Skip LCP images (default: true) Enabled by default because SVG render cost (path tessellation in the browser) can regress LCP for hero images. Set it to `false` when your LCP images are simple graphics that benefit from vectorization. #### --svg-timeout-ms - **Syntax:** `--svg-timeout-ms N` - **Default:** `500` Vectorization timeout (default: 500) [reserved] Reserved for a later release; accepted but not yet applied. #### --svg-preset - **Syntax:** `--svg-preset N` - **Default:** `1` 0=bw, 1=poster, 2=photo (default: 1) [reserved] Reserved for a later release; accepted but not yet applied. #### --svg-color-precision - **Syntax:** `--svg-color-precision N` - **Default:** `0` 0=adaptive, 1-8=fixed (default: 0) #### --svg-filter-speckle - **Syntax:** `--svg-filter-speckle N` - **Default:** `4` Min cluster area (default: 4) ### Agent optimize (experimental, off by default) [`--agent-optimize`](https://modpagespeed.com/docs/worker-configuration/#--agent-optimize), [`--agent-optimize-paths`](https://modpagespeed.com/docs/worker-configuration/#--agent-optimize-paths), [`--agent-optimize-llms-txt`](https://modpagespeed.com/docs/worker-configuration/#--agent-optimize-llms-txt), [`--agent-optimize-sitemap-url`](https://modpagespeed.com/docs/worker-configuration/#--agent-optimize-sitemap-url), [`--[no-]agent-optimize-respect-ai-directives`](https://modpagespeed.com/docs/worker-configuration/#--no-agent-optimize-respect-ai-directives), [`--agent-optimize-llms-summary-fetch-cap`](https://modpagespeed.com/docs/worker-configuration/#--agent-optimize-llms-summary-fetch-cap), [`--agent-optimize-cache-ttl`](https://modpagespeed.com/docs/worker-configuration/#--agent-optimize-cache-ttl), [`--agent-render-allow-hosts`](https://modpagespeed.com/docs/worker-configuration/#--agent-render-allow-hosts) #### --agent-optimize - **Syntax:** `--agent-optimize` - **Default:** — Serve a rendered-markdown variant to AI agents (Accept: text/markdown). Behavior may change. Experimental; behavior may change between releases. See [Agent optimize](https://modpagespeed.com/docs/agent-optimize/). #### --agent-optimize-paths - **Syntax:** `--agent-optimize-paths LIST` - **Default:** — Comma-separated path prefixes to enable #### --agent-optimize-llms-txt - **Syntax:** `--agent-optimize-llms-txt` - **Default:** — Publish a synthesized /llms.txt site index (implies --agent-optimize) #### --agent-optimize-sitemap-url - **Syntax:** `--agent-optimize-sitemap-url URL` - **Default:** — Sitemap to build /llms.txt from #### --[no-]agent-optimize-respect-ai-directives - **Syntax:** `--[no-]agent-optimize-respect-ai-directives` - **Default:** `on` Honor robots AI rules (default: on) #### --agent-optimize-llms-summary-fetch-cap - **Syntax:** `--agent-optimize-llms-summary-fetch-cap N` - **Default:** `200` Max summary fetches (default: 200) #### --agent-optimize-cache-ttl - **Syntax:** `--agent-optimize-cache-ttl SEC` - **Default:** `86400` /llms.txt cache TTL (default: 86400) #### --agent-render-allow-hosts - **Syntax:** `--agent-render-allow-hosts HOSTS` - **Default:** `none` Third-party hosts the agent render may fetch: comma-separated, exact host names (no wildcards), still SSRF-guarded (default: none) ### Web Bot Auth (observe-only, off by default) [`--web-bot-auth`](https://modpagespeed.com/docs/worker-configuration/#--web-bot-auth), [`--web-bot-auth-key-directory`](https://modpagespeed.com/docs/worker-configuration/#--web-bot-auth-key-directory), [`--web-bot-auth-verified-bots`](https://modpagespeed.com/docs/worker-configuration/#--web-bot-auth-verified-bots), [`--web-bot-auth-public-counter`](https://modpagespeed.com/docs/worker-configuration/#--web-bot-auth-public-counter) #### --web-bot-auth - **Syntax:** `--web-bot-auth` - **Default:** — Classify RFC 9421-signed agent requests (label + counter only; never changes request handling) Observe-only: labels and counts signed agent requests and never changes request handling. See [Web Bot Auth](https://modpagespeed.com/docs/web-bot-auth/). #### --web-bot-auth-key-directory - **Syntax:** `--web-bot-auth-key-directory URL` - **Default:** — https JWKS key-directory URL to warm-fetch periodically (repeatable) #### --web-bot-auth-verified-bots - **Syntax:** `--web-bot-auth-verified-bots LIST` - **Default:** — keyid=name pairs (comma-separated) promoting a verified signature to a named bot #### --web-bot-auth-public-counter - **Syntax:** `--web-bot-auth-public-counter MODE` - **Default:** — opt-in verified-crawl counter (experimental): off (default) | private | public. Enabling a non-off mode publishes a discoverable marker at /.well-known/webbotauth-counter. The exact doc is gated by the PAGESPEED_WEB_BOT_AUTH_COUNTER_TOKEN env bearer token. ## Proactive variant generation When the worker receives an image notification, it can generate multiple variants from a single decode pass. This avoids decoding the same image repeatedly for different client types. Each dimension can be independently enabled or disabled: [`--proactive-image-variants`](https://modpagespeed.com/docs/worker-configuration/#--proactive-image-variants), [`--no-proactive-viewport-variants`](https://modpagespeed.com/docs/worker-configuration/#--no-proactive-viewport-variants), [`--no-proactive-savedata-variants`](https://modpagespeed.com/docs/worker-configuration/#--no-proactive-savedata-variants) and [`--no-proactive-density-variants`](https://modpagespeed.com/docs/worker-configuration/#--no-proactive-density-variants). Save-Data variants use lower compression quality to reduce bandwidth: | Format | Normal quality | Save-Data quality | | ------ | -------------- | ----------------- | | JPEG | 85 | 60 | | WebP | 75 | 50 | | AVIF | 60 | 45 | These quality levels can be overridden at runtime with the [image quality flags](https://modpagespeed.com/docs/worker-configuration/#image-quality-flags). ### Variant matrix With all proactive flags enabled, a single image notification can produce up to: - 3 formats (WebP, AVIF, optimized original) - 3 viewports (Mobile, Tablet, Desktop) - 2 Save-Data states (off, on) - 2 pixel densities (1x, 2x+) That is up to **37 variants** (36 raster plus 1 SVG for eligible images) from a single decode pass. In practice, many of these already exist in the cache and are skipped, so the actual number of new writes is typically much smaller. ### Viewport resize widths [`--mobile-width`](https://modpagespeed.com/docs/worker-configuration/#--mobile-width), [`--tablet-width`](https://modpagespeed.com/docs/worker-configuration/#--tablet-width) and [`--desktop-width`](https://modpagespeed.com/docs/worker-configuration/#--desktop-width) set the target width for viewport-based image resizing. Images wider than the target are downscaled (preserving aspect ratio). Images already smaller than the target are not resized. ```bash factory_worker --mobile-width 480 --tablet-width 768 --desktop-width 0 ``` ## URL normalization [`--strip-query-extensions`](https://modpagespeed.com/docs/worker-configuration/#--strip-query-extensions), [`--strip-query-groups`](https://modpagespeed.com/docs/worker-configuration/#--strip-query-groups), [`--strip-query-params`](https://modpagespeed.com/docs/worker-configuration/#--strip-query-params) and [`--host-alias`](https://modpagespeed.com/docs/worker-configuration/#--host-alias) normalize the cache key: query strings that only bust caches and host aliases that serve the same content collapse onto one cache entry. ## Image quality [`--jpeg-quality`](https://modpagespeed.com/docs/worker-configuration/#--jpeg-quality), [`--webp-quality`](https://modpagespeed.com/docs/worker-configuration/#--webp-quality) and [`--avif-quality`](https://modpagespeed.com/docs/worker-configuration/#--avif-quality) override the default encoding quality at runtime for all image transcoding the worker performs; [`--savedata-jpeg-quality`](https://modpagespeed.com/docs/worker-configuration/#--savedata-jpeg-quality), [`--savedata-webp-quality`](https://modpagespeed.com/docs/worker-configuration/#--savedata-webp-quality) and [`--savedata-avif-quality`](https://modpagespeed.com/docs/worker-configuration/#--savedata-avif-quality) are used when the request includes `Save-Data: on`. ```bash factory_worker --cache-path /data/cache.vol \ --jpeg-quality 80 --webp-quality 70 --avif-quality 55 \ --savedata-jpeg-quality 55 --savedata-webp-quality 40 --savedata-avif-quality 40 ``` ## Learned quality prediction Per-format ML models predict the optimal encoder quality parameter for a target SSIMULACRA2 score. The models are trained LightGBM decision trees compiled to C at build time — zero runtime dependencies, ~5 microsecond inference per format. When enabled, the worker extracts 16 image features (edge density, noise level, color entropy, spatial frequency, luminance, etc.) from the decoded pixels and predicts the encoder quality that hits the configured `target_ssimulacra2` score. SSIMULACRA2 verification still runs as a safety net: if the predicted quality produces a score outside the tolerance band, the worker re-encodes. When disabled ([`--no-learned-quality`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality), or per format with [`--no-learned-quality-jpeg`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality-jpeg), [`--no-learned-quality-webp`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality-webp) and [`--no-learned-quality-avif`](https://modpagespeed.com/docs/worker-configuration/#--no-learned-quality-avif)) or when a model returns an invalid prediction (e.g., the AVIF model is not yet trained), the worker falls back to the existing heuristic quality calculation based on content class and base quality. [`--savedata-score-reduction`](https://modpagespeed.com/docs/worker-configuration/#--savedata-score-reduction) sets how many SSIMULACRA2 points Save-Data variants give up. ```bash # Disable learned quality for AVIF (stub model), keep JPEG and WebP factory_worker --cache-path /data/cache.vol --no-learned-quality-avif # Disable all learned quality, fall back to heuristic factory_worker --cache-path /data/cache.vol --no-learned-quality ``` ## SSIMULACRA2 quality tuning The worker uses SSIMULACRA2 perceptual quality scoring to verify that encoded images meet a target visual quality. [`--target-ssimulacra2`](https://modpagespeed.com/docs/worker-configuration/#--target-ssimulacra2) sets the target score and [`--ssimulacra2-tolerance`](https://modpagespeed.com/docs/worker-configuration/#--ssimulacra2-tolerance) the band around it. When verification is enabled (the default), the worker encodes at the predicted or configured quality level, then measures the actual SSIMULACRA2 score. If the score falls outside the asymmetric tolerance band `[target - 0.6*tolerance, target + 1.6*tolerance]`, the worker re-encodes with adjusted quality. Disabling verification ([`--no-quality-verify`](https://modpagespeed.com/docs/worker-configuration/#--no-quality-verify)) skips the SSIMULACRA2 measurement pass entirely, reducing CPU cost at the risk of inconsistent visual quality. ## Content analysis and denoising The worker classifies image content (photo, screenshot, illustration, noisy) and applies content-aware encoding presets. A bilateral filter denoises images that exceed the noise threshold before encoding, improving compression efficiency. The flags are [`--no-content-analysis`](https://modpagespeed.com/docs/worker-configuration/#--no-content-analysis), [`--denoise-threshold`](https://modpagespeed.com/docs/worker-configuration/#--denoise-threshold), [`--denoise-sigma-spatial`](https://modpagespeed.com/docs/worker-configuration/#--denoise-sigma-spatial) and [`--denoise-sigma-range`](https://modpagespeed.com/docs/worker-configuration/#--denoise-sigma-range). Content analysis is fast (runs on the already-decoded pixel buffer) and feeds into both the learned quality model and the denoising decision. Disabling it falls back to the `Unknown` content class for all images. ## HTML transforms The HTML transforms are on by default and switched off individually with [`--no-lazy-load-images`](https://modpagespeed.com/docs/worker-configuration/#--no-lazy-load-images), [`--no-image-dimensions`](https://modpagespeed.com/docs/worker-configuration/#--no-image-dimensions), [`--no-lcp-preload`](https://modpagespeed.com/docs/worker-configuration/#--no-lcp-preload), [`--no-preconnect-injection`](https://modpagespeed.com/docs/worker-configuration/#--no-preconnect-injection), [`--no-async-css`](https://modpagespeed.com/docs/worker-configuration/#--no-async-css) and [`--no-css-import-flattening`](https://modpagespeed.com/docs/worker-configuration/#--no-css-import-flattening); [`--enable-speculation-rules`](https://modpagespeed.com/docs/worker-configuration/#--enable-speculation-rules) switches on the one transform that is off by default. Script deferral has no flag of its own: it runs as part of HTML optimization and is governed by browser script analysis. Lazy loading skips the LCP candidate image (which gets `fetchpriority="high"` instead), the first 3 body images when an LCP candidate is identified, and the first iframe in the document body (typically an above-the-fold video or media embed). Invisible images — 1x1 tracking pixels, `hidden` or `display:none` elements — are left untouched entirely: never promoted, never lazy-loaded. LCP preload injects a `` tag in the `` and writes the URL to the Early Hints cache sentinel, so nginx can emit `103 Early Hints` or `Link` response headers on subsequent requests. Preconnect injection detects third-party origins from external resources in the HTML and writes `preconnect:` hints to the Early Hints sentinel. The hint carries `crossorigin` exactly when the resource that motivated it is fetched in CORS mode (fonts, `crossorigin`-marked resources, ES modules), so the warmed connection is the one the browser actually reuses. Async CSS loading makes render-blocking `` tags non-blocking. Each link is switched to `rel="preload" as="style"` so it downloads at normal priority without blocking first paint; a small same-origin loader script turns it back into a stylesheet, with its original media, once the sheet has loaded. Because it is a standard preload, the deferred stylesheet is also announced in early hints. The loader is served at a content-hashed path under `/pagespeed_static/` (for example `/pagespeed_static/async_css..js`; the hash changes whenever the loader script changes, so the front-end serves it with an immutable, year-long cache and a loader update lands as a fresh URL). It is referenced with an external ` ``` #### When it helps and when it does not It helps on legacy or machine-generated pages where stylesheets ended up interleaved with or after scripts: template fragments that each carry their own ``, or ad and widget snippets injecting CSS late in the body. On pages whose CSS already sits in `` with scripts at the end of ``, there is nothing after any script to move and the filter changes nothing. The stylesheets keep their order among themselves, so the cascade is unchanged; what changes is where the group sits relative to the script. #### How it decides The first ``. On pages whose HTML is served many times between deploys that small saving repeats on every serve, which is where the filter earns its place. ### Risks - The minifier never renames identifiers; the historical failure mode is a script that inspects its own source text, for example through `Function.prototype.toString()`, and reacts to the changed formatting. - Verify with the `X-Mod-Pagespeed` response header and a `?PageSpeedFilters=-rewrite_javascript` comparison; [Is it working?](https://modpagespeed.com/docs/is-it-working/) has the steps. - `rewrite_javascript` ignores the deprecated `UseExperimentalJsMinifier` directive, which is accepted for compatibility and logs a warning at configuration load (`ModPagespeedUseExperimentalJsMinifier` on Apache, `pagespeed UseExperimentalJsMinifier` on nginx). Remove it from your configuration. ### Configuration **Apache:** ```apache ModPagespeedEnableFilters rewrite_javascript ``` **Nginx:** ```nginx pagespeed EnableFilters rewrite_javascript; ``` ## combine_javascript [Full guide →](https://modpagespeed.com/docs/filters/combine_javascript/) ### What it does `combine_javascript` concatenates consecutive external scripts into one file, loads the combined file from a `.pagespeed.jc.` URL, and replaces each original tag with a small inline script, `eval(…)`, that runs that member in order. A page that loads five scripts back to back makes one request instead of five. The scripts run in their original order, so dependencies between them keep working. Live demo: [combine_javascript](https://modpagespeed.com/examples/combine_javascript/). ```text ``` ### When it helps and when it does not Combining was designed for HTTP/1.1, where a browser opens only a few connections per host and extra requests queue. Over HTTP/2 and HTTP/3 requests multiplex over one connection, so the saving shrinks to per-request overhead. The costs cut the other way too: the combined file is refetched in full when any member changes, and the browser cannot run the first script until the whole combined file has arrived. On a legacy page loading a dozen small files, combining still pays. On a page with two or three scripts over HTTP/2, measure with the filter on and off before keeping it. ### How it decides Only consecutive, synchronously executing external scripts join a group. An inline ` ``` ### When it helps and when it does not Inlining pays when a script is tiny: for a few hundred bytes, the request with its headers and round trip costs more than the bytes it fetches. The trade runs the other way as files grow or get shared. An inlined script is not cached on its own, so it downloads again with every page view, and a file inlined into ten pages is transferred ten times. Scripts that several pages share, and anything well above the default threshold, are better served external with a long cache lifetime. `inline_javascript` is a CoreFilter, so this trade is already live on a default install; the threshold is the knob. ### How it decides Only external scripts whose contents are no larger than `JsInlineMaxBytes` (default 2048 bytes) qualify, and only files on domains the module is authorized to fetch. A script with `async` or `defer`, or with the IE-specific `for` and `event` attributes, is left external: those attributes change when the script runs, and an inline block cannot express that timing. Module scripts (`type="module"`) are never inlined, since inlining would change how their relative imports resolve. Nothing is inlined when the page's Content-Security-Policy forbids inline scripts. Everything else about the element, including its position in the document, stays as authored. ### Risks - The page grows by the script's size on every view, so keep `JsInlineMaxBytes` small. Raising it to inline a large file usually costs more than the saved request returns. - Verify with the `X-Mod-Pagespeed` response header and a `?PageSpeedFilters=-inline_javascript` comparison; [Is it working?](https://modpagespeed.com/docs/is-it-working/) has the steps. ### Configuration **Apache:** ```apache ModPagespeedEnableFilters inline_javascript ModPagespeedJsInlineMaxBytes 2048 ``` **Nginx:** ```nginx pagespeed EnableFilters inline_javascript; pagespeed JsInlineMaxBytes 2048; ``` ## defer_javascript [Full guide →](https://modpagespeed.com/docs/filters/defer_javascript/) Not a core filter. Test thoroughly before enabling. Defers execution of all JavaScript until after the page finishes loading. This can dramatically improve initial render time but will break scripts that rely on executing during page parse (e.g., `document.write`). **Apache:** ```apache ModPagespeedEnableFilters defer_javascript ``` **Nginx:** ```nginx pagespeed EnableFilters defer_javascript; ``` ### Risks - Scripts using `document.write` will fail. - Scripts that expect to run before `DOMContentLoaded` may break. - Order-dependent scripts may execute in unexpected order. - Inserts a `