GitHub Action
Run an accessibility scan as a step in your own workflow, and fail the build when the score drops.
Overview
adaguard-io/accessibility-action@v1 scans a URL against WCAG 2.2, ADA, Section 508 and EAA, then exposes the score and issue counts as step outputs. It is a step in a workflow you control, so it runs wherever you put it — after a deploy, on a schedule, on a tag, or on a pull request.
Fails the build
Below min-score exits non-zero. Set min-score: 0 to report without gating.
Step outputs
11 outputs, so later steps can branch on the result.
Any trigger
Your workflow, your triggers — not limited to pull requests.
Quick Start
Add this as .github/workflows/accessibility.yml. The only required inputs are api-key and url.
The URL must be publicly reachable — the scanner runs on our infrastructure, not on your runner, so localhost and private addresses are rejected. Scan a deployed preview or staging URL.
Getting an API Key
- Create a key at Settings → API Keys. It is shown once.
- In your repository, go to Settings → Secrets and variables → Actions and add it as a secret named
ADAGUARD_API_KEY. - Reference it as
${{ secrets.ADAGUARD_API_KEY }}— never inline the key.
Each run spends one scan from your monthly quota, unless idempotency-key matches a scan from the last 24 hours.
Scanning Behind a Login
Capture a session once at Settings → Authenticated Targets, copy its target key, and pass it as auth-target. Use latest for your most recent session.
auth-status: expired_fallback with passed: false — so a silently-public scan cannot pass as an authenticated one. Recapture the session to fix it.Crawling Many Pages
scan-mode is single by default, which ignores max-pages. To scan more than one page you must change both.
Budget roughly 10 seconds per page unauthenticated and 13 seconds per page authenticated, so 100 pages takes 15–20 minutes. Raise max-wait-minutes past the default 30 for large crawls, or the job gives up before the scan finishes.
Gating the Build
The step exits non-zero when the score is below min-score. Two things worth knowing before you pick a number:
- ·Start from your current score, not from 100. Run once with
min-score: 0, then set the threshold at or just below what you actually score. A gate that has never passed gets ignored. - ·A scanner error is not an accessibility regression.
fail-on-scan-errorisfalseby default so infrastructure trouble does not block your merge. Set ittrueif you would rather know.
Inputs
| Input | Default | Description |
|---|---|---|
api-keyrequired | — | ADAGuard API key. Store it as a repository secret. Requires a Professional plan or above. |
urlrequired | — | URL to scan. Must be publicly reachable — private and internal addresses are rejected. |
min-score | 80 | Fail the build when the score falls below this (0-100). |
scan-mode | single | single (the given URL only), crawl (follow internal links), sitemap (read sitemap.xml, then crawl), or layout (crawl, then skip structurally duplicate pages). |
max-pages | 1 | Maximum pages to scan. Ignored when scan-mode is "single". Your plan caps this. |
include-subdomains | true | Crawl subdomains of the target host. Set false to stay on the exact hostname. Crawl modes only. |
auth-target | — | Scan pages behind a login. Pass a target_key from Settings → Authenticated Targets, or "latest" for your most recent session. Requires a Professional plan or above. |
fail-on-scan-error | false | Fail the build when the scanner itself errors. Off by default, because that is an infrastructure problem rather than an accessibility regression. |
comment-on-pr | true | Post results as a pull request comment, updated in place on each push. Needs pull-requests:write. |
max-wait-minutes | 30 | Give up waiting after this many minutes, so a stuck scan cannot burn your runner budget. |
idempotency-key | — | Dedupe key. If a scan was already created with this key in the last 24h, its result is reused instead of spending another scan from your quota. Defaults to this run + attempt, so re-running a job after a network flake does not cost a second scan. Set to a unique value (e.g. the commit SHA) to force a fresh scan, or leave blank to disable. |
api-base | https://api.adaguard.io | API base URL. Change only when testing against a non-production instance. |
Outputs
Give the step an id, then read ${{ steps.<id>.outputs.<name> }}.
| Output | Description |
|---|---|
score | Accessibility score out of 100. Empty when the scan errored. |
passed | Whether the scan met min-score. Also false when an authenticated scan fell back to public pages. |
critical | Count of critical issues. |
warning | Count of warnings. |
info | Count of informational issues. |
pages | Pages actually scanned. |
scan-id | Scan ID, for fetching the report from the API later. |
scan-status | completed or failed. |
auth-status | not_requested, authenticated, expired_fallback, or public_only. |
dashboard-url | Human-readable report. Requires signing in to the account that owns the API key. |
report-url | JSON report endpoint, for fetching full results with your API key. |
Deciding for yourself
Action vs GitHub App
Both scan and report into GitHub. They differ in who decides when a scan runs.
| GitHub Action | GitHub App | |
|---|---|---|
| Setup | A workflow file you write | Install once, no config |
| Runs on | Any workflow trigger | Pull requests |
| URL | You specify it | Auto-detected preview, or .adaguard.yml |
| Result | Step outputs + build exit code | PR comment + Check Run |
| Control | Full — branch on any output | Thresholds via .adaguard.yml |
| Plan | Professional and above | All plans |
They are not exclusive — the App for a zero-config signal on every PR, the Action for a gate you control. See the GitHub App docs.
Troubleshooting
Authenticated target not found (HTTP 404)
The auth-target value does not match a saved target. Copy the exact key from Settings → Authenticated Targets, or use "latest".
Scan did not finish within N minutes
The crawl outlasted max-wait-minutes. Raise it, or lower max-pages. A 100-page crawl needs about 20 minutes.
auth-status came back expired_fallback
The saved session expired, so only public pages were scanned and passed is false. Recapture the session at Settings → Authenticated Targets.
Fewer pages scanned than max-pages
The crawler only found that many linked pages, or some were skipped as non-HTML or duplicate layouts. scan-mode: single always scans exactly one.
The PR comment never appears
The job needs permissions: pull-requests: write, and comment-on-pr must not be false. Forked-PR runs cannot comment — that is a GitHub restriction.
401 or 403 from the API
The key is missing, revoked, or on a plan below Professional. Check the secret name matches what the workflow references.
