Skip to content

Auditing PWAs After Lighthouse Dropped the PWA Category

Lighthouse 12.0.0, released on April 22, 2024, removed the Progressive Web App category, and Chrome 126 DevTools shipped without it. There is no replacement score. Chromium's own installability check is still there, in DevTools and in the DevTools Protocol, and everything else the category covered now needs a small script and a checklist. This post explains why the category went, where each of its audits ended up, and what a PWA audit looks like now. The full, maintained workflow, with custom Lighthouse audits, user flows and CI configuration, is on Lighthouse & Auditing.

Key takeaways

  • Lighthouse removed the category "as per Chrome's updated Installability Criteria". Once Chrome 108 (Android) and 112 (desktop) stopped requiring a fetch handler for installation from the menu, most of what the category measured was no longer the thing that made a site installable.
  • The removal happened in stages: the service-worker audit went in Lighthouse 11.0 (August 2023), a deprecation warning arrived in 11.5 (January 2024), and the whole category went in 12.0 (April 2024).
  • The installability audit was always a wrapper around Chromium's own check. That check is still available as Page.getInstallabilityErrors in the DevTools Protocol and as the Installability section of DevTools' Application > Manifest pane.
  • Lighthouse's default settings clear service worker registrations and Cache Storage before every navigation. A default run always measures a first visit and never tests your offline behavior.
  • A useful 2026 audit has four layers: a DevTools pass, a CDP or Playwright script in CI, Lighthouse CI for performance, accessibility and best practices, and manual checks on Safari and Firefox, whose install rules Chromium's check doesn't cover.
  • Old Lighthouse CI configs that assert on categories:pwa or installable-manifest fail after an upgrade, because the audit didn't run (auditRan expected 1, got 0).

What the PWA category used to check

The category went through several designs before it was removed. The short version:

Lighthouse version Date What changed in the PWA category
4.0.0 January 16, 2019 Badges instead of a score gauge; groups for fast and reliable, installable, and PWA optimized.
7.0.0 December 16, 2020 The Installable group is "powered entirely by the capability checks that enable Chrome's installable criteria". works-offline, offline-start-url and load-fast-enough-for-pwa are removed.
11.0.0 August 3, 2023 service-worker audit removed.
11.5.0 January 24, 2024 "Added a warning for PWA deprecation."
12.0.0 April 22, 2024 Category removed. Shipped in Chrome 126 DevTools (stable June 11, 2024).

By Lighthouse 11.7.1, the last release that had it, the category held six scored audits (installable-manifest, splash-screen, themed-omnibox, content-width, viewport, maskable-icon) and three manual reminders (pwa-cross-browser, pwa-page-transitions, pwa-each-page-has-url). Nothing tested offline behavior, nothing checked that the service worker did anything useful, and nothing looked at Safari or Firefox beyond the manual reminders. By 2024 the category was mostly Chromium's installability check plus four cosmetic audits. Lighthouse & Auditing has the full audit-by-audit history.

Why Lighthouse removed it

The Lighthouse 12.0.0 release notes give a one-line reason: "As per Chrome's updated Installability Criteria, Lighthouse has removed the PWA category." They point users to the Chrome DevTools documentation for PWA debugging instead. The Chrome post that announced the new criteria, Revisiting Chrome's installability criteria, says the same: "we have decided to remove this category from Lighthouse", while developers can "still find the checks for optimizations and debugging for installable experiences on DevTools."

The underlying change is this:

  • Chrome 108 on Android and Chrome 112 on desktop stopped requiring a service worker with a fetch handler "for installation from the menu". Chrome shows a default offline page for installed apps that don't provide their own.
  • The post noted that the promotion algorithm, the one that fires beforeinstallprompt and shows install UI on its own, still required a fetch handler at that time. Current Chromium no longer does, as Installability Criteria documents with tests against Chrome 153.

Three consequences made the category hard to keep:

  1. The main audit measured a moving browser rule, not quality. installable-manifest asked Chromium whether the page could be installed. When Chromium lowered the bar, a green badge started to mean "has a manifest with a name, a start URL, a display mode and an icon of at least 144 px" (Chromium's kMinimumPrimaryIconSizeInPx; Google still documents 192 px and 512 px). That is useful to know, but it doesn't say much about how good the app is.
  2. It encouraged the wrong fixes. For years the easiest way to get the badge was an empty fetch handler, which gives users nothing and costs a worker startup on every navigation. The Chrome post mentions this directly as a reason for the criteria change. Pitfalls & Anti-Patterns explains the cost.
  3. "PWA" isn't a Chromium-only property. Safari has never used a manifest-based installability rule on iOS, and since Safari 26.0 (September 15, 2025) WebKit says "there are now zero requirements for 'installability' in Safari". Firefox on Windows can pin any site to the taskbar since Firefox 143. A single score computed in one engine couldn't represent that, and the manual pwa-cross-browser reminder was the category admitting it.

What the removal did not change

Nothing about how Chromium, Safari or Firefox treat your app changed on April 22, 2024. The removal affected reports, not browsers. It also had no search impact: Google has never documented a ranking signal tied to the manifest, a service worker or installability, which SEO for PWAs covers in detail.

Where each audit went

Most checks still exist somewhere. This table maps every audit from the final PWA category, plus the HTTPS checks that sat next to it, to its fate in Lighthouse 12 and 13 and to what you should use now.

Old audit Status in Lighthouse 12 Status in Lighthouse 13.x Use instead
installable-manifest Removed Removed DevTools Manifest > Installability; Page.getInstallabilityErrors in CI
splash-screen Removed Removed Check name, background_color, theme_color and a 512 px icon yourself (Android builds its splash screen from them)
themed-omnibox Removed Removed Check theme_color and <meta name="theme-color">
content-width Removed Removed Responsive tests at real viewport widths; see Responsive & Adaptive Design
viewport Moved to Best Practices Replaced by the viewport-insight performance insight; the accessibility audit meta-viewport still checks zoom Keep asserting meta-viewport, and check the viewport meta in your script
maskable-icon Removed Removed DevTools Manifest > Icons with "Show only the minimum safe area for maskable icons"
pwa-cross-browser, pwa-page-transitions, pwa-each-page-has-url Removed (manual) Removed A written cross-browser test plan
service-worker Already removed in 11.0 Removed Registration, scope and control checks in your own script
is-on-https Best Practices Best Practices Unchanged
redirects-http Restored in Best Practices, passive only Best Practices Only checks when the URL you test is http://; test the redirect explicitly

The viewport audit's move in 12.0 came from the SEO reorganization in the same release, not from the PWA removal; Lighthouse 13.0.0 (October 10, 2025, shipped in Chrome 143 DevTools) then replaced many performance audits with performance insights, which is why viewport-insight exists and viewport doesn't.

Two things that break when you upgrade

A default Lighthouse run never tests your service worker. Lighthouse's default clearStorageTypes setting includes service_workers and cache_storage, so before each navigation it unregisters your worker and deletes Cache Storage. Every default run is a first visit. That was also true while the PWA category existed, which is one reason its offline audits were unreliable. To measure the repeat visit your PWA is optimized for, use a user flow whose second navigation keeps storage; Lighthouse & Auditing shows how, and why emulating offline inside a Lighthouse run doesn't work.

Old Lighthouse CI assertions fail. Assertions on audits that no longer run don't pass silently: LHCI reports them as failed auditRan assertions (expected 1, actual 0). Configs like this one break on upgrade:

lighthouserc.cjs (legacy config that fails on Lighthouse 12+)
module.exports = {
  ci: {
    assert: {
      assertions: {
        'categories:pwa': ['error', { minScore: 1 }],   // category no longer exists
        'installable-manifest': 'error',                  // audit no longer exists
        'maskable-icon': 'warn',                          // audit no longer exists
      },
    },
  },
};

Delete those assertions rather than setting them to off, so nobody thinks they still check something, and move the checks into a script like the one below. PageSpeed Insights runs Lighthouse too, so its reports lost the PWA section in the same weeks. Lighthouse 13 also requires Node.js 22.19 or later, so an older CI image fails before any audit runs.

What a PWA audit looks like now

A PWA audit in 2026 answers five questions, and no single tool answers all of them:

flowchart TD
    A["1. Is it installable in Chromium?"] --> T1["DevTools Manifest pane<br/>Page.getInstallabilityErrors"]
    B["2. Is the manifest complete for every platform?"] --> T2["CI script: members, icons, screenshots"]
    C["3. Does the service worker work: control, offline, updates?"] --> T3["E2E tests with offline emulation"]
    D["4. Is it fast, accessible and well-behaved?"] --> T4["Lighthouse CI<br/>cold and warm runs"]
    E["5. Does it work in Safari and Firefox?"] --> T5["Manual test plan on devices"]
    T1 --> R["Release gate"]
    T2 --> R
    T3 --> R
    T4 --> R
    T5 --> R

Start with a DevTools pass in Chrome or Edge: Application > Manifest shows parser warnings and the Installability section (the same data installable-manifest used to show), the computed app ID, and a maskable-icon safe-area preview that is more useful than the old maskable-icon audit. Browser DevTools walks through every pane.

Then script the Chromium check so it runs on every pull request. The installability audit was always a wrapper around two DevTools Protocol methods, and you can call them directly. This excerpt uses Playwright:

scripts/lighthouse-pwa-audit.mjs (excerpt)
import { mkdtemp } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { chromium } from 'playwright';

// A persistent profile matters: browser.newContext() is off-the-record, and
// Chromium reports "in-incognito" as an installability error there.
const profile = await mkdtemp(path.join(tmpdir(), 'pwa-audit-'));
const context = await chromium.launchPersistentContext(profile, { serviceWorkers: 'allow' });
const page = context.pages()[0] ?? (await context.newPage());
await page.goto(process.argv[2], { waitUntil: 'load' });

const cdp = await context.newCDPSession(page);
// Manifest URL, raw JSON, parser errors (each with a `critical` flag) and resolved URLs.
const manifest = await cdp.send('Page.getAppManifest');
// Chromium's real installability check: [{ errorId, errorArguments }], e.g. "no-manifest".
const { installabilityErrors } = await cdp.send('Page.getInstallabilityErrors');

for (const e of manifest.errors ?? []) console.log(e.critical ? 'FAIL' : 'WARN', e.message);
for (const e of installabilityErrors) console.log('FAIL', e.errorId);
await context.close();
process.exitCode = installabilityErrors.length ? 1 : 0;

Both methods are experimental in the protocol, so pin your Playwright version. Passing this check means little on its own: Chromium's bar is now a name, a start URL, an app-like display mode and one icon of at least 144 px. Add the checks the old category never had: icon files compared against their declared sizes (a mislabeled icon passes Chromium's check), the worker's scope and Cache-Control headers, and an offline launch. For offline tests, use Playwright's context.setOffline(), which also applies to service workers; Puppeteer's page-level offline mode doesn't, so a network-first handler still reaches the network and the test passes for the wrong reason. Automated Testing has complete manifest, installability and offline test suites.

Keep Lighthouse for what it measures well (performance, accessibility and best practices) and run it twice: a cold run that matches a first visit and a warm run with the worker installed and controlling. If the warm run isn't clearly faster, your worker isn't helping navigations, usually because HTML is network-first without navigation preload or every request goes through a fetch handler that the Static Routing API could skip. The flow script, a maintained lighthouserc.cjs and a GitHub Actions workflow are in Lighthouse & Auditing.

Manual checks Chromium can't do for you

Every automated check above runs in Chromium. Safari and Firefox install web apps under different rules, and some of the most important PWA behavior only exists there. Before a release that touches install, the manifest or the worker, test these on real devices:

Platform What to check Why
iOS and iPadOS (Safari 26+) Add to Home Screen with Open as Web App on; icon, name, start_url, status bar; notification permission prompt only after a tap No install event, no installability errors, and push only works in Home Screen web apps. See iOS & iPadOS
iOS Launch offline from the Home Screen Home Screen web apps have their own storage, separate from Safari's
macOS Safari File > Add to Dock Mac web apps ignore some manifest members; check the window and links
Firefox for Android Menu offers to install, not just add a shortcut Needs an explicit display other than browser and an icon of at least 192 px. See Installability Criteria
Firefox on Windows Pin to taskbar (Firefox 143+) No beforeinstallprompt, so your install UI must fall back to instructions
Android Chrome Install, then check about://webapks WebAPK minting can fail even when the desktop check passes

Record the results in the release checklist. The Production Checklist has a complete list.

Common pitfalls when replacing the category

  • Treating "installable" as "done". An app can pass Page.getInstallabilityErrors with a manifest and one icon, and still show a browser error page when offline.
  • Auditing in an incognito profile. Playwright's default contexts, and some CI browser setups, are off-the-record. You get in-incognito and nothing else.
  • Reading a Lighthouse score as a PWA verdict. Default runs reset storage and never see your worker. A perfect score says nothing about offline support.
  • Forgetting to test the real origin. CI on localhost skips HTTPS, HSTS, CDN headers and redirects. Run the checks against staging too.

Further reading

On this site

External references