# Website Accessibility Checker (`automation-lab/website-accessibility-wcag-audit`) Actor

Audit rendered public webpages with axe-core and export WCAG violations, impacts, affected selectors, evidence, rule references, and pass summaries.

- **URL**: https://apify.com/automation-lab/website-accessibility-wcag-audit.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.40 / 1,000 page auditeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Website Accessibility Checker

Audit rendered public webpages and export machine-readable WCAG findings with the **Website Accessibility Checker** Actor.

It loads each supplied URL in Chromium, runs the industry-standard axe-core engine against the rendered DOM, and returns one structured page record containing violations, impacts, affected CSS selectors, HTML evidence, rule references, and pass summaries.

Use the results for one-time accessibility reviews, release checks, scheduled regression monitoring, spreadsheets, dashboards, and automated data pipelines.

### What does this Actor do?

The Actor performs an automated accessibility audit of each submitted public webpage.

For every successfully rendered page, it:

1. validates that the URL resolves only to public network addresses;
2. renders the page in a real Chromium browser;
3. waits for the selected page-readiness milestone and render delay;
4. injects axe-core into the final DOM;
5. runs the selected WCAG rule tags;
6. groups failed rules by impact;
7. records affected selectors, bounded HTML evidence, and fix summaries;
8. returns pass and manual-review counts;
9. optionally includes detailed passed and incomplete rules.

The Actor does not treat a browser challenge or navigation failure as a clean accessibility result.

### Who is it for?

#### Accessibility and compliance teams

Export stable rule IDs, WCAG criteria, impact levels, selectors, and references for triage and recurring reviews.

#### Developers and QA engineers

Add rendered-page accessibility checks to release workflows and compare structured results between versions.

#### Agencies and consultants

Audit batches of client-owned public pages and deliver machine-readable evidence alongside human review.

#### Data and automation teams

Send dataset rows to spreadsheets, databases, webhooks, or BI tools without parsing a visual report.

This is an automated testing aid, not a certification service or legal opinion.

### Why use this website accessibility checker?

- **Rendered DOM:** audits JavaScript-generated interfaces, not only source HTML.
- **Structured evidence:** outputs rule IDs, WCAG criteria, CSS selectors, HTML snippets, and failure summaries.
- **Repeatable fields:** suitable for schedules and regression comparisons.
- **Explicit uncertainty:** axe-core `incomplete` checks can be retained for manual review.
- **Pass summaries:** always returns the pass count and can include compact passed-rule records.
- **Batch safe:** one failed page does not erase successful results from other pages.
- **SSRF protection:** rejects local, private, reserved, and credential-bearing destinations, including redirect and subresource hops.
- **No automatic paid proxy:** costs do not silently change because a target blocks Chromium.

### Website content accessibility guidelines covered

By default, the Actor selects these axe-core tags:

- `wcag2a`
- `wcag2aa`
- `wcag21aa`
- `wcag22aa`

You can also select `wcag2aaa`, `wcag21a`, or `best-practice`.

Rule tags describe the automated checks to run. Automated tools cannot verify every Web Content Accessibility Guidelines requirement, user journey, assistive-technology behavior, or legal obligation.

Use `incompleteRules` as a manual-review queue rather than treating it as a pass or failure.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | required | Up to 100 public HTTP(S) webpages to render and audit. |
| `maxItems` | integer | submitted URL count | Maximum submitted pages to process, from 1 to 100. |
| `wcagTags` | string array | WCAG A/AA set | Supported axe-core WCAG and best-practice tags. |
| `includePassedRules` | boolean | `false` | Include compact detail for rules that passed. |
| `includeIncompleteRules` | boolean | `true` | Include rules and nodes that need manual review. |
| `waitUntil` | string | `domcontentloaded` | Browser readiness milestone: `domcontentloaded`, `load`, or `networkidle`. |
| `renderDelayMs` | integer | `500` | Extra post-navigation render delay, from 0 to 30,000 ms. |
| `navigationTimeoutSecs` | integer | `45` | Per-attempt navigation timeout, from 5 to 120 seconds. |

#### Small input example

```json
{
  "startUrls": [
    { "url": "https://www.python.org/" }
  ],
  "maxItems": 1,
  "wcagTags": ["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"],
  "includePassedRules": false,
  "includeIncompleteRules": true,
  "waitUntil": "domcontentloaded",
  "renderDelayMs": 500,
  "navigationTimeoutSecs": 45
}
```

### Output fields

The default dataset contains one row per requested page.

| Field | Meaning |
| --- | --- |
| `requestedUrl` | Validated submitted URL. |
| `finalUrl` | Final URL after public redirects, or null on failure. |
| `status` | `succeeded` or `failed`. |
| `statusCode` | Main-document HTTP status when available. |
| `title` | Rendered page title. |
| `wcagTags` | Rule tags used for this audit. |
| `violationCount` | Number of distinct failed rules. |
| `affectedNodeCount` | Total affected DOM nodes across failed rules. |
| `violationsByImpact` | Rule counts for minor, moderate, serious, critical, and unknown impacts. |
| `violations` | Failed rules with references and affected-node evidence. |
| `passedRuleCount` | Number of rules with passing nodes. |
| `passedRules` | Optional compact passed-rule summaries. |
| `incompleteRuleCount` | Number of rules requiring manual review. |
| `incompleteRules` | Optional manual-review rules and affected nodes. |
| `inapplicableRuleCount` | Number of selected rules not applicable to this page. |
| `testEngine` | `axe-core`. |
| `testEngineVersion` | axe-core version used by the run. |
| `runtimeMs` | Render and audit duration for the page. |
| `auditedAt` | ISO 8601 audit timestamp. |
| `error` | Bounded failure reason, or null after success. |

Fields can be null when the browser cannot obtain the corresponding value.

### Example WCAG audit result

This shortened record reflects the current output shape:

```json
{
  "requestedUrl": "https://www.python.org/",
  "finalUrl": "https://www.python.org/",
  "status": "succeeded",
  "statusCode": 200,
  "title": "Welcome to Python.org",
  "wcagTags": ["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"],
  "violationCount": 5,
  "affectedNodeCount": 103,
  "violationsByImpact": {
    "minor": 0,
    "moderate": 0,
    "serious": 3,
    "critical": 2,
    "unknown": 0
  },
  "violations": [
    {
      "id": "aria-required-children",
      "impact": "critical",
      "wcagCriteria": ["1.3.1"],
      "help": "Certain ARIA roles must contain particular children",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/aria-required-children?application=axeAPI",
      "affectedNodeCount": 4,
      "nodes": [
        {
          "selectors": [".meta-navigation > ul[role=\"tree\"]"],
          "html": "<ul class=\"menu\" role=\"tree\">",
          "failureSummary": "Fix any of the following: Element has children which are not allowed: li",
          "impact": "critical"
        }
      ]
    }
  ],
  "passedRuleCount": 22,
  "passedRules": null,
  "incompleteRuleCount": 1,
  "inapplicableRuleCount": 48,
  "testEngine": "axe-core",
  "testEngineVersion": "4.13.0",
  "error": null
}
```

Page content and accessibility findings change over time, so counts are examples rather than guarantees.

### How to run your first audit

1. Open the Actor in Apify Console.
2. Add one or more public webpage URLs under **Public webpage URLs**.
3. Keep the default WCAG tags for a standard A/AA check.
4. Enable **Include passed-rule details** only when you need full pass metadata.
5. Click **Start**.
6. Open the **Dataset** tab.
7. Review impact counts first, then expand `violations` and `incompleteRules`.
8. Export JSON, CSV, Excel, XML, or connect the dataset to another system.

Start with one representative page before increasing a batch.

### How much does it cost to audit a webpage for WCAG issues?

Pay-per-event pricing has two events:

- **Accessibility audit started:** $0.005 once per run.
- **Page audited:** charged only for each page successfully rendered and audited.

Current page-audit prices are:

| Apify tier | Price per audited page |
| --- | ---: |
| FREE | $0.0391 |
| BRONZE | $0.0340 |
| SILVER | $0.02652 |
| GOLD | $0.0204 |
| PLATINUM | $0.0204 |
| DIAMOND | $0.0204 |

At BRONZE, approximate totals are:

- 1 successful page: **$0.039** including the start event.
- 10 successful pages: **$0.345** including the start event.
- 100 successful pages: **$3.405** including the start event.

A failed page produces a diagnostic dataset row but no `page-audit` event. Passed rules, incomplete rules, selectors, and evidence are included in the page event and have no separate charge.

### Recurring accessibility regression checks

Apify schedules can run the same input daily, weekly, or before a release.

A practical workflow is:

1. keep the URL list and WCAG tags stable;
2. schedule the Actor;
3. store each dataset ID and run timestamp;
4. compare `violations[].id`, `affectedNodeCount`, and `violationsByImpact`;
5. notify the owning team when new serious or critical findings appear;
6. preserve incomplete checks for human review.

This Actor reports the current page. It does not maintain cross-run history or send alerts by itself.

### CI and release-gate pattern

Call the Actor from CI with release-candidate URLs.

After completion, fetch dataset items and apply your own policy, for example:

- fail when `status` is `failed`;
- fail when critical violation count increases;
- warn on new serious rules;
- create tickets from affected selectors;
- require review of `incompleteRules`.

Avoid treating `violationCount === 0` as legal certification.

### cURL API example

Replace `YOUR_APIFY_TOKEN` with an Apify token stored in your secret manager.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~website-accessibility-wcag-audit/runs?token=YOUR_APIFY_TOKEN&waitForFinish=120" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.python.org/"}],
    "maxItems": 1,
    "wcagTags": ["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"]
  }'
```

Fetch the resulting dataset with the `defaultDatasetId` returned by the run.

### JavaScript API example

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('automation-lab/website-accessibility-wcag-audit').call({
  startUrls: [{ url: 'https://www.python.org/' }],
  maxItems: 1,
  includeIncompleteRules: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].violationsByImpact);
```

### Python API example

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])

run = client.actor('automation-lab/website-accessibility-wcag-audit').call(run_input={
    'startUrls': [{'url': 'https://www.python.org/'}],
    'maxItems': 1,
    'includeIncompleteRules': True,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items[0]['violationsByImpact'])
```

### Use with Apify MCP

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/website-accessibility-wcag-audit"
```

#### Claude Desktop setup

Add the following remote MCP server configuration in Claude Desktop.

#### Cursor setup

Use the same remote MCP server JSON in Cursor's MCP settings.

#### VS Code setup

Add the same server URL through your VS Code MCP extension or workspace MCP configuration.

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/website-accessibility-wcag-audit"
    }
  }
}
```

Example prompts:

- "Audit Python.org against WCAG A and AA and summarize critical selectors."
- "Check these three staging pages and return rule IDs that fail on more than one page."
- "Run an accessibility regression audit and format serious findings for our issue tracker."

### Limits and reliability

- A run accepts at most 100 submitted URLs.
- Pages are processed sequentially to keep browser memory predictable.
- Only anonymous public HTTP(S) pages are supported.
- URLs with credentials, non-web protocols, private addresses, or reserved addresses are rejected.
- Redirect and subresource requests are checked against the same public-network policy.
- Login walls, CAPTCHA pages, and anti-bot interstitials are not bypassed.
- A transient timeout, network error, 429, or 5xx receives one retry with a fresh context.
- Stable 4xx responses and detected challenges are not blindly retried.
- The Actor does not automatically enable residential proxies.
- Dynamically changing pages can produce different findings between runs.
- axe-core covers automatable rules; manual evaluation remains necessary.

If every page fails, the Actor run fails after storing diagnostic rows.

### Tips for useful results

- Audit the same URL, viewport assumptions, tags, and render delay when comparing runs.
- Use `load` if the DOM-ready state is too early for a page.
- Use `networkidle` cautiously; analytics and live connections can prevent it from settling.
- Increase `renderDelayMs` for late client rendering, not as a substitute for a correct readiness milestone.
- Keep `includePassedRules` off for compact regression datasets.
- Keep `includeIncompleteRules` on when a human reviewer will triage uncertain checks.
- Group findings by `violations[].id` before opening one ticket per affected selector.
- Follow each `helpUrl` for rule context and remediation guidance.

### Troubleshooting

#### Why did the page fail with a private or reserved address error?

The submitted hostname, redirect, or subresource resolved to a non-public network address. The Actor rejects it to prevent server-side request forgery. Use an anonymously reachable public URL.

#### Why did the Actor report a challenge instead of violations?

The target returned an anti-bot or verification page. A challenge is not the page you intended to audit, so the Actor records a failure rather than a misleading clean result.

#### Why are some rules incomplete?

Some checks require visual or contextual judgment that axe-core cannot determine automatically. Review `incompleteRules[].nodes`, the selectors, and the linked rule reference.

#### Why do violation counts differ from another tool?

Tools can use different engine versions, rule tags, render timing, browser state, viewport assumptions, and custom rules. Compare like-for-like settings and inspect stable rule IDs rather than only a total score.

#### Does a zero-violation result prove WCAG compliance?

No. It means no selected automated axe-core rule failed on the rendered page at that moment. Manual testing, keyboard navigation, assistive technology, content review, and applicable legal analysis may still be required.

### Legality and responsible use

Audit only pages you are authorized to test.

Respect website terms, rate limits, copyright, privacy obligations, and organizational policies. Do not submit private intranet URLs, authenticated pages, personal data, or secrets.

The output is technical evidence for review. It is not a guarantee of conformance with WCAG, ADA, EAA, Section 508, or any other legal standard.

### Related Automation Lab Actors

- [Lighthouse Website Audit](https://apify.com/automation-lab/website-lighthouse-seo-audit) — use when you also need performance, Core Web Vitals, best-practice, and SEO scores.
- [Sitewide Broken Link Checker](https://apify.com/automation-lab/sitewide-broken-link-checker) — use for bounded link discovery and broken-link status checks.
- [Website HTML & Text Change Monitor](https://apify.com/automation-lab/website-html-text-change-monitor) — use when the buyer job is content-change detection rather than accessibility testing.

Choose this Actor when detailed axe-core WCAG rules and affected DOM evidence are the primary output.

### FAQ

#### Can I audit multiple pages?

Yes. Add up to 100 public URLs and set `maxItems` to the desired processed count.

#### Can I crawl an entire site automatically?

No. This version audits supplied page URLs. Provide a bounded list from your own sitemap, crawler, or release manifest.

#### Are passed rules available?

Yes. `passedRuleCount` is always returned. Set `includePassedRules` to `true` for compact metadata about each passing rule.

#### Are incomplete checks charged separately?

No. Violations, pass summaries, and incomplete checks are included in the successful `page-audit` event.

#### Can it audit authenticated applications?

No. The Actor supports anonymously reachable public pages and does not accept cookies, passwords, or account sessions.

#### Which browser does it use?

It uses the maintained Playwright Chromium runtime in the Actor container.

#### Does it fix accessibility problems?

No. It exports evidence and remediation references. Your development or content team applies and validates fixes.

#### Can I export the data?

Yes. Apify datasets support JSON, JSONL, CSV, Excel, XML, RSS, and API access. Nested violation details are richest in JSON or JSONL.

# Actor input Schema

## `startUrls` (type: `array`):

HTTP(S) pages to render and audit. Private, local, credential-bearing, and reserved-network URLs are rejected.

## `maxItems` (type: `integer`):

Maximum submitted pages to audit in this run. Pages are processed in input order.

## `wcagTags` (type: `array`):

axe-core rule tags to run. Defaults cover WCAG 2.0 A/AA, WCAG 2.1 AA, and WCAG 2.2 AA.

## `includePassedRules` (type: `boolean`):

Include a compact record for every rule that passed. The passedRuleCount is always returned.

## `includeIncompleteRules` (type: `boolean`):

Include axe-core incomplete checks and their affected selectors for manual review.

## `waitUntil` (type: `string`):

Browser navigation milestone before the optional render delay and accessibility scan.

## `renderDelayMs` (type: `integer`):

Bounded delay after navigation for client-rendered content. Increase only when a page renders late.

## `navigationTimeoutSecs` (type: `integer`):

Maximum time for each navigation attempt. A transient failure is retried once in a fresh context.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.python.org/"
    }
  ],
  "maxItems": 10,
  "wcagTags": [
    "wcag2a",
    "wcag2aa",
    "wcag21aa",
    "wcag22aa"
  ],
  "includePassedRules": false,
  "includeIncompleteRules": true,
  "waitUntil": "domcontentloaded",
  "renderDelayMs": 500,
  "navigationTimeoutSecs": 45
}
```

# Actor output Schema

## `dataset` (type: `string`):

Typed page summaries, structured violations, affected selectors, references, evidence, and pass counts.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://www.python.org/"
        }
    ],
    "maxItems": 10,
    "wcagTags": [
        "wcag2a",
        "wcag2aa",
        "wcag21aa",
        "wcag22aa"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/website-accessibility-wcag-audit").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://www.python.org/" }],
    "maxItems": 10,
    "wcagTags": [
        "wcag2a",
        "wcag2aa",
        "wcag21aa",
        "wcag22aa",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/website-accessibility-wcag-audit").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.python.org/"
    }
  ],
  "maxItems": 10,
  "wcagTags": [
    "wcag2a",
    "wcag2aa",
    "wcag21aa",
    "wcag22aa"
  ]
}' |
apify call automation-lab/website-accessibility-wcag-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/website-accessibility-wcag-audit"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/S027k6mKOcPq3v9FY/builds/ugVB0wcsPqQzQOdsV/openapi.json
