Skip to content

GitHub Action — accessibility scan + VPAT auto-update

The Wholisphere Scan action runs the agent against your site (sitemap or URL list), submits findings to your org’s scan history, and optionally fails the build when WCAG conformance regresses since the last scan. The next render of your VPAT (POST /v1/vpat) reflects the new findings immediately — no manual re-issue.

Quick start

.github/workflows/accessibility-scan.yml
name: Accessibility scan
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: wholisphere/scanner-runner@v0
with:
api-key: ${{ secrets.WHOLISPHERE_API_KEY }}
product-name: Acme App
product-version: ${{ github.sha }}
sitemap: https://acme.test/sitemap.xml

That’s it. The action installs @wholisphere.ai/scanner-runner, walks your sitemap, runs the agent’s reference evaluators against each page, and submits findings.

Add regression gating

To fail the build when conformance regresses since the previous scan:

- uses: wholisphere/scanner-runner@v0
with:
api-key: ${{ secrets.WHOLISPHERE_API_KEY }}
product-name: Acme App
product-version: ${{ github.sha }}
sitemap: https://acme.test/sitemap.xml
fail-on-regression: 'true'

The action looks up your most recent completed scan for the same product, compares findings via GET /v1/scans/:id/diff, and exits non-zero when any criterion regressed (e.g., Supports → Partially Supports or Partially Supports → Does Not Support).

Scanning a fixed URL list

Use urls instead of sitemap:

- uses: wholisphere/scanner-runner@v0
with:
api-key: ${{ secrets.WHOLISPHERE_API_KEY }}
product-name: Acme App
product-version: ${{ github.sha }}
urls: |
https://acme.test/
https://acme.test/pricing
https://acme.test/about

Newlines and commas are both accepted. URLs must be absolute (http:// or https://).

Inputs

InputRequiredDescription
api-keyyesWholisphere API key (issue from Dashboard → Keys → Create)
base-urlnoBackend base URL. Default https://api.wholisphere.ai.
product-nameconditionalRequired when scan-id is omitted.
product-versionconditionalRequired when scan-id is omitted. Often ${{ github.sha }}.
scan-idconditionalAppend to an existing scan instead of creating one.
sitemapconditionalSitemap URL — pick this OR urls.
urlsconditionalNewline- or comma-separated URLs — pick this OR sitemap.
build-refnoDefaults to ${{ github.sha }}.
max-concurrencynoParallel page count. Default 3.
fail-on-regressionnoWhen 'true', fail the workflow on any regression vs the previous scan. Default 'false'.
runner-versionnoPin a specific @wholisphere.ai/scanner-runner version. Default latest.

Outputs

OutputDescription
scan-idThe scan that was created or appended to.
page-countPages successfully scanned.
finding-countTotal findings emitted.

What the workflow summary looks like

The action writes a step summary to your workflow run page:

Wholisphere Scan

MetricValue
Scan IDabc123def456
Pages scanned24
Findings emitted87
Build refa3f2c91…

Regression check — Compared scan abc123 against xyz7890 criterion(s) regressed.

Combining with the VPAT

After every successful scan, you can render the latest VPAT directly:

Terminal window
curl -X POST https://api.wholisphere.ai/v1/vpat \
-H "x-api-key: $WHOLISPHERE_API_KEY" \
-H "accept: text/html" \
-d '{
"product": {
"productName": "Acme App",
"productVersion": "1.4.2",
"vendorName": "Acme Inc.",
"contactInfo": "a11y@acme.test",
"reportDate": "2026-04-26",
"productDescription": "An ordering app.",
"standards": ["WCAG 2.2 Level AA"],
"edition": "INT"
},
"findings": []
}' > vpat.html

The findings array can be empty — the route auto-pulls the latest scan’s findings. The generated VPAT reflects only what the scan found; nothing is derived, measured, or inferred from an agent, and open issues are disclosed rather than filled in.

See also