WCAG Accessibility Scanner (axe-core) avatar

WCAG Accessibility Scanner (axe-core)

Pricing

from $3.00 / 1,000 accessibility violation founds

Go to Apify Store
WCAG Accessibility Scanner (axe-core)

WCAG Accessibility Scanner (axe-core)

Crawls a website with headless Chromium, runs axe-core on every page and returns one result per WCAG 2.x A/AA violation with selector, HTML, fix guidance and screenshots. Includes an A–F accessibility grade.

Pricing

from $3.00 / 1,000 accessibility violation founds

Rating

0.0

(0)

Developer

Hesling Reidinga

Hesling Reidinga

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Find out in minutes whether a website breaks accessibility rules — and exactly where. This Actor crawls a site with a real Chromium browser, runs axe-core (the same engine behind Lighthouse and most enterprise accessibility tools) on every page, and returns one result per offending element with the CSS selector, the HTML snippet, a plain-language explanation, a link to the fix, and a screenshot of the element. You also get an A–F accessibility grade for the site.

What it does

  1. Opens your start URL in headless Chromium (1280×900) and follows same-origin links — product, cart, checkout, collection, contact and content pages first — up to the number of pages you choose.
  2. Runs axe-core against WCAG 2.0, 2.1 and 2.2 at levels A and AA on each page. Best-practice-only rules are not included, so every finding maps to a real WCAG success criterion.
  3. Takes a full-page screenshot of every page and an element screenshot for the first three offending elements of each rule.
  4. Writes one dataset row per violation and a SUMMARY record with totals, the grade and the top failing rules.

It respects robots.txt, scans one page at a time with a polite delay, and identifies itself as AccessibilityGradeBot.

Input

FieldTypeDefaultDescription
startUrlstring (required)The page to start from, e.g. https://example.com.
maxPagesinteger5Maximum pages to scan, including the start URL (1–50).
includeScreenshotsbooleantrueStore page and element screenshots and link them from each result.
{
"startUrl": "https://example.com",
"maxPages": 5,
"includeScreenshots": true
}

Output

Dataset — one item per violation

Each row is one element that fails one rule. Sort or filter by impact to prioritise, group by ruleId to plan fixes, or by pageUrl to assign work.

{
"pageUrl": "https://www.w3.org/WAI/demos/bad/before/home.html",
"pageTitle": "Welcome to CityLights! [Inaccessible Home Page]",
"ruleId": "image-alt",
"impact": "critical",
"wcag": ["wcag2a", "wcag111"],
"tags": ["cat.text-alternatives", "wcag2a", "wcag111", "section508", "section508.22.a", "EN-301-549", "EN-9.1.1.1", "ACT"],
"help": "Images must have alternative text",
"helpUrl": "https://dequeuniversity.com/rules/axe/4.13/image-alt",
"description": "Ensure <img> elements have alternative text or a role of none or presentation",
"selector": "#nav > a[href$=\"tickets.html\"] > img",
"html": "<img src=\"./img/tickets.gif\" width=\"85\" height=\"20\">",
"failureSummary": "Fix any of the following:\n Element does not have an alt attribute\n ...",
"screenshotUrl": "https://api.apify.com/v2/key-value-stores/.../records/screenshot-p1-image-alt-1.jpg"
}

impact is one of minor, moderate, serious, critical. wcag lists the WCAG tags (wcag2a = level A, wcag2aa = level AA, wcag111 = success criterion 1.1.1); tags keeps every axe tag, including EN 301 549 and Section 508 references. screenshotUrl is present only when a screenshot was taken for that element (first three elements per rule, visible elements only).

Key-value store

  • SUMMARY — the site-level result:

    {
    "grade": "F",
    "pagesScanned": 2,
    "violations": 6,
    "nodes": 46,
    "byImpact": { "minor": 0, "moderate": 0, "serious": 12, "critical": 34 },
    "seriousNodes": 46,
    "topRules": [
    { "ruleId": "image-alt", "nodes": 33 },
    { "ruleId": "link-name", "nodes": 7 },
    { "ruleId": "color-contrast", "nodes": 2 }
    ],
    "targetUrl": "https://www.w3.org/WAI/demos/bad/before/home.html",
    "platform": "custom",
    "pages": [
    { "url": "https://www.w3.org/WAI/demos/bad/before/home.html", "title": "...", "httpStatus": 200, "loadMs": 283, "violations": 46, "screenshotUrl": "..." }
    ],
    "errors": [],
    "startedAt": "2026-09-19T21:34:10.000Z",
    "finishedAt": "2026-09-19T21:34:18.000Z"
    }

    violations counts distinct rule failures per page; nodes counts offending elements (the number of dataset rows). platform is a best-effort guess (shopify, woocommerce, wix, squarespace, bigcommerce, custom).

  • RESULT — the complete raw scan result (all pages, all rules, all nodes).

  • page-<n>.jpg — full-page screenshot of each scanned page.

  • screenshot-p<n>-<rule>-<k>.jpg — element screenshots.

Grade

The grade is based on the number of serious + critical offending elements across the scanned pages:

GradeSerious + critical elements
A0
B1–3
C4–10
D11–25
Fmore than 25

Use cases

  • Agencies and freelancers — run it on a prospect's site before the first call and open with concrete, screenshot-backed findings; re-run after the fix to prove the improvement.
  • Compliance checks (EAA, ADA, Section 508, AODA) — the European Accessibility Act applies to most consumer-facing e-commerce and services since June 2025, and ADA Title III lawsuits over websites keep rising. A monthly scan gives you a dated, repeatable record of where you stand.
  • E-commerce and SaaS teams — schedule the Actor and pipe the dataset into Slack, a spreadsheet or your issue tracker; the selector and html fields point developers to the exact element.
  • Procurement and audits — get a quick, engine-based baseline before commissioning a manual audit, so the auditor's time goes to what tools can't catch.

Limits and what this is not

  • Automated testing finds roughly 30–40 % of WCAG issues. Tools can check alt attributes, contrast, form labels, ARIA usage, language attributes and similar rules reliably, but they cannot judge whether alt text is meaningful, whether keyboard focus order makes sense, or whether video has accurate captions. A clean scan is a good sign, not a certificate of conformance.
  • One viewport (desktop, 1280×900), no logged-in areas, no interaction with cookie walls or modals beyond what loads by default.
  • Pages that need JavaScript to render are fine (real Chromium), but pages blocked by robots.txt, returning 4xx/5xx, or behind bot protection are skipped and listed in SUMMARY.errors. If no page at all can be scanned the run fails with an explanation.
  • Up to 50 pages per run; screenshots are capped at 60 per run (page screenshots are always kept, element screenshots fill the rest).

Pricing

This Actor is offered as pay per result: you pay a small fixed amount for each violation row written to the dataset, plus nothing else — a clean site costs you (almost) nothing to check. The exact per-result price is shown on the Actor's Apify Store page; with the Apify free plan you can run it without a card. If the Actor is switched to pay-per-event pricing, each dataset row is charged as one violation event; the amount is set in the Apify Console, not in the code.

Support

Something missing — a mobile viewport, authenticated scans, a PDF report? Open an issue on the Actor's page and describe the site type you are testing.


For developers

This Actor lives in the FullAutoBiz pnpm monorepo as apify/wcag-scanner and wraps the workspace package @fab/scanner (Playwright + @axe-core/playwright).

Build strategy: a single esbuild bundle. The Apify platform builds the Actor from this directory alone, without the pnpm workspace, so scripts/build.mjs bundles src/main.ts together with @fab/scanner, @fab/contracts, axe-core and zod into dist/main.js (esbuild --bundle --platform=node --format=esm --external:playwright --external:apify). Only apify and playwright stay external: playwright ships with the apify/actor-node-playwright-chrome:22 base image (with matching browsers), and apify is installed in the Docker build from the generated dist/package.json. The bundle is not minified because axe-core serialises itself with Function#toString() at runtime.

pnpm install # repo root
pnpm --filter @fab/scanner run setup # once: playwright install chromium
pnpm --filter @fab/apify-wcag-scanner build # -> dist/main.js + dist/package.json
cd apify/wcag-scanner
echo '{"startUrl":"https://www.w3.org/WAI/demos/bad/before/home.html","maxPages":2}' \
> storage/key_value_stores/default/INPUT.json
pnpm exec apify run --purge # local run; results in ./storage

dist/main.js and dist/package.json are deliberately not git-ignored in this directory (see .gitignore) because apify push uploads the directory as-is and .actor/Dockerfile only copies those two files. Always run build before apify push. storage/ and apify_storage/ (local run output) are ignored.