Case studyProduct2026
Client A11y — Accessibility Monitoring
An internal dashboard that runs Lighthouse and axe-core against 270 client sites, keeps every score as history rather than a snapshot, and turns each failure into a recommendation someone can actually act on.
- Role
- Design & Build
- Timeline
- 2026
- Status
- Live — internal
- Category
- Product
01Overview
Accessibility is not a state you arrive at, it is one you drift out of. A site that passed at launch fails three months later because someone uploaded an image with no alt text or a button with no accessible name. Across 270 client sites, nobody was going to catch that by hand.
The challenge
The tool this replaced was a static site with the audit data baked in at build time — 219 clients in one long table, no search, no history, no export, and no way to trigger a run.
What I did
- Audit
- Track
- Explain
- Verify by hand
- Oversee
- Report
The result
270 client sites under continuous monitoring, mobile and desktop, up from 219 on the static predecessor.
02The problem
The tool this replaced was a static site with the audit data baked in at build time — 219 clients in one long table, no search, no history, no export, and no way to trigger a run. It could tell you a score today but not whether that score was better or worse than last month, and with hundreds of sites in the book there was no way to answer the only question that matters on a Monday morning: which of these needs attention this week?
03Approach
Audit
Every page is run twice — mobile and desktop — through Lighthouse for performance, SEO and best practices, and through axe-core driven by Playwright for accessibility. Two engines rather than one, because Lighthouse's accessibility score is a summary and axe is the thing that names the actual violated rule.
Track
Runs are stored rather than replaced, so each site carries a score history instead of a single current number. The useful signal is the slope: a site at 82 and climbing is in better shape than one at 88 and falling, and a trend line makes that obvious where a table of today's numbers never could.
Explain
Findings land in a recommendations table with the rule, its impact, its WCAG criteria and — the field that decides who picks it up — whether it is fixable in the CMS or needs a developer. A missing alt attribute and a render-blocking bundle are both failures, but they belong to different people.
Verify by hand
Automation catches perhaps a third of WCAG. The rest is a guided manual checklist across seven categories — keyboard and focus, screen reader, visual and cognitive, content, multimedia, forms, mobile — each with its criterion, level and a written how-to-test, so a manual pass is repeatable rather than dependent on who ran it.
Oversee
The portfolio view puts the whole book on one screen: total sites, average performance and accessibility with week-on-week movement, and a count of what is critical right now. Sorting and filtering happen against live data instead of a rebuild.
Report
Core Web Vitals are shown against their real thresholds — LCP, INP, CLS, FCP, TTFB — with per-page breakdowns and export, so an account manager can walk into a client meeting with the evidence rather than a screenshot of a gauge.
04Screens
05Results
- 270
client sites under continuous monitoring, mobile and desktop, up from 219 on the static predecessor.
- 3,922
critical issues surfaced across the portfolio — ranked by impact rather than buried in per-site PDFs.
- 12
sites sitting below 70 on accessibility are identifiable in a glance instead of by opening 270 reports.
Portfolio health reads as a trend — 64.0 average performance, 86.0 average accessibility — so a regression shows up as a falling line rather than a surprise at the next manual audit.
NoteInternal tool. One constraint shaped the data model more than anything else: every re-audit overwrites machine-generated content, but the human-written explanation of what an issue is and why it matters has to survive that. Those fields are deliberately excluded from the audit write path — the automated pass is not allowed to flatten the part a person wrote.