@pwa-today/pwa-check
v0.1.9
Published
An automated PWA health check tool
Maintainers
Readme
pwa-check
Is your web app actually ready to be installed, work offline, and behave like a real PWA?
Let pwa-check check your app for you.
It scans the HTML, manifest, scripts, and service worker, then points straight at the gaps that will hurt installability or offline behavior.
What it checks
Web App Manifest
pwa-check finds a Web App Manifest in the HTML or in JavaScript that injects it dynamically, then checks the pieces that matter for installability:
scopedisplaystart_urldescriptionshort_nameorientationiconsscreenshotsshortcutsshare_targetfile_handlershandle_links
It also checks whether referenced icons, screenshots, and shortcut icons are reachable, because broken assets make a PWA look unfinished.
Viewport meta tag
It checks for the viewport configuration a polished PWA should have:
width=device-widthinitial-scale=1viewport-fit=cover
If tokens are missing, the warning tells you exactly what is wrong.
iOS startup images
It checks whether the app defines iOS splash screens using apple-touch-startup-image links, so the first launch does not feel half-built.
These can be present in the HTML or injected by JavaScript.
When startup-image links exist, it also checks for <meta name="apple-mobile-web-app-capable" content="yes">, which is required for those images through iOS 26.4.
Service worker
It checks whether the app registers a service worker and whether the worker does the work a PWA needs:
installhandleractivatehandlerfetchhandlerpushhandlernotificationclickhandler- caching behavior
It also supports Workbox-style service workers, including generated wrappers that load additional modules and precache assets.
Output
The CLI prints a list of results with one of three statuses:
passwarnfail
The process exits with a non-zero status if any fail result is found, so it fits cleanly into CI and local checks.
You can also show only warnings and failures, make warnings fail the run, ignore specific warning codes, emit JSON, or set a timeout for each request.
Usage
Run the free checks against a URL when you want a straight answer instead of guessing:
node bin/pwa-check.js https://example.comThe explicit free-check command produces the same result:
pwa-check check https://example.comor install it as a CLI tool:
npm i @pwa-today/pwa-checkthen run:
npx pwa-check https://example.comIf you install the package globally:
npm i -g @pwa-today/pwa-checkor link it:
npm link @pwa-today/pwa-checkyou can run it directly:
pwa-check https://example.comFlags:
--json: emit machine-readable output--issues-only: hide passing checks in terminal output--fail-on-warn: treat warnings as failures--ignore-warn <code>: exclude a warning code from--fail-on-warn--timeout <ms>: cap each network request--insecure-localhost: allow HTTPS requests to localhost with an invalid certificate--auth-env <name>: read origin-scoped bearer/cookie authentication JSON from an environment variable--auth-file <path>: read the same authentication JSON from a local file
For a protected PWA, keep the authentication value out of shell history and configuration files:
export PWA_CHECK_AUTH='{"headers":{"authorization":"Bearer token"}}'
pwa-check check --auth-env PWA_CHECK_AUTH https://app.example.com{"cookies":[{"name":"session","value":"cookie-value"}]}Authentication is applied only to requests for the audited origin and is
removed before a cross-origin redirect. It is never printed or read from
pwa-check.yml.
In terminal output, warnings and failures include their code, priority, impact, suggested fix, and documentation URL. Passing checks remain on one line.
Warning Codes
Every result includes a stable code. Warning and failure codes also include priority,
impact, fix, and documentation fields in JSON output.
Use the code shown in JSON output with --ignore-warn <code> to exclude one warning
from --fail-on-warn.
Paid runtime audits
Paying customers can run the hosted runtime checks with the explicit audit
command. A paid plan can be purchased from https://pwa.today.
A token never enables paid checks by itself.
Set the access token in the environment:
export PWA_AUDIT_TOKEN="..."Then start an audit:
pwa-check audit https://example.comThe CLI creates one aggregate audit, waits for the background checks to complete, prints the results, applies the quality gate, and returns:
0when the audit and quality gate pass1when the quality gate fails2for authentication or configuration errors3for audit service errors or timeouts
Runtime audit flags:
--profile <quick|standard|full|custom>--include <check-id>: include one or more comma-separated check IDs--exclude <check-id>: exclude one or more comma-separated check IDs--application <hostname>--minimum-score <0-100>--fail-on <critical|high|medium|low>--config <file>--poll-interval <ms>--audit-timeout <ms>--api-url <url>: override the defaulthttps://api.pwa.today--idempotency-key <key>--json--auth-env <name>or--auth-file <path>: provide one-time bearer, cookie, or session-storage credentials for this hosted audit
The token can only be supplied through PWA_AUDIT_TOKEN. The API URL and
idempotency key can also be set with PWA_TODAY_API_URL and
PWA_TODAY_IDEMPOTENCY_KEY.
One-time audit authentication uses the same JSON shape as check, but it is
sent only when the audit is created. The service encrypts it, applies it only
to the target origin, and expires it after the audit. It is never read from
pwa-check.yml or printed. Files passed to --auth-file must not be readable
by group or others.
Hosted audits also support session storage. Each storage value must be a string:
{
"sessionStorage": {
"app-session": "{\"accessToken\":\"token\"}"
}
}The local check command uses direct HTTP requests, so session-storage
authentication is supported only by pwa-check audit.
Audit configuration
The CLI automatically loads pwa-check.yml, pwa-check.yaml, or
pwa-check.json from the current directory. You can select another file with
--config.
version: 1
audit:
profile: standard
exclude:
- push-notifications
qualityGate:
minimumScore: 90
failOn:
- critical
- high
failOnWarnings: true
reports:
junit: reports/pwa-audit.xml
json: reports/pwa-audit.jsonChecks with additional inputs use the stable check ID under audit.options:
audit:
profile: full
options:
offline-navigation:
series:
- [/, /installation, /offline-support]
- [/, /audit, /email-list]
expectedSelectors:
- main
- h1
requiredText:
- Example
push-notifications:
payload:
title: Runtime audit
message: Test notification
offline-request-retry:
requestUrl: /api/messages
method: POST
requestBody:
message: Test requestThe service worker deployment check is opt-in because it runs a local deployment command. The CLI waits for the hosted check to capture its baseline, runs the command without a shell, waits for it to exit successfully, and then signals that the deployment is complete:
audit:
profile: full
include:
- service-worker-deployment
options:
service-worker-deployment:
deploymentTimeout: 900000
commandTimeout: 900000
command:
- ./scripts/deploy.shThe command and command timeout are local-only settings and are never sent to the PWA Today API. The deployment script must not exit until the deployment is finished and publicly observable.
Stable runtime check IDs:
manifestofflineoffline-navigationservice-worker-first-installationservice-worker-handlersservice-worker-updateservice-worker-deployment(explicit opt-in only)before-install-promptoffline-request-retrypush-notifications
offline-request-retry and push-notifications require hosted check options;
missing prerequisites produce not-applicable. A selected
service-worker-deployment check requires a local command and missing local
configuration is a CLI configuration error.
Testing
Run the test suite with:
npm testLicense
ISC. See LICENSE.
Notes
- The checker uses heuristics for dynamic behavior, such as manifests or service workers injected by JavaScript.
- A
warnresult means the app might still work, but it is leaving quality on the table. - A
failresult means the app is missing a required piece and should not be treated as install-ready.
