How to Run pa11y Accessibility Tests in CI
pa11y runs accessibility checks by loading pages in headless Chrome through Puppeteer - so its CI requirements are the standard headless-Chrome ones plus a URL to test.
pa11y (and pa11y-ci) audits web pages for accessibility issues by loading them in headless Chrome via Puppeteer. In CI it needs the same Chrome flags and system libraries as any Puppeteer job, plus a reachable URL - either a static build served locally or a deployed environment.
Why it fails in CI
pa11y launches Chrome through Puppeteer, so in a container it fails without --no-sandbox, and on a slim runner it fails on missing Chromium shared libraries. It also needs the page to be reachable - testing localhost requires serving your build first.
No usable sandbox!- containerized Chrome needs--no-sandbox.error while loading shared libraries: libnss3.so- missing Chromium libs.- Timeouts/connection refused - the target URL is not being served.
Install & run it reliably
Pass Chrome args via pa11y’s config, install the Chromium libraries (or use a Puppeteer base image), and serve your build before running pa11y-ci against the URL.
npm ci
# serve the built site, then run pa11y-ci against it
npx serve -l 3000 ./dist &
npx wait-on http://localhost:3000
# .pa11yci.json: { "defaults": { "chromeLaunchConfig":
# { "args": ["--no-sandbox"] } }, "urls": ["http://localhost:3000"] }
npx pa11y-ciCache & speed
Cache the Puppeteer browser download (~/.cache/puppeteer) keyed on the Puppeteer version, and ~/.npm for Node deps. Bake the Chromium system libraries into the image to skip the apt step each run.
- uses: actions/cache@v4
with:
path: ~/.cache/puppeteer
key: puppeteer-${{ hashFiles('**/package-lock.json') }}Common errors
No usable sandbox!→ add--no-sandboxtochromeLaunchConfig.args.libnss3.so/ shared-library errors → install the Chromium system libs or use a Puppeteer image.- Connection refused / timeout → serve your build and
wait-onit before pa11y runs. - Chrome download blocked → cache
~/.cache/puppeteeror use a base image with Chromium.
Key takeaways
- pa11y drives headless Chrome via Puppeteer - apply the standard Chrome CI fixes.
- Add
--no-sandboxin chromeLaunchConfig; install Chromium system libs. - Serve your build and wait-on it before running pa11y-ci.