Fixing accessibility once isn't enough: at the next pull request, a regression can break everything without anyone seeing it. The fix is to audit automatically on every PR. axe-core runs as a CLI on any CI runner, the integration takes about fifteen minutes, and it blocks the merge as soon as a critical regression appears.
GitHub Actions snippet
name: a11y
on: [pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci && npm run build
- run: npx @axe-core/cli http://localhost:3000 \
--exit \
--tags wcag2a,wcag2aa,wcag21aaWhat each step does
- →`on: [pull_request]`: the audit triggers on every PR, before the merge
- →`npm ci && npm run build`: install and build the app, then serve it locally
- →`@axe-core/cli`: runs axe on the served URL
- →`--exit`: returns a non-zero error code if violations are found — that's what makes the PR fail (and therefore block)
- →`--tags`: limits the analysis to WCAG A and AA rules, the legally relevant scope
Making it actually block
The `--exit` only blocks if the CI is set as a required check. In the protected-branch settings, mark the "a11y" job as required for the merge. Without that, the red shows but nothing stops anyone from merging — half the benefit is lost.
⚠ But it's not enough
axe-core measures WCAG, not the RGAA (the French framework), and the WCAG-to-RGAA mapping isn't 1-to-1. It doesn't crawl your site by itself: you have to feed it the URLs to test. And it only covers 30 to 40% of the criteria — the rest needs a human. The axe-core CI is an anti-regression guardrail, not a full compliance audit.
Frequently asked questions
How many URLs should axe run on?
At minimum your key templates: home, category page, product page, cart, checkout. Testing one example of each page type catches most regressions without bloating the CI.
Will axe generate false positives?
axe-core is known for its low false-positive rate, but no tool is perfect. Start in blocking mode on "critical" and "serious" violations, then broaden as you clean up the base.
Does it replace an RGAA audit?
No. The CI prevents regressing between two audits, but it doesn't measure full RGAA compliance or the criteria that need a human. See it as a complement to continuous monitoring, not a substitute.
Should the CI fail on the very first violation?
At the start, block only on "critical" and "serious" violations, while you clear the debt. Once the base is clean, you can tighten to block on everything. Blocking on everything from the start often freezes an existing site's CI in permanent red.
How to test a page that requires a login?
Serve a test session, or inject an authentication cookie into the job before running axe on the logged-in pages (cart, checkout). That's where the worst non-conformities hide: the effort is worth it.
Does axe-core slow the pipeline much?
No: analysing a page takes a few seconds. The real cost is the `npm run build` and starting the server, not axe itself. Testing 5 key templates typically adds less than a minute to the job.
Can it be used outside GitHub Actions?
Yes. `@axe-core/cli` runs on any runner — GitLab CI, CircleCI, Jenkins, Bitbucket. Only the pipeline file's syntax changes; the axe command stays the same.
Compare axe-core alone with full RGAA monitoring.
→ See the comparison