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: Identify the process before stopping it, or assign a different port:
# Show the process listening on port 9222
lsof -nP -iTCP:9222 -sTCP:LISTENconst PORT = 9223For CI environments, use 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)]- Use the provided network without Lighthouse simulation for local diagnostics:
const result = await lighthouse(url, {
port: PORT,
throttlingMethod: 'provided',
})Use simulated throttling again for performance budgets. Unthrottled scores describe your test machine and should not be compared with PageSpeed Insights.
- 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: The installed Playwright package, browser binary, and Lighthouse version came from different lockfile states or caches.
Solution: Check the installed versions, reinstall Playwright's matching Chromium, and let Playwright use its bundled executable:
npm ls @playwright/test lighthouse
npx playwright install chromiumPlaywright warns that custom executables may not work with its APIs. If you deliberately test branded Chrome, select a supported channel and keep that choice explicit:
const browser = await chromium.launch({
channel: 'chrome',
args: [`--remote-debugging-port=${PORT}`],
})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=1Lighthouse 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: Check 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-depsThe --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 \
libasound2Or use Playwright's Docker image. Pin the image tag to the same Playwright version as @playwright/test; mismatched versions can prevent the client from locating browser executables.
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 testWhen paused:
- Check that the page has logged you in (if expected).
- Verify the browser has fully loaded the DOM.
- 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