Accessibility regressions should fail CI.
Nobody notices accessibility breaking, because nothing turns red. AllyRadar scans your PR against the base branch with axe-core in a real browser, comments on the exact line, and blocks the merge — only for issues the PR introduces.
A PR breaks something — the check turns red
Both the PR and its base branch are built and scanned inside the runner — no deploy, no preview environment needed. This is real output from AllyRadar's own CI catching a deliberately broken PR:
One summary comment — updated, never spammed
Score: 98 → 95 · 1 new issue type(s) · 0 worsened · 0 fixed
| Page | Issue | Severity | Elements |
|---|---|---|---|
/ | 🆕 Images must have alternative text | Critical | 1 |
A review comment on the offending line
The failing rendered HTML is matched back to your source in the diff. Readable by humans — and by your coding agent: “look at the PR comments and fix them” just works.
<img
src="/marketing/issue-report-portion.png"
width={1260}♿ Critical: Images must have alternative text image-alt
<img src="/marketing/issue-report-portion.png" width="1260" …>
Fix: Element does not have an alt attribute · WCAG guidance →
Adopt it on a messy codebase
Issues are diffed against the base branch — 400 pre-existing violations won’t block anyone. Only new or worsened issues fail the check.
Forgejo & Gitea, out of the box
The forge is auto-detected from the CI environment. Same command posts comments on GitHub or your self-hosted instance.
The same engine as production
Open-source, MIT, powered by axe-core. Identical scoring to the AllyRadar dashboard, so CI numbers match monitoring numbers.
Set up in one workflow file
# .github/workflows/accessibility.yml (Forgejo: .forgejo/workflows/)
name: Accessibility
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-node@v4
with: { node-version: 22, cache: npm }
- run: npm ci && npx playwright install --with-deps chromium
- run: | # scan the PR
npm run build
npx allyradar scan http://localhost:3000 --start "npm start" \
--pages "/,/pricing" --out head.json
- run: | # scan the base branch
git checkout ${{ github.event.pull_request.base.sha }} -- .
npm ci && npm run build
npx allyradar scan http://localhost:3000 --start "npm start" \
--pages "/,/pricing" --out base.json
- env: { GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} }
run: | # comment + line reviews + gate
npx allyradar diff base.json head.json --markdown report.md
npx allyradar comment report.md
npx allyradar review base.json head.json
npx allyradar diff base.json head.json --fail-on new-seriousFull recipes for GitHub and Forgejo in the repo →
CI catches what changes. Monitoring catches what drifts.
A plugin update, a CMS edit, a marketing page shipped outside the repo — most accessibility regressions never go through a PR. AllyRadar monitors your deployed sites continuously with the same engine: scheduled scans, email alerts, client-ready reports.