This document describes the configuration used by:
pwa-check audit https://example.com
For pipeline setup and authentication, see Integrating PWA Today Audits into CI/CD. For direct HTTP integration, see the Runtime Audit API Reference. For provider-specific deployment scripts, see Service Worker Deployment Testing.
Configuration file discovery
The CLI looks in its current working directory for the first available file in this order:
pwa-check.ymlpwa-check.yamlpwa-check.json
Select another file with:
pwa-check audit --config config/production-audit.yml https://example.com
Paths in reports and the service worker deployment command are resolved
relative to the directory in which the CLI runs.
Top-level structure
version: 1
audit:
profile: standard
applicationId: example.com
allowedOrigins: []
include: []
exclude: []
options: {}
qualityGate:
minimumScore: 90
failOn:
- critical
- high
failOnWarnings: true
reports:
json: reports/pwa-audit.json
junit: reports/pwa-audit.xml
| Field | Required | Description |
|---|---|---|
version |
Yes | Configuration format version. It must be 1. |
audit |
No | Check selection and per-check options. |
qualityGate |
No | Conditions that determine the CLI exit code. |
reports |
No | JSON and JUnit report output paths. |
If no configuration file exists, the CLI uses version 1, the standard
profile, the API’s default quality gate, and no report files.
version
The only supported value is:
version: 1
The CLI rejects files without version: 1.
audit
audit.profile
Selects the initial set of checks:
audit:
profile: standard
Supported profiles:
| Profile | Checks |
|---|---|
quick |
manifest, service-worker-first-installation, service-worker-handlers |
standard |
Everything in quick, plus offline, offline-navigation, service-worker-update, and before-install-prompt |
full |
Every runtime check except service-worker-deployment |
custom |
Only checks listed under include |
The default profile is standard.
The hosted Runtime Audit API also applies the customer entitlement. The
complimentary trial and Developer plan accept the standard profile with one
or more Standard checks selected. Team and Business dashboard configurations may
select any check from the Full runtime suite except
service-worker-deployment; complete release audits use the exact
full profile with service-worker-deployment included. Other
profiles remain useful for local checks, but the API returns a structured
entitlement error if they do not match the active plan.
Some selected checks require options. If their required options are missing,
they return not-applicable. The exception is
service-worker-deployment: when explicitly selected, its missing local
command is a CLI configuration error.
audit.applicationId
Identifies the Application that owns the audit history:
audit:
applicationId: example.com
If omitted, the audited hostname is used. An Application ID must:
- Be the verified Application hostname in the customer console.
- Match the hostname of the audited URL.
- Contain only letters, numbers, dots, or dashes.
audit.allowedOrigins
By default, the audit browser can load only the audited PWA origin. Add an origin here only when the PWA needs an essential script, stylesheet, font, image, or API from another host:
audit:
allowedOrigins:
- https://cdn.example.com
- https://api.example.com
Each entry must be a public HTTPS origin without a path or query string. The audit validates and pins each origin before the browser starts, so an entry cannot resolve to a private network address during the audit. Same-origin PWAs do not need this setting. You can configure at most 10 additional origins.
audit.include
Adds checks to a profile:
audit:
profile: quick
include:
- offline
For custom, include defines the entire check set and must contain at least
one check:
audit:
profile: custom
include:
- manifest
- offline
Duplicate check IDs are removed.
audit.exclude
Removes checks after the profile and include list have been combined:
audit:
profile: full
exclude:
- push-notifications
If a check appears in both include and exclude, it is excluded.
Stable check IDs
| Check ID | Severity | Required options |
|---|---|---|
manifest |
critical |
None |
offline |
critical |
None |
cache |
high |
routes |
offline-navigation |
high |
series |
service-worker-first-installation |
critical |
None |
service-worker-handlers |
high |
None |
service-worker-update |
high |
None |
service-worker-deployment |
critical |
Local command; the CLI supplies the API testId |
before-install-prompt |
medium |
None |
offline-request-retry |
high |
requests |
push-notifications |
high |
payload |
Unknown check IDs are rejected.
audit.options
Options are grouped by stable check ID:
audit:
options:
offline-navigation:
series:
- [/, /products, /checkout]
Do not put credentials, authorization headers, cookies, passwords, API keys, private keys, client secrets, or tokens in check options. Sensitive option names are rejected by the API, and the audit configuration is stored with the audit record.
Common browser timeout
Most checks support:
audit:
options:
manifest:
timeout: 20000
timeout is a navigation timeout in milliseconds. The default is 15000.
Increasing it can help applications that take longer to reach the browser’s
network-idle state.
manifest
audit:
options:
manifest:
timeout: 20000
The check:
- Loads the page in a browser.
- Resolves the manifest from the rendered document.
- Runs the static
pwa-checkmanifest rules. - Loads icons and screenshots to verify their actual dimensions.
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
Number | 15000 |
Page navigation and manifest fetch timeout in milliseconds. |
offline
audit:
options:
offline:
offlineUrls:
- /
- /products
expectedSelectors:
- main
- h1
requiredText:
- Example Store
minBodyTextLength: 20
minHtmlLength: 1000
timeout: 20000
This check loads each URL online, confirms that a service worker controls it, reloads it offline, and compares the online and offline documents.
| Option | Type | Default | Description |
|---|---|---|---|
offlineUrls |
Array of URLs | Audited URL | URLs to reload offline. Relative URLs resolve against the audited URL. |
expectedSelectors |
Array of strings | [] |
Selectors that must be present online and offline. |
requiredText |
Array of strings | [] |
Text that must be present in the offline document. |
minBodyTextLength |
Number | 20 |
Minimum acceptable offline body-text length. |
minHtmlLength |
Number | 1000 |
Minimum acceptable offline HTML length. |
timeout |
Number | 15000 |
Navigation timeout in milliseconds. |
offline-navigation
audit:
options:
offline-navigation:
series:
- - /
- /products
- /checkout
- - /
- /account
expectedSelectors:
- main
requiredText:
- Example Store
timeout: 20000
series is required. Each nested array is one navigation sequence. The check
visits every URL in the sequence online and then repeats the sequence offline.
Relative URLs resolve against the audited URL.
Use multiple sequences to test independent navigation paths:
series:
- [/, /products, /products/featured]
- [/, /help, /contact]
| Option | Type | Default | Description |
|---|---|---|---|
series |
Array of URL arrays | Required | Online and offline navigation sequences. |
expectedSelectors |
Array of strings | [] |
Selectors expected on each tested page. |
requiredText |
Array of strings | [] |
Text expected on each offline page. |
timeout |
Number | 15000 |
Navigation timeout in milliseconds. |
cache
audit:
options:
cache:
routes:
- url: /
readySelector: '#home-title'
- url: /audit/
readySelector: '#audit-title'
privateResponseAllowlist:
- /offline-profile
growthTolerance: 0
cacheSettleTimeout: 10000
cacheQuietPeriod: 1000
timeout: 20000
routes is required. The audit opens every route twice online, waiting for its
readySelector to contain text each time. It verifies that Cache Storage stops
growing after the second pass, rejects cached private or no-store responses,
and then opens every configured route in a fresh offline tab.
Use a route-specific readySelector that represents rendered page content, not
an empty application shell. Relative URLs resolve against the audited URL.
| Option | Type | Default | Description |
|---|---|---|---|
routes |
Array of { url, readySelector } objects |
Required | Routes to exercise online and cold-start offline. |
routes[].url |
URL | Required | Relative or absolute URL for the route. |
routes[].readySelector |
Selector string | Required | Element that must exist and contain text after the route renders. |
privateResponseAllowlist |
Array of paths | [] |
Exact pathnames allowed to cache despite private-response signals. |
growthTolerance |
Number | 0 |
Additional cache entries permitted after the second route pass. |
cacheSettleTimeout |
Number | 10000 |
Maximum time to wait for cache writes to settle after each pass. |
cacheQuietPeriod |
Number | 1000 |
Duration for which the entry count must remain unchanged. |
timeout |
Number | 15000 |
Navigation and render-readiness timeout in milliseconds. |
service-worker-first-installation
audit:
options:
service-worker-first-installation:
timeout: 20000
The check starts with a clean browser profile, waits up to 10 seconds for the first service worker to become ready, reloads the page, and verifies that the worker controls it.
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
Number | 15000 |
Page navigation timeout in milliseconds. |
The 10-second serviceWorker.ready limit is fixed separately from the
navigation timeout.
service-worker-handlers
audit:
options:
service-worker-handlers:
timeout: 20000
The check resolves the active service worker at runtime, loads its imported scripts, and checks the required handlers:
installactivatefetchpushnotificationclick
It also checks lifecycle behavior such as waitUntil, self.skipWaiting(),
and self.clients.claim().
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
Number | 15000 |
Page navigation timeout in milliseconds. |
service-worker-update
audit:
options:
service-worker-update:
timeout: 20000
The check installs the current service worker, requests a cache-busted version of its script, and verifies that the browser detects and installs the simulated update.
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
Number | 15000 |
Navigation and simulated-update timeout in milliseconds. |
service-worker-deployment
This check is never selected automatically, including by the full profile.
It must appear in include:
audit:
profile: full
include:
- service-worker-deployment
options:
service-worker-deployment:
deploymentTimeout: 900000
commandTimeout: 900000
command:
- ./scripts/deploy-and-wait.sh
requiredCachedUrls:
- /
- /offline
contentCheckUrls:
- /
- /app.js
The CLI first asks the hosted deployment check to capture a baseline. It then
runs command, waits for it to finish, signals deployment completion, and
waits for the service worker verification result.
See Service Worker Deployment Testing for complete Vercel, Netlify, and AWS Amplify Hosting scripts.
Local-only options:
| Option | Type | Default | Description |
|---|---|---|---|
command |
Non-empty array of strings | Required | Executable followed by its arguments. |
commandTimeout |
Number | deploymentTimeout |
Maximum local command duration in milliseconds. |
command is executed without a shell. This is correct:
command:
- ./scripts/deploy-and-wait.sh
Arguments are separate array entries:
command:
- ./scripts/deploy-and-wait.sh
- production
Shell syntax is not interpreted inside an entry. Put pipes, redirects, and multiple shell commands inside the script.
Hosted deployment options:
| Option | Type | Default | Description |
|---|---|---|---|
deploymentTimeout |
Number | 600000 |
Maximum time to establish the baseline, coordinate deployment, and observe the deployed change. |
navigationTimeout |
Number | 15000 |
Navigation and resource-probe timeout. |
updateTimeout |
Number | 30000 |
Maximum time to observe the service worker update after a worker change is detected. |
activationGracePeriod |
Number | 1000 |
Delay before checking activation behavior. |
pollInterval |
Number | 3000 |
Interval between hosted deployment observations. |
stableObservations |
Number | 2 |
Consecutive matching observations required before the deployment is considered stable. |
requiredCachedUrls |
Array of URLs | [] |
URLs that must remain present in Cache Storage after deployment. |
contentCheckUrls |
Array of URLs | [] |
Cached URLs whose response content should be compared across deployment. |
All timeout values are milliseconds. The deployment must produce a changed service worker file; otherwise the update cannot be verified.
Do not configure testId manually. The CLI creates the deployment test and
replaces the local deployment options with the resulting testId when it
creates the aggregate runtime audit.
before-install-prompt
audit:
options:
before-install-prompt:
timeout: 20000
The check observes the beforeinstallprompt event while loading, interacting
with, and reloading the page.
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
Number | 15000 |
Page navigation timeout in milliseconds. |
offline-request-retry
audit:
options:
offline-request-retry:
requests:
- requestUrl: https://example.com/api/messages
method: POST
requestBody:
message: Audit test request
retryTimeout: 8000
offlineSettleTime: 1000
timeout: 20000
The check takes the browser offline, sends every configured request from the page, restores connectivity, and observes whether the service worker retries each request. It passes only when all configured requests are observed offline and retried online.
| Option | Type | Default | Description |
|---|---|---|---|
requests[].requestUrl |
URL | Required | One or more requests expected to be queued and retried. Relative URLs resolve against the audited URL. |
requests[].method |
GET or POST |
Required | HTTP method to test. |
requests[].requestBody |
Any JSON value | None | JSON body for a POST request. It is not allowed for GET. |
retryTimeout |
Number | 8000 |
Time to wait for the retried request after restoring connectivity. |
offlineSettleTime |
Number | 1000 |
Delay after switching the browser offline. |
timeout |
Number | 15000 |
Page navigation timeout in milliseconds. |
Use a dedicated test endpoint and test data. The check can cause a real request to reach the configured endpoint.
push-notifications
The check supports synthetic and real delivery.
Synthetic delivery does not contact an application push server:
audit:
options:
push-notifications:
payload:
title: PWA audit
message: Synthetic test notification
Real delivery creates a new browser push subscription and calls a customer endpoint:
audit:
options:
push-notifications:
applicationServerKey: YOUR_PUBLIC_VAPID_KEY
triggerUrl: https://example.com/api/send-audit-push
payload:
title: PWA audit
message: Real test notification
pushSubscription: $subscription
observationTimeout: 8000
timeout: 20000
If the application stores subscriptions separately, configure
subscriptionUrl:
push-notifications:
applicationServerKey: YOUR_PUBLIC_VAPID_KEY
subscriptionUrl: https://example.com/api/push-subscriptions
triggerUrl: https://example.com/api/send-audit-push
payload:
title: PWA audit
message: Real test notification
| Option | Type | Default | Description |
|---|---|---|---|
payload |
String, object, or array | Required | Push data or the JSON request body sent to triggerUrl. |
triggerUrl |
Absolute URL | None | Enables real push delivery and receives the trigger request. |
applicationServerKey |
String | Required with triggerUrl |
Public VAPID application server key used to create the subscription. |
subscriptionUrl |
Absolute URL | None | Optional endpoint that receives the subscription before triggerUrl is called. |
observationTimeout |
Number | 8000 |
Time to observe registration and notification behavior. |
timeout |
Number | 15000 |
Page navigation timeout in milliseconds. |
For real delivery, every value equal to the exact string $subscription inside
payload is replaced recursively with the generated subscription. If there is
no placeholder, triggerUrl receives only the configured payload.
The audit request sends the audited application’s origin in the HTTP Origin
header when calling subscriptionUrl and triggerUrl. These endpoints must
accept that origin.
The check creates a fresh subscription for the run and unsubscribes it during cleanup.
qualityGate
qualityGate:
minimumScore: 90
failOn:
- critical
- high
qualityGate.minimumScore
A number from 0 to 100. The default is 90.
The score is:
passed checks / scored checks × 100
Statuses included in the score:
passedfailedwarning
not-applicable, skipped, and error are not scored.
qualityGate.failOn
An array containing any of:
criticalhighmediumlow
The default is:
failOn:
- critical
- high
The quality gate fails when either:
- The score is below
minimumScore. - A
failedcheck has a severity listed infailOn.
Warnings do not trigger failOn, although they lower the score because they
are scored but not counted as passed.
qualityGate.failOnWarnings
A boolean that defaults to false. When true, any warning causes the
quality gate to fail.
Infrastructure errors produce an audit status of failed or
partially-completed. The CLI returns its service-error exit code independently
of the quality gate.
reports
reports:
json: reports/pwa-audit.json
junit: reports/pwa-audit.xml
| Field | Description |
|---|---|
json |
Writes the complete audit and ordered results as formatted JSON. |
junit |
Writes one JUnit test case for each runtime check. |
Directories are created automatically. Paths are relative to the CLI working directory unless absolute paths are used.
Report files are optional and are written after the audit reaches a terminal state. Configure the CI/CD platform to retain them as artifacts.
CLI overrides
These command-line flags override configuration values:
| Flag | Configuration field |
|---|---|
--profile |
audit.profile |
--application |
audit.applicationId |
--include |
audit.include |
--exclude |
audit.exclude |
--minimum-score |
qualityGate.minimumScore |
--fail-on |
qualityGate.failOn |
Examples:
pwa-check audit \
--profile quick \
--minimum-score 95 \
https://example.com
pwa-check audit \
--include offline,service-worker-update \
https://example.com
The CLI flags replace the corresponding configured arrays when at least one value is supplied; they do not append to them.
Authenticated audits
For a protected PWA, provide a bearer token or cookies only at runtime. Do not put credentials in pwa-check.yml.
export PWA_AUDIT_AUTH='{"headers":{"authorization":"Bearer token"}}'
pwa-check audit --auth-env PWA_AUDIT_AUTH https://app.example.com
The service encrypts one-time CLI credentials, uses them only for the exact target origin, and expires them after the audit. Cross-origin redirects never receive them. A local --auth-file must not be readable by group or others.
Runtime-only CLI settings do not have pwa-check.yml fields:
| Flag or environment variable | Default | Purpose |
|---|---|---|
--poll-interval |
2000 ms |
Audit and deployment status polling interval. |
--audit-timeout |
900000 ms |
Maximum time to wait for the aggregate audit. |
--api-url / PWA_TODAY_API_URL |
https://api.pwa.today |
API base URL. |
--idempotency-key / PWA_TODAY_IDEMPOTENCY_KEY |
None | Reuse one logical audit request safely. |
PWA_AUDIT_TOKEN |
Required | Customer access token. |
PWA_TODAY_ENVIRONMENT |
None | Environment name included in audit source metadata. |
Complete annotated example
version: 1
audit:
applicationId: shop.example.com
profile: full
include:
- service-worker-deployment
exclude: []
options:
manifest:
timeout: 20000
offline:
offlineUrls:
- /
- /products
expectedSelectors:
- main
requiredText:
- Example Store
offline-navigation:
series:
- [/, /products, /checkout]
- [/, /account]
expectedSelectors:
- main
cache:
routes:
- url: /
readySelector: '#home-title'
- url: /products
readySelector: '#products-title'
service-worker-first-installation:
timeout: 20000
service-worker-handlers:
timeout: 20000
service-worker-update:
timeout: 20000
service-worker-deployment:
deploymentTimeout: 900000
commandTimeout: 900000
command:
- ./scripts/deploy-and-wait.sh
requiredCachedUrls:
- /
- /offline
contentCheckUrls:
- /
- /app.js
before-install-prompt:
timeout: 20000
offline-request-retry:
requests:
- requestUrl: https://example.com/api/audit-messages
method: POST
requestBody:
message: PWA audit retry test
push-notifications:
payload:
title: PWA audit
message: Synthetic notification
qualityGate:
minimumScore: 90
failOn:
- critical
- high
failOnWarnings: true
reports:
json: reports/pwa-audit.json
junit: reports/pwa-audit.xml
Remove options and checks that are not relevant to the application. In particular, only enable checks that create external side effects when dedicated test endpoints and data are available.
Run an audit