Troubleshooting Playwright Lighthouse Integration
Common issues and solutions when integrating Lighthouse with Playwright.
Port Already in Use
Error: Error: listen EADDRINUSE: address already in use :::9222
The debugging port is already occupied, usually from a previous run that didn't close properly.
Solution: Kill existing Chrome processes or use a different port:
# Kill process on port 9222
lsof -ti:9222 | xargs kill -9
# Or use a different port
const PORT = 9223
For CI environments, ensure proper cleanup:
async function audit() {
let browser
try {
browser = await chromium.launch({
args: [`--remote-debugging-port=${PORT}`],
})
// ... audit logic
}
finally {
if (browser)
await browser.close()
}
}
Authentication State Lost
Symptom: Lighthouse audits a login page instead of the authenticated page.
Cause: Lighthouse opens a new page context, losing cookies/session.
Solution: Use disableStorageReset: true:
const result = await lighthouse(url, {
port: PORT,
disableStorageReset: true, // Prevents Lighthouse from clearing storage
})
See Authentication Guide for complete examples.
Flaky or Inconsistent Scores
Symptom: Performance scores vary significantly between runs (±10-20 points).
Causes:
- Network variability
- CPU load on the machine
- Shared CI runners
- Third-party script timing
Solutions:
- Run multiple audits and use median:
const runs = 3
const scores = []
for (let i = 0; i < runs; i++) {
const result = await lighthouse(url, { port: PORT })
scores.push(result.lhr.categories.performance.score)
}
scores.sort((a, b) => a - b)
const median = scores[Math.floor(scores.length / 2)]
- Disable throttling for consistent local results:
const result = await lighthouse(url, {
port: PORT,
throttling: {
cpuSlowdownMultiplier: 1,
throughputKbps: 0,
requestLatencyMs: 0,
},
})
- Use dedicated CI runners instead of shared ones.
Chrome/Chromium Version Mismatch
Error: Protocol error or Target closed or Cannot find context with specified id
Cause: Lighthouse and Playwright bundled Chromium versions are incompatible.
Solution: Use the same Chrome for both:
// Use Playwright's bundled Chromium path
import { chromium } from 'playwright'
const browserPath = chromium.executablePath()
console.log('Using Chrome at:', browserPath)
const browser = await chromium.launch({
executablePath: browserPath,
args: [`--remote-debugging-port=${PORT}`],
})
Or install a specific Chrome version:
npx playwright install chrome # Installs stable Chrome, not Chromium
Timeout Errors
Error: Lighthouse timeout or Navigation timeout exceeded
Causes:
- Page takes too long to load
waitUntil: 'networkidle'waiting for never-ending requests- Large pages with many resources
Solutions:
- Increase Lighthouse timeout:
const result = await lighthouse(url, {
port: PORT,
maxWaitForLoad: 60000, // 60 seconds (default is 45s)
})
- Use different wait strategy:
// Instead of networkidle, wait for specific element
await page.goto(url)
await page.waitForSelector('#main-content')
- Check for infinite polling requests (analytics, websockets).
Sandbox Errors
Error: No usable sandbox! or Running as root without --no-sandbox is not supported
Cause: Chrome sandboxing issues, common in Docker/CI.
Solution: Disable sandbox (only in trusted CI environments):
const browser = await chromium.launch({
args: [
`--remote-debugging-port=${PORT}`,
'--no-sandbox',
'--disable-setuid-sandbox',
],
})
Multiple Concurrent Audits Fail
Error: Audits interfere with each other or return incorrect results.
Cause: Multiple Lighthouse instances trying to use the same debugging port.
Solution: Use different ports for parallel audits:
async function auditWithDynamicPort(url) {
const port = 9222 + Math.floor(Math.random() * 1000)
const browser = await chromium.launch({
args: [`--remote-debugging-port=${port}`],
})
// ... use `port` variable
}
Or run audits sequentially with a single worker:
# Playwright Test
npx playwright test --workers=1
Lighthouse Reports Show Wrong Page
Symptom: Report shows homepage or login page instead of target URL.
Causes:
- Redirects before audit runs
- Authentication issues
- URL mismatch between Playwright navigation and Lighthouse call
Solution: Verify URL after navigation:
await page.goto(targetUrl, { waitUntil: 'networkidle' })
// Check actual URL
const actualUrl = page.url()
if (actualUrl !== targetUrl) {
console.warn(`Redirected from ${targetUrl} to ${actualUrl}`)
}
// Use actual URL for Lighthouse
const result = await lighthouse(actualUrl, { port: PORT })
Empty or Incomplete Reports
Symptom: Lighthouse report missing metrics or categories.
Causes:
- Page not fully loaded
- JavaScript errors on page
- Missing viewport settings
Solution: Ensure page readiness:
await page.goto(url, { waitUntil: 'networkidle' })
// Wait for critical content
await page.waitForSelector('[data-testid="main-content"]')
// Check for console errors
page.on('console', (msg) => {
if (msg.type() === 'error')
console.warn('Page error:', msg.text())
})
CI-Specific Issues
GitHub Actions: Chrome Not Found
- name: Install Chrome
run: npx playwright install chromium --with-deps
The --with-deps flag installs system dependencies required by Chromium.
Docker: Missing Dependencies
Add to Dockerfile:
RUN apt-get update && apt-get install -y \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
libgbm1 \
libasound2
Or use Playwright's Docker image:
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
Crash / Target Closed in Docker:
If Chrome crashes with "Target closed" or "Page crashed", it's often due to small shared memory /dev/shm. Add this flag:
const browser = await chromium.launch({
args: [
`--remote-debugging-port=${PORT}`,
'--disable-dev-shm-usage', // Critical for Docker
],
})
Visual Debugging
Use Playwright's Inspector to pause execution right before the Lighthouse audit to verify the page state.
# Run with Inspector
PWDEBUG=1 npx playwright test
When paused:
- Check if you are logged in (if expected).
- Verify the DOM is fully loaded.
- Check for any overlay/modals that might block Lighthouse.
Still Stuck?
- Check Lighthouse GitHub Issues
- Check Playwright GitHub Issues
- For site-wide auditing without these integration headaches, try Unlighthouse
Related
- Playwright Setup Guide — Basic integration
- Authentication — Protected page testing
- CI/CD Integration — GitHub Actions setup