WCAG Accessibility Auditor
Crawl any website and audit it against WCAG 2.1 accessibility standards. Checks 30 rules across four severity levels, scores each site 0–100 with letter grades A through F, and provides element-level violations with CSS selectors and fix recommendations. Test multiple websites in a single run — no browser extensions or manual page-by-page testing required.
Maintenance Pulse
90/100Cost Estimate
How many results do you need?
Pricing
Pay Per Event model. You only pay for what you use.
| Event | Description | Price |
|---|---|---|
| audit-completed | Charged per domain audited. Includes WCAG violation analysis across 4 severity levels, audit scores, grades, and remediation guidance. | $0.25 |
Example: 100 events = $25.00 · 1,000 events = $250.00
Documentation
Crawl any website and audit it against WCAG 2.1 accessibility standards. Checks 30 rules across four severity levels, scores each site 0–100 with letter grades A through F, and provides element-level violations with CSS selectors and fix recommendations. Test multiple websites in a single run — no browser extensions or manual page-by-page testing required.
Why use WCAG Accessibility Auditor?
Accessibility compliance is required by law in many jurisdictions (ADA, Section 508, EN 301 549) but testing is tedious. Browser extensions check one page at a time. Enterprise tools cost thousands per year. This actor runs in the cloud, audits multiple pages per domain, tests multiple websites in a single batch, and produces machine-readable JSON you can pipe into dashboards, Jira, or CI/CD pipelines. Get a scored audit report with actionable fix recommendations for every violation.
Features
- 30 accessibility rules covering images, forms, headings, ARIA, navigation landmarks, multimedia, tables, and document structure
- Four severity levels — critical, serious, moderate, and minor — with configurable threshold filtering
- WCAG 2.1 Levels A, AA, and AAA — choose the conformance level that matches your requirements
- Multi-page crawling — automatically discovers and audits subpages, up to 50 per domain
- Accessibility score (0–100) with letter grade (A through F) for quick comparison across sites
- Actionable fix recommendations for every violation, written in plain language
- Element-level detail — each violation includes the HTML snippet and CSS selector for easy developer handoff
- Batch auditing — test dozens of websites in a single run
- Proxy support — audit geo-restricted or rate-limited sites using Apify Proxy
Use Cases
Compliance auditing
Audit your website against WCAG 2.1 AA (the most common legal requirement) before a compliance deadline. The severity filtering lets you prioritize critical and serious violations first.
Competitor benchmarking
Score competing websites side-by-side and identify accessibility advantages your competitors are missing. Higher accessibility scores improve SEO and user experience.
CI/CD integration
Run accessibility audits automatically after each deployment via the API. Fail the pipeline if the score drops below a threshold.
Agency reporting
Web agencies can audit client websites in batch and generate structured compliance reports with scores, violation counts, and prioritized fix lists.
Regression monitoring
Schedule weekly audits to catch accessibility regressions introduced by new code deployments. Track scores over time to ensure continuous improvement.
Vendor evaluation
Score third-party tools and SaaS platforms for accessibility before procurement decisions. Filter by critical violations to identify deal-breakers.
How to Use
- Navigate to the actor's input page on Apify Console
- Enter one or more website URLs (e.g.,
https://example.com) - Adjust Max pages per domain to control audit depth (default: 5)
- Select your target WCAG conformance level (A, AA, or AAA)
- Set the Minimum severity if you only want serious or critical issues
- Click Start to run the audit
- View results in the Dataset tab or download as JSON, CSV, or Excel
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
urls | string[] | Yes | — | Website URLs to audit. Bare domains auto-prefixed with https:// |
maxPagesPerDomain | integer | No | 5 | Maximum pages to crawl and audit per domain (1–50) |
wcagLevel | string | No | AA | Target conformance level: A (minimum), AA (standard), AAA (enhanced) |
severityThreshold | string | No | minor | Minimum severity: minor (all), moderate, serious, critical (critical only) |
proxyConfiguration | object | No | Apify Proxy | Proxy configuration for crawling |
Input Examples
Standard compliance audit:
{
"urls": ["https://example.com"],
"maxPagesPerDomain": 10,
"wcagLevel": "AA",
"severityThreshold": "minor"
}
Quick critical-only check for multiple sites:
{
"urls": ["example.com", "competitor1.com", "competitor2.com"],
"maxPagesPerDomain": 3,
"wcagLevel": "AA",
"severityThreshold": "critical"
}
Thorough AAA audit:
{
"urls": ["https://example.com"],
"maxPagesPerDomain": 50,
"wcagLevel": "AAA",
"severityThreshold": "minor"
}
Input Tips
- Start with the homepage URL only. The actor automatically discovers and crawls subpages.
- Use Level AA unless you have a specific reason for A or AAA. AA covers most legal requirements (ADA, Section 508, EN 301 549).
- Increase maxPagesPerDomain for thorough audits. Default of 5 is good for quick checks; use 20-50 before compliance deadlines.
- Filter by severity when fixing issues. Start with critical and serious violations for highest impact.
Output Example
Each item in the dataset represents one audited domain:
{
"url": "https://example.com",
"domain": "example.com",
"score": 72,
"grade": "C",
"totalViolations": 14,
"uniqueRulesViolated": 7,
"violationsBySeverity": {
"critical": 3,
"serious": 4,
"moderate": 5,
"minor": 2
},
"violations": [
{
"ruleId": "img-alt",
"description": "Images must have alt text",
"severity": "critical",
"wcagCriteria": "1.1.1",
"wcagLevel": "A",
"element": "<img src=\"/hero.jpg\" class=\"banner-image\">",
"selector": "img.banner-image",
"fix": "Add an alt attribute to all <img> elements. Use alt=\"\" for decorative images.",
"pageUrl": "https://example.com"
}
],
"summary": {
"critical": ["img-alt: Images must have alt text", "input-label: Form inputs must have associated labels"],
"serious": ["heading-order: Heading levels should not skip"],
"moderate": ["link-purpose: Links should not use generic text like 'click here'"],
"minor": ["landmark-main: Page should have a <main> landmark"]
},
"pagesAudited": 5,
"wcagLevel": "AA",
"auditedAt": "2025-01-15T10:30:00.000Z"
}
Output Fields
Domain-Level Fields
| Field | Type | Description |
|---|---|---|
url | string | Starting URL for this domain |
domain | string | Normalized domain name |
score | number | Accessibility score (0–100) |
grade | string | Letter grade: A (90-100), B (80-89), C (70-79), D (60-69), F (<60) |
totalViolations | number | Total violation instances found across all pages |
uniqueRulesViolated | number | Number of distinct accessibility rules violated |
violationsBySeverity | object | Violation counts broken down by severity level |
summary | object | Lists of violated rule descriptions grouped by severity |
pagesAudited | number | Number of pages successfully audited |
wcagLevel | string | Target conformance level used (A, AA, or AAA) |
auditedAt | string | ISO 8601 timestamp of the audit |
Violation-Level Fields
| Field | Type | Description |
|---|---|---|
ruleId | string | Rule identifier (e.g., img-alt, heading-order) |
description | string | Human-readable rule description |
severity | string | critical, serious, moderate, or minor |
wcagCriteria | string | WCAG success criterion number (e.g., 1.1.1, 2.4.4) |
wcagLevel | string | WCAG level of this criterion (A, AA, or AAA) |
element | string | HTML snippet of the violating element (truncated to 120 chars) |
selector | string | CSS selector to locate the element (e.g., img.banner-image, #header) |
fix | string | Plain-language fix recommendation |
pageUrl | string | URL of the page where this violation was found |
Programmatic Access (API)
Python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("ryanclinton/wcag-accessibility-auditor").call(run_input={
"urls": ["https://example.com", "https://competitor.com"],
"maxPagesPerDomain": 10,
"wcagLevel": "AA",
"severityThreshold": "minor",
})
for site in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"{site['domain']}: Score {site['score']}/100 ({site['grade']})")
print(f" Violations: {site['totalViolations']} ({site['uniqueRulesViolated']} rules)")
for v in site["violations"]:
if v["severity"] == "critical":
print(f" CRITICAL: {v['description']} on {v['pageUrl']}")
JavaScript
import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "YOUR_API_TOKEN" });
const run = await client.actor("ryanclinton/wcag-accessibility-auditor").call({
urls: ["https://example.com", "https://competitor.com"],
maxPagesPerDomain: 10,
wcagLevel: "AA",
severityThreshold: "minor",
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((site) => {
console.log(`${site.domain}: ${site.score}/100 (${site.grade})`);
console.log(` Critical: ${site.violationsBySeverity.critical}`);
console.log(` Serious: ${site.violationsBySeverity.serious}`);
});
cURL
# Start the audit
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~wcag-accessibility-auditor/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://example.com"],
"maxPagesPerDomain": 10,
"wcagLevel": "AA",
"severityThreshold": "minor"
}'
# Fetch results (replace DATASET_ID from the run response)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
How It Works
Crawling
A CheerioCrawler starts from each input URL (labeled HOMEPAGE), audits the page, then discovers subpages via enqueueLinks with same-domain filtering. Subpages are audited up to maxPagesPerDomain. The crawler runs with 10 concurrent workers at 120 requests/minute.
Rule Engine
Each page is checked against 30 rules organized by severity. Rules receive the Cheerio $ DOM object and return an array of violations, each with the offending HTML element and a CSS selector. Rules are filtered by the target WCAG level — Level A runs 28 rules, Level AA runs all 30, Level AAA runs all 30.
Scoring Algorithm
The score starts at 100 and deducts points based on unique rules violated (not per-instance counts). This means a site with 50 images missing alt text gets the same penalty as a site with 1 — both violated the img-alt rule once.
| Severity | Penalty per Rule | Maximum Deduction |
|---|---|---|
| Critical | -10 points | -40 (capped) |
| Serious | -5 points | -25 (capped) |
| Moderate | -3 points | -15 (capped) |
| Minor | -1 point | -10 (capped) |
Minimum possible score: 10 (all caps hit: 100 - 40 - 25 - 15 - 10).
| Grade | Score Range |
|---|---|
| A | 90–100 |
| B | 80–89 |
| C | 70–79 |
| D | 60–69 |
| F | Below 60 |
Results Aggregation
After crawling, violations from all pages are aggregated per domain. A summary groups violated rules by severity. The score and grade are calculated from the unique rules violated across all audited pages.
Accessibility Rules Reference
Critical Rules (6)
| Rule ID | Description | WCAG | Fix |
|---|---|---|---|
img-alt | Images must have alt text | 1.1.1 (A) | Add alt attribute to <img>. Use alt="" for decorative images |
input-label | Form inputs must have associated labels | 1.3.1 (A) | Add <label>, aria-label, or aria-labelledby |
button-name | Buttons must have discernible text | 4.1.2 (A) | Add text, aria-label, or aria-labelledby to buttons |
link-name | Links must have discernible text | 2.4.4 (A) | Add text or aria-label to <a> tags |
document-title | Page must have a <title> element | 2.4.2 (A) | Add descriptive <title> in <head> |
html-lang | <html> must have a lang attribute | 3.1.1 (A) | Add lang="en" (or appropriate code) to <html> |
Serious Rules (8)
| Rule ID | Description | WCAG | Fix |
|---|---|---|---|
heading-order | Heading levels should not skip | 1.3.1 (A) | Use sequential heading levels (h1 → h2 → h3) |
empty-heading | Headings must not be empty | 1.3.1 (A) | Add text content or remove empty headings |
duplicate-id | Element IDs must be unique | 4.1.1 (A) | Ensure all id attributes are unique |
meta-viewport | Viewport must not disable user scaling | 1.4.4 (AA) | Remove user-scalable=no, set maximum-scale ≥ 2 |
aria-valid-attr | ARIA attributes must be valid | 4.1.2 (A) | Use only valid ARIA attributes from WAI-ARIA spec |
aria-roles | ARIA role values must be valid | 4.1.2 (A) | Use only valid role values from WAI-ARIA spec |
frame-title | Frames/iframes must have a title | 2.4.1 (A) | Add title attribute to <iframe> elements |
select-name | Select elements need accessible name | 1.3.1 (A) | Add <label>, aria-label, or title to <select> |
Moderate Rules (10)
| Rule ID | Description | WCAG | Fix |
|---|---|---|---|
html-lang-valid | Lang attribute must be valid BCP 47 | 3.1.1 (A) | Use valid language codes (e.g., "en", "fr") |
tabindex-positive | Avoid positive tabindex values | 2.4.3 (A) | Use tabindex="0" or tabindex="-1" only |
link-purpose | Avoid generic link text ("click here") | 2.4.4 (A) | Use descriptive link text |
list-structure | Lists must contain only <li> children | 1.3.1 (A) | Ensure <ul>/<ol> only contain <li> |
table-header | Data tables should have <th> cells | 1.3.1 (A) | Add <th> elements and <thead> rows |
autocomplete-valid | Autocomplete values must be valid | 1.3.5 (AA) | Use standard autocomplete values |
meta-refresh | No auto-refresh via <meta> | 2.2.1 (A) | Remove <meta http-equiv="refresh"> |
image-redundant-alt | Alt text shouldn't duplicate surrounding text | 1.1.1 (A) | Use alt="" when text is redundant |
textarea-label | Textareas need accessible name | 1.3.1 (A) | Add <label> or aria-label |
svg-img-alt | SVGs with role="img" need accessible text | 1.1.1 (A) | Add aria-label or <title> to SVG |
Minor Rules (6)
| Rule ID | Description | WCAG | Fix |
|---|---|---|---|
landmark-main | Page should have <main> landmark | 1.3.1 (A) | Add <main> or role="main" |
landmark-banner | Page should have <header> landmark | 1.3.1 (A) | Add <header> or role="banner" |
bypass-blocks | Page should have skip navigation link | 2.4.1 (A) | Add "Skip to main content" link |
video-caption | Videos should have captions | 1.2.2 (A) | Add <track kind="captions"> |
audio-caption | Audio should have text alternatives | 1.2.1 (A) | Provide transcript or <track> |
landmark-nav | Navigation should use <nav> element | 1.3.1 (A) | Wrap navigation in <nav> |
How Much Does It Cost?
The actor uses minimal resources (256 MB memory, Cheerio-based parsing):
| Scenario | Sites | Pages Each | Estimated Cost | Run Time |
|---|---|---|---|---|
| Quick check | 1 | 5 | ~$0.005 | ~20 seconds |
| Standard audit | 1 | 20 | ~$0.01 | ~1 minute |
| Competitor comparison | 10 | 5 each | ~$0.02 | ~1 minute |
| Thorough batch | 10 | 20 each | ~$0.05 | ~3 minutes |
| Large batch | 50 | 10 each | ~$0.10 | ~8 minutes |
Tips
- Start with the homepage. The actor discovers subpages automatically.
- Fix critical and serious first. These have the highest impact on users with disabilities and the biggest scoring penalties.
- Schedule regular audits to catch regressions after code deployments.
- Compare scores over time. The 0–100 score makes tracking progress straightforward.
- Use severity filtering to focus developer attention. Show only critical issues in sprint planning; use the full report for quarterly reviews.
- Export to Jira via webhook or Zapier to auto-create tickets for each critical violation.
Combine with Other Actors
| Actor | How to combine |
|---|---|
| Website Content to Markdown | Convert website content to Markdown while auditing accessibility — parallel workflows |
| Website Change Monitor | Detect page changes, then trigger accessibility re-audit for modified pages |
| SERP Rank Tracker | Correlate accessibility scores with search rankings to measure SEO impact |
| Website Tech Stack Detector | Identify CMS and frameworks — certain tech stacks have common accessibility patterns |
| Shopify Store Intelligence | Audit Shopify stores for accessibility alongside product and theme analysis |
Limitations
- HTML-only analysis — uses CheerioCrawler, not a headless browser. Cannot evaluate JavaScript-rendered content, dynamic ARIA states, or client-side interactions.
- No color contrast checking — requires visual rendering to compute contrast ratios, which Cheerio cannot do.
- No keyboard navigation testing — cannot simulate Tab key traversal or focus management.
- ~30-40% of WCAG issues — automated tools can detect roughly a third of accessibility problems. Many issues (meaningful alt text, logical focus order, cognitive load) require human judgment.
- No authenticated content — only audits publicly accessible pages.
- Rule count — checks 30 rules, not the full WCAG 2.1 specification. Covers the most impactful and automatable criteria.
Responsible Use
- This actor only accesses publicly visible web pages.
- Accessibility audit results should be used constructively to improve web accessibility, not to shame or penalize websites.
- Automated audits are a starting point — always follow up with manual testing and assistive technology testing for full WCAG compliance.
- See Apify's guide on web scraping legality for general guidance.
FAQ
What WCAG rules does this actor check? 30 rules across four severity tiers. See the Accessibility Rules Reference section above for the complete list with WCAG criteria numbers and fix recommendations.
How is the score calculated? Score starts at 100 and deducts points per unique rule violated (not per instance). Critical: -10 each (cap 40), serious: -5 (cap 25), moderate: -3 (cap 15), minor: -1 (cap 10). Minimum possible score is 10.
Does this replace a manual accessibility audit? No. Automated tools catch roughly 30-40% of WCAG issues. Many problems — meaningful alt text, logical focus order, sufficient color contrast in dynamic states — require human judgment. Use this actor as a first pass, then follow up with manual and assistive technology testing.
Can I audit sites that require authentication? No. The actor audits publicly accessible pages only.
How does this compare to axe-core or Lighthouse? Similar rule coverage to axe-core's best-practice set. Key difference: runs in the cloud, audits multiple sites in batch, and produces structured JSON for integration. Lighthouse also includes performance metrics this actor doesn't cover.
What WCAG level should I use? Level AA for most cases. It covers the requirements of ADA, Section 508, EN 301 549, and most accessibility laws. Level A is the bare minimum. Level AAA is enhanced and rarely required by law.
Integrations
- Slack — get notified when audits find critical violations or scores drop
- Google Sheets — export results for tracking and reporting
- Zapier — create Jira tickets, send Slack alerts, or trigger workflows on completion
- Make — connect audit results to multi-step automation workflows
- Apify API — trigger audits from CI/CD pipelines or custom applications
- Webhooks — POST results to your endpoint on completion
- GitHub Actions — run audits as part of deployment pipelines
How it works
Configure
Set your parameters in the Apify Console or pass them via API.
Run
Click Start, trigger via API, webhook, or set up a schedule.
Get results
Download as JSON, CSV, or Excel. Integrate with 1,000+ apps.
Use cases
Sales Teams
Build targeted lead lists with verified contact data.
Marketing
Research competitors and identify outreach opportunities.
Data Teams
Automate data collection pipelines with scheduled runs.
Developers
Integrate via REST API or use as an MCP tool in AI workflows.
Related actors
Bulk Email Verifier
Verify email deliverability at scale. MX record validation, SMTP mailbox checks, disposable and role-based detection, catch-all flagging, and confidence scoring. No external API costs.
GitHub Repository Search
Search GitHub repositories by keyword, language, topic, stars, forks. Sort by stars, forks, or recently updated. Returns metadata, topics, license, owner info, URLs. Free API, optional token for higher limits.
Website Content to Markdown
Convert any website to clean Markdown for RAG pipelines, LLM training, and AI apps. Crawls pages, strips boilerplate, preserves headings, tables, and code blocks. GFM support.
Website Tech Stack Detector
Detect 100+ web technologies on any website. Identifies CMS, frameworks, analytics, marketing tools, chat widgets, CDNs, payment systems, hosting, and more. Batch-analyze multiple sites with version detection and confidence scoring.
Ready to try WCAG Accessibility Auditor?
Start for free on Apify. No credit card required.
Open on Apify Store