Free & open source · GitHub Actions + Forgejo

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.

$ npx allyradar scan http://localhost:3000
1

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:

Accessibility / a11y
✗ 1 new/worsened violation(s) at or above “serious” — failing after 2m
Required
Merging is blocked until the regression is fixed. Pre-existing issues never block.
2

One summary comment — updated, never spammed

github-actionsbotcommented 2 minutes ago
♿ AllyRadar accessibility check

Score: 98 → 95 · 1 new issue type(s) · 0 worsened · 0 fixed

PageIssueSeverityElements
/🆕 Images must have alternative textCritical1
▸ Failing elements & how to fix
Scanned 5 page(s) with axe-core (WCAG 2.1 AA). Automated checks catch most — not all — issues.
3

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.

app/page.tsx
96
<img
97
  src="/marketing/issue-report-portion.png"
98
  width={1260}
github-actionsbot

♿ 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-serious

Full 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.