I've spent the last year building AccessHawk, a hosted accessibility scanning platform. Under the dashboards and the billing sits an engine: the code that loads a page in a real browser, audits it, has an AI model reason about what it sees, and writes the report. That engine is where all the hard problems live, and I've now extracted it and released it as open source (July 2026).
It's called A11yHawk. It's on npm as a11yhawk, licensed Apache-2.0, and it runs entirely on your own infrastructure. No accounts, no telemetry, nothing phoning home. If you've been looking at the accessibility tooling market and wondering why a URL scan costs what it costs, this post is for you.
What a scan does
A11yHawk runs a single URL through a pipeline:
- Playwright capture. The page loads in real Chromium. The engine takes a full-page screenshot (tiled to fit your AI provider's image limits), pulls the Chrome DevTools accessibility tree, and sanitizes the HTML down to its accessibility-relevant structure.
- Lighthouse audit. The accessibility category runs in a subprocess against the same browser. Findings get mapped to WCAG criteria.
- AI analysis (optional). The model receives the screenshot tiles, the accessibility tree, the sanitized HTML, the Lighthouse findings, and a condensed matrix of every WCAG criterion for the version and level you chose. It returns structured issues with remediation guidance for each one.
- Scoring. The engine recomputes every score and statistic from the actual findings. Nothing numeric is trusted from the model.
Out the other side you get a structured JSON report, a human-readable markdown report, a self-contained HTML report page, and an annotated screenshot with issues boxed directly on the page. The HTML report is a single file with zero external dependencies, so it opens straight from file:// and attaches to a ticket or CI artifact without a web server. It's also WCAG AA accessible itself, which felt like table stakes for an accessibility tool.
The AI layer is what automated checkers can't give you. Rule-based tools like Lighthouse and axe catch the mechanical failures: missing alt text, broken ARIA references, contrast below threshold. They can't tell you that your alt text is technically present but describes nothing, or that a visually obvious grouping has no programmatic relationship. A model looking at the rendered page, the accessibility tree, and the source together catches that second category.
Free scans in seconds, AI depth when you want it
Both modes matter, and you pick per scan.
Lighthouse-only mode needs no API key and no configuration. It runs the audit and gives you a repeatable score in a few seconds. This is the mode you put in CI, run on every commit, and never think about the cost of, because there isn't one.
AI mode is bring-your-own-key. You hand the engine a key for OpenRouter or any OpenAI-compatible endpoint, pick any model your endpoint accepts, and pay your provider directly for the tokens. A11yHawk adds nothing on top. A full AI scan takes a few minutes and costs whatever your chosen model charges, which for most pages is a fraction of what per-page pricing on hosted scanners implies. The report even includes the token usage and cost in USD so you can see exactly what each scan cost you.
The minimal program is three lines:
import { scan } from 'a11yhawk'
const report = await scan('https://example.com')
console.log(report.structured.overallScore, report.structured.issues.length)And AI mode is one option away:
const report = await scan('https://example.com', {
llm: { apiKey: process.env.OPENROUTER_API_KEY },
wcagVersion: '2.2',
wcagLevel: 'AA',
})Why give away the engine behind a paid product
Fair question, since AccessHawk is how this engine pays for itself.
The accessibility tooling market has a pricing problem. Enterprise scanning platforms charge per page, per scan, or per seat, and the numbers climb fast once you're auditing more than a handful of pages. Meanwhile the actual scanning technology is not the moat those prices suggest. Browsers are free. Lighthouse is free. AI models are cheap and getting cheaper. What you're paying for at those price points is mostly the platform around the scan.
So I split it along that exact line. The engine, meaning capture, audits, AI analysis, scoring, and reports, is open source. AccessHawk sells what a platform genuinely adds: scheduled scans, history and trend tracking, dashboards, team access, and a managed API where you never think about browsers or infrastructure. If you want that, it's there. If what you want is the scan itself, A11yHawk gives you the whole engine to run on your own infrastructure, with nothing held back.
I'd rather compete on the platform than on artificial scarcity of the scan. And an engine that other people build on, file issues against, and harden in environments I never thought of makes the hosted product better too.
Build your own accessibility product on it
This is the part I'm most interested to see people use. There's real demand for accessibility tooling that fits a team's own stack: an internal audit dashboard, or an accessibility feature inside a bigger product. The teams that want to build those keep running into the same wall, which is that the SaaS platforms sell dashboards, not engines.
A11yHawk is deliberately shaped like a component you embed:
- Library API. The
scan()one-shot helper for scripts, andA11yHawkEnginewhen you're scanning many pages and want the browser kept warm across scans with configurable concurrency. - Typed failure taxonomy. Every pipeline failure throws a
ScanErrorwith acodeand aretryableflag. If you're building on a job queue, you mapretryableonto your retry logic and you're done. Auth failures and malformed URLs fail fast; transient browser hiccups requeue. - Server mode.
a11yhawk serveexposes a small HTTP job API:POST /scansto enqueue, pollGET /scans/:id, fetch the rendered HTML report when it's done. Optional bearer-token auth, configurable concurrency, and in-memory jobs by design, so persistence stays your call. - Docker image. Browser and system dependencies baked in. One
docker runand you have a scanning service on your own network.
docker run --rm -p 4000:4000 ghcr.io/charlesjones-dev/a11yhawk:latest
curl -s localhost:4000/scans \
-H 'content-type: application/json' \
-d '{"url":"https://example.com"}'That's a self-hosted accessibility scanning API in two commands. Put your own UI on it, wire it into your queue, or leave it as an internal service your other tools call.
Because it's built to sit behind services where scan URLs come from untrusted users, the security posture is default-safe: an SSRF request guard validates every request the scanned page makes, refuses private and loopback targets, re-resolves DNS per request, and blocks service workers. Scanning your own internal apps is a supported opt-in (allowPrivateNetworks), not a hole. The security section of the README covers the full posture, including the residual risks, honestly stated.
Fail the build, not your users
Your pipeline already runs linting, tests, and probably a security scanner. Accessibility can sit in that same list instead of being an audit someone schedules after launch. The CLI has a built-in gate:
# .github/workflows/a11y.yml
name: Accessibility
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npx playwright install --with-deps chromium
- name: Accessibility gate
run: npx a11yhawk https://your-site.example --fail-below 90 --format json,html --output a11y-report
- if: always()
uses: actions/upload-artifact@v4
with:
name: a11y-report
path: a11y-report/The job fails when the overall score drops below 90 and uploads the full report as an artifact either way. Lighthouse-only mode makes this free and fast enough to run on every push; add an API key from your secrets when you want the AI pass on top.
Where it goes from here
A11yHawk is pre-1.0. The library API, CLI, and server mode are functional and tested, and the structured report shape is stable enough to build against, but the API may still shift between minor versions until 1.0. The CHANGELOG is honest about that, and about what each release changed.
On the roadmap: a packaged GitHub Action wrapper, plus SARIF and JUnit output formats so findings land natively in code scanning dashboards and test reporters.
If you build something on it, I want to hear about it. Issues and PRs are welcome on GitHub, and the request guard, URL validation, and process handling get extra review scrutiny, so security-minded contributors are especially welcome.
Conclusion
The scan engine I spent a year building for AccessHawk is now open source. npm install a11yhawk gets you real-browser capture, Lighthouse audits, optional AI analysis against every WCAG criterion for the version and level you pick, and reports you can hand to a developer, a client, or a CI system. Free Lighthouse-only scans in seconds, bring-your-own-key AI depth when you want it, and a server mode plus Docker image when you'd rather build your own accessibility product than rent someone else's dashboard.
Start with one command against your own site:
npx a11yhawk https://your-site.exampleIf the score surprises you, the report will tell you exactly why, and now the tool that produced it is yours to keep.
