The breaking point
I run a company called Scale Campaign. One of our products is a batch geocoding platform with a Laravel backend, a Vue.js frontend, and a TerriaJS-based map viewer on a separate subdomain.
It's the kind of app that has a lot of surface area: landing pages, authentication flows, a file-upload pipeline, an interactive map, payment pages, an admin dashboard, and help docs. Multiple JS bundles, multiple CSS builds, third-party scripts.
And things kept breaking silently.
A deploy would go out. Everything looked fine. Then, a week later, someone would mention that the file upload wasn't working on the pricing page. Or I'd discover that a third-party script was throwing TypeError on three pages. Or Google Search Console would flag that our OG images were missing. Or performance had regressed to a 6-second LCP on mobile, and nobody noticed.
The worst part? Every time I investigated, the problem had been there for days.
The workflow that doesn't scale
My debugging process was:
- Open Chrome DevTools
- Check one page at a time
- Run Lighthouse on that page
- Check the console for JS errors
- Inspect meta tags manually
- Repeat for the next page
- Forget which pages I already checked
For a site with 75+ distinct pages, some requiring authentication, this takes forever. And I'd only do it when something was already broken.
I wanted something that would just tell me: "Here's everything wrong across your entire site right now."
What I built
https://github.com/acenji/lighthouse is an open source QA platform that combines three tools (for now) into one workflow:
- Bulk Lighthouse audits - for local and production environments
Instead of auditing one URL at a time, ScaleLighthouse crawls your site and runs Lighthouse across every page. You get a dashboard showing performance, accessibility, SEO, and best practices scores for your entire site at a glance.
pnpm cli --site https://csv2geo.com --server-port 5678
Open localhost:5678 and you're looking at every page's audit results.
- Playwright smoke tests (zero test code) - for local and production environments
This is the part that saved me the most time. The smoke test framework is data-driven — you write a config file
describing your site, and it generates all the tests automatically.
Here's what the config looks like for CSV2GEO:
const csv2geo: ProductTarget = {
name: 'csv2geo',
baseUrl: 'http://localhost:8000',
baseUrlEnv: 'CSV2GEO_URL',
pages: [
{ path: '/', name: 'Homepage', selectors: ['#app', 'nav'] },
{ path: '/features', name: 'Features' },
{ path: '/pricing', name: 'Pricing' },
{ path: '/help', name: 'Help Center' },
{ path: '/inside/dashboard', name: 'Dashboard', auth: true,
selectors: ['.dashboard-grid'] },
{ path: '/inside/tasks', name: 'Tasks', auth: true },
],
auth: {
strategy: 'form',
loginUrl: '/login',
fields: {
'#email': '${CSV2GEO_EMAIL}',
'#password': '${CSV2GEO_PASSWORD}',
},
submitSelector: 'button[type="submit"]',
successIndicator: '/inside',
},
allowedErrors: ['analytics', 'hotjar', 'google'],
seo: {
pages: [
{ path: '/', title: /CSV2GEO/i, ogImage: /.+/, canonical: 'https://csv2geo.com/' },
{ path: '/features', title: /Features/i },
{ path: '/pricing', title: /Pricing/i },
]
}
};
No test code. That config generates tests that:
- Visit every page and verify the HTTP status
- Check that required DOM elements are visible
- Catch every JavaScript error (filtered for third-party noise)
- Validate SEO meta tags, OG images, and canonical URLs
- Log in and test authenticated pages
- Run on both localhost and production with one command
npx playwright test # all environments
npx playwright test --project="csv2geo [prod]" # production only
npx playwright test --ui # interactive UI
- Multi-step flow testing
The file upload on CSV2GEO is a multi-step process — select a file, configure columns, and submit. When it broke, users were the first to find out. Now there's a flow test:
flows: [{
name: 'CSV file upload',
auth: true,
steps: [
{ action: 'goto', path: '/inside/dashboard' },
{ action: 'click', selector: '#new-task-btn' },
{ action: 'upload', selector: '#file-input', value: 'fixtures/sample.csv' },
{ action: 'wait', selector: '#column-mapping', timeout: 10000 },
],
expectSelectors: ['#column-mapping'],
expectNoJsErrors: true,
}]
- Real-user metrics (CrUX)
The platform also pulls data from Chrome's UX Report API, so you can see real INP, CLS, and LCP trends from actual users — not just synthetic tests.
What it catches
Since deploying this against CSV2GEO, it's caught:
- A TypeError in the map viewer caused by a missing null check after a refactor
- An OG image returning 404 on three pages
- A render-blocking script that pushed LCP from 2.1s to 5.8s
- A broken CSS class reference that made the dashboard invisible on Firefox
- A third-party script failing silently and swallowing form submissions
All of these were found within seconds of running the tests — not days later from a user report.
Tech stack
It's a pnpm monorepo:
┌─────────────┬─────────────────────────────────────┐
│ Package │ What it does │
├─────────────┼─────────────────────────────────────┤
│ cli │ Command-line entry point │
├─────────────┼─────────────────────────────────────┤
│ core │ Scanning engine and route discovery │
├─────────────┼─────────────────────────────────────┤
│ server │ API serving scan results │
├─────────────┼─────────────────────────────────────┤
│ client │ Vue 3 dashboard (Vite) │
├─────────────┼─────────────────────────────────────┤
│ smoke-tests │ Playwright test framework │
├─────────────┼─────────────────────────────────────┤
│ crux-api │ Nitro server for CrUX data │
└─────────────┴─────────────────────────────────────┘
Requires Node.js 20+. MIT licensed.
Getting started
git clone https://github.com/acenji/lighthouse.git
cd lighthouse
pnpm install
# Run a Lighthouse audit
pnpm cli --site https://your-site.com
# Run smoke tests
cd packages/smoke-tests
npx playwright install chromium
npx playwright test --ui
The repo
https://github.com/acenji/lighthouse
If you're maintaining a web app with more than a handful of pages and you're tired of things breaking silently — give it a try.
Star the repo if it's useful, and open an issue if you run into anything.
Feedback and contributions welcome.
Note: credentials in the config examples are loaded from environment variables (.env file), never hardcoded.


Top comments (0)