PWA Testing with Lighthouse — Auditing Progressive Web Apps
In this tutorial, you will learn about PWA Testing with Lighthouse. We cover key concepts, practical examples, and best practices to help you master this topic.
Lighthouse audits PWAs against Google's quality checklist, testing offline support, installability, performance, and best practices with automated scoring in Chrome DevToolsk "DevTools" >}}.
What You'll Learn
By the end of this tutorial, you will understand how to run Lighthouse audits, interpret PWA audit results, fix common failures, automate audits with Lighthouse CI, and maintain a high PWA score.
Why It Matters
Lighthouse is the official PWA quality benchmark. A low Lighthouse score means your PWA is not truly progressive — it may fail offline, cannot be installed, or has poor performance. Passing the PWA audit checklist builds user trust and ensures your PWA works as intended.
Real-World Use
A team building a PWA for a major retailer ran Lighthouse daily in CI. A commit that introduced a JavaScript error caused the service worker to fail registration, dropping the PWA score from 92 to 45. The CI pipeline caught it before deployment, saving thousands of users from a broken experience.
Lighthouse Audit Categories
Lighthouse PWA Audits
┌──────────────────────────────────────────────────────────────┐
│ PWA Audit Checklist (15 audits) │
├──────────────────────────────────────────────────────────────┤
│ Installable (3 audits): │
│ ✓ Has web app manifest │
│ ✓ Manifest has correct icons │
│ ✓ Registers service worker │
│ │
│ PWA Optimized (12 audits): │
│ ✓ Responds with 200 when offline │
│ ✓ start_url responds with 200 when offline │
│ ✓ HTTPS used │
│ ✓ Redirects HTTP to HTTPS │
│ ✓ Page load is fast enough on mobile │
│ ✓ Splash screen configured │
│ ✓ Theme color set │
│ ✓ Content sized correctly for viewport │
│ ✓ Has a `<meta name="viewport">` tag │
│ ✓ Has a `<title>` tag │
│ ✓ Displays content without JavaScript │
│ ✓ Address bar matches brand colors │
└──────────────────────────────────────────────────────────────┘
Think of Lighthouse audits like a vehicle safety inspection. You would not drive a car that had not passed inspection. Similarly, you should not ship a PWA that has not passed Lighthouse audits. The inspections catch issues that affect user safety (privacy, security) and experience (speed, reliability).
Running Lighthouse
// 1. Open Chrome DevTools (F12)
// 2. Click "Lighthouse" tab
// 3. Select "PWA" category
// 4. Click "Generate report"
// Programmatic: Lighthouse Node API
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
async function runLighthouse(url) {
const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });
const options = {
logLevel: 'info',
output: 'json',
onlyCategories: ['pwa'],
port: chrome.port
};
const result = await lighthouse(url, options);
await chrome.kill();
console.log('Lighthouse PWA score:', result.score * 100);
result.lhr.audits.forEach(audit => {
if (audit.score !== null && audit.score < 1) {
console.log('Failed:', audit.title, `(score: ${audit.score})`);
}
});
}
runLighthouse('https://your-pwa.com');
Interpreting PWA Audit Results
// Common PWA audit failures and fixes
const pwaAuditFixes = {
'has-web-app-manifest': {
check: 'Does the page have a manifest.json link?',
fix: 'Add <link rel="manifest" href="/manifest.json"> to your HTML <head>.'
},
'manifest-icons-exist': {
check: 'Does the manifest have at least 192x192 and 512x512 icons?',
fix: 'Add icons to your manifest. Both sizes are required.'
},
'registers-service-worker': {
check: 'Does the page register a service worker?',
fix: 'Add navigator.serviceWorker.register() to your main JavaScript file.'
},
'works-offline': {
check: 'Does the page return 200 when offline?',
fix: 'Ensure your service worker has a fetch handler that serves cached content.'
},
'splash-screen': {
check: 'Is the splash screen configured correctly?',
fix: 'Ensure manifest has name, background_color, and a 512x512 icon.'
},
'themed-omnibox': {
check: 'Is the address bar themed?',
fix: 'Add <meta name="theme-color" content="#your-color"> to your HTML.'
}
};
Automating PWA Audits with Lighthouse CI
// .lighthouserc.json
{
"ci": {
"collect": {
"numberOfRuns": 3,
"settings": {
"onlyCategories": ["pwa", "performance"]
}
},
"assert": {
"assertions": {
"service-worker": "warn",
"works-offline": "error",
"installable-manifest": "error",
"viewport": "error",
"meta-description": "off",
"lighthouse-plugin-pwa": "off"
}
},
"upload": {
"target": "filesystem",
"outputDir": "./lhci-reports"
}
}
}
Run in CI:
# Install
npm install -g @lhci/cli
# Collect and assert
lhci autorun --config=.lighthouserc.json
Manual PWA Testing Checklist
Beyond automated audits, test manually:
const manualTestChecklist = {
offline: async function() {
// 1. Load PWA with network
// 2. Go to DevTools > Network tab > check "Offline"
// 3. Refresh and verify the app loads
console.log('Testing offline...');
const testPages = ['/', '/articles', '/about'];
for (const page of testPages) {
const cached = await caches.match(page);
console.log(` ${page}: ${cached ? 'cached' : 'not cached'}`);
}
},
install: function() {
// 1. Check install prompt appears
// 2. Install and verify standalone mode
// 3. Check icon and name on home screen
console.log('Install prompt available:',
!!window.deferredPrompt);
console.log('Running standalone:',
window.matchMedia('(display-mode: standalone)').matches);
},
pushNotifications: function() {
// 1. Subscribe and verify permission
// 2. Send a push from server
// 3. Verify notification appears and click works
console.log('Push permission:',
Notification.permission);
},
responsive: function() {
// 1. Test on mobile viewport (375px)
// 2. Test on tablet (768px)
// 3. Test on desktop (1440px)
// 4. Verify no horizontal scroll
const width = window.innerWidth;
console.log('Viewport width:', width, 'px');
console.log('No overflow:',
document.documentElement.scrollWidth <= window.innerWidth);
}
};
Common PWA Audit Failures
// Most common Lighthouse PWA failures
const COMMON_FAILURES = {
NO_HTTPS: {
score: 0,
fix: 'Configure SSL/TLS on your server. Use Let\'s Encrypt for free certificates.',
impact: 'Service workers require HTTPS. PWA will not work at all without it.'
},
NO_SERVICE_WORKER: {
score: 0,
fix: 'Create sw.js and register it from your page. Must have a fetch event listener.',
impact: 'Without a service worker, offline, caching, and push notifications are impossible.'
},
NO_MANIFEST: {
score: 0,
fix: 'Create manifest.json and link it in your HTML <head>.',
impact: 'Without a manifest, the PWA cannot be installed to the home screen.'
},
OFFLINE_404: {
score: 0,
fix: 'Add a fetch handler that serves cached content. Pre-cache critical pages.',
impact: 'Users see browser error pages when offline instead of your app.'
}
};
Maintaining PWA Quality
// Continuous monitoring
async function monitorPWAHealth() {
const checks = {
swRegistered: 'serviceWorker' in navigator,
hasManifest: !!document.querySelector('link[rel="manifest"]'),
https: location.protocol === 'https:' || location.hostname === 'localhost',
manifestValid: await validateManifest()
};
const allPass = Object.values(checks).every(Boolean);
console.log('PWA Health Check:', allPass ? 'PASS' : 'FAIL');
console.table(checks);
if (!allPass) {
const failures = Object.entries(checks)
.filter(([_, v]) => !v)
.map(([k]) => k);
console.log('Failed checks:', failures.join(', '));
}
}
async function validateManifest() {
try {
const link = document.querySelector('link[rel="manifest"]');
if (!link) return false;
const response = await fetch(link.href);
const manifest = await response.json();
return manifest.name && manifest.icons && manifest.icons.length >= 2;
} catch {
return false;
}
}
Common Mistakes
- Not running Lighthouse on mobile. Mobile has less CPU, memory, and network bandwidth. Always audit on mobile emulation with Slow 3G throttling.
- Fixing only the PWA category. PWA performance and installation depend on the performance category scores. A slow PWA is not truly progressive.
- Ignoring the "works offline" audit. This is the most important PWA audit. Without it, your PWA is just a website with an icon.
- Not testing on real devices. Lighthouse emulation is not a substitute for testing on actual mobile devices with real network conditions.
- Auditing only once. PWA quality degrades over time with code changes. Automate Lighthouse in CI to catch regressions.
Practice Questions
- What are the 15 audits in the Lighthouse PWA category?
- How do you automate Lighthouse audits in a CI pipeline?
- What is the difference between the "installable" and "PWA optimized" audit groups?
- Why is the "works offline" audit the most critical PWA audit?
- How often should you run PWA audits?
Challenge: Run a Lighthouse PWA audit on any website. Identify three failed audits. Fix each one and re-audit. Document the before/after scores and the changes you made. Achieve a PWA score of 100.
FAQ
Mini Project
Take a PWA you have been building or use a sample PWA project. Run a full Lighthouse PWA audit. Fix every failed audit (there should be at least 3 failures initially). Re-audit and achieve a score of 100 on all PWA audits. Document each fix with the before/after state.
What's Next
Your PWA is tested and optimized. Now learn about publishing PWAs to app stores — wrapping your PWA for Google Play, Microsoft Store, and the App Store.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro