The CheckOps Engineer
Pa11y
Pa11y is a free, open-source command-line accessibility checker. It opens a URL in a headless browser and reports rule failures.
Latest public signals
Not refreshed yet. Refresh reads the public site and, when the entry has a GitHub repository, the latest release.
Introduction
Pa11y is a command-line tool that loads a URL and runs accessibility checks against the rendered page. Current releases (the 10.x line on npm) drive the page with Puppeteer and can run either HTML CodeSniffer or axe-core as the runner. The default output is a list of issues with type, code, selector, and context. Exit code 2 means issues were found, which is what CI uses to fail the job.
The project is LGPL-3.0, maintained at pa11y/pa11y. Two companion projects matter in real setups: pa11y-ci runs a list of URLs from a config file, and pa11y-dashboard stores results over time. Pa11y checks pages you can open. It does not replace an in-component axe assertion, and it does not cover every WCAG criterion.
Features
- Single-URL CLI:
pa11y https://example.comlaunches a headless browser, waits for the page, and prints issues. - Runners:
--runner axeuses axe-core.--runner htmlcsuses HTML CodeSniffer. You can run one or both. - Standard and threshold:
--standard WCAG2AAselects the rule level.--thresholdlets the process exit 0 when the issue count stays under a number you accept. - Wait and actions: A config file can wait for a selector, click, fill a form, or set a viewport before the check. That is how you reach a page that is empty until JavaScript runs.
- Reporters: CLI, JSON, and CSV. JSON is the one to archive in CI.
- pa11y-ci: A sitemap or an explicit URL list, with one config, for a nightly crawl rather than a single page.
- Ignore lists: Specific codes or selectors can be ignored in config. Use that for a known third-party widget, and review the list.
- Dashboard:
pa11y-dashboardis a separate web app that graphs repeated runs. It is optional and has its own install.
Pros
- No test framework required: A shell script and a URL are enough to start. That suits marketing sites and docs sites that have no Playwright suite.
- axe or HTML CodeSniffer: You can align the CLI with the axe rules your component tests already use, or keep the older HTMLCS behavior.
- CI exit codes: The process fails when issues exist, so a workflow needs no custom parser unless you want JSON.
- Actions cover simple journeys: Login and “open the menu” can be a few lines in the config before the audit.
- Free: LGPL-3.0. No cloud account.
Cons
- One page at a time in the core CLI: A whole site means
pa11y-cior your own loop. Crawl scope, auth, and rate limits become your problem. - Headless browser cost: Every URL pays Chromium startup. Axe inside an already-open Playwright page is faster when you have that page.
- SPAs need a wait: Checking too early audits the loading shell. The config must name the selector that means “ready.”
- Not a component tool: Pa11y does not import a React tree. Design-system checks belong in axe inside unit or Storybook tests.
- Ignores hide regressions: A long ignore list makes the job green. Someone has to own why each code is ignored.
Usage and Links (Example)
npm install --global pa11y
pa11y https://example.com
pa11y --runner axe --standard WCAG2AA --reporter json https://example.com > pa11y.json
A small config for a page that renders late:
{
"runners": ["axe"],
"standard": "WCAG2AA",
"timeout": 20000,
"wait": "main h1",
"chromeLaunchConfig": { "args": ["--no-sandbox"] }
}
pa11y --config pa11y.json https://example.com
--no-sandbox is often required in containers. For many URLs, switch to pa11y-ci and a URL array in the same config format.
Resources:
Pricing
- Free: Pa11y, pa11y-ci, and the dashboard project are open source. Pa11y itself is LGPL-3.0-only. There is no paid Pa11y tier.
- You supply Chromium: Puppeteer downloads a browser, or you point at one already installed. CI minutes are the cost.
Recommended for?
- Content and marketing sites where the thing to test is a public URL, not a component.
- Nightly crawls via pa11y-ci against a sitemap or a short list of templates.
- Teams that want an axe run without adopting Playwright yet. If Playwright is already there,
@axe-core/playwrightis usually the tighter check. - Pipelines that can store JSON and fail on a non-zero exit.
Conclusion
Pa11y is the small CLI for “open this URL and tell me what axe or HTML CodeSniffer finds.” Use it for sites that are mostly pages. Use axe-core inside the existing browser tests when you already render those pages in Playwright or Cypress. Either way, a green report is a rule-engine result, not a full accessibility audit.