# WCAG Accessibility Auditor (axe-core) (`jetlaunch/wcag-accessibility-auditor`) Actor

Audit the web pages you name for WCAG 2.0, 2.1 and 2.2 accessibility violations with axe-core in a real browser. You get failing elements with selectors, HTML snippets and fix hints. Pay only for completed audits.

- **URL**: https://apify.com/jetlaunch/wcag-accessibility-auditor.md
- **Developed by:** [Chris O'Byrne](https://apify.com/jetlaunch) (community)
- **Categories:** Developer tools, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 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.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**WCAG Accessibility Auditor** opens the web pages you list in a real Chrome browser and checks them for accessibility problems with **axe-core**, the open source rules engine from Deque Systems. For every page you get a score, counts of failing, passing, "needs review" and not applicable rules, and a list of the failing elements with the CSS selector, the HTML snippet, the WCAG success criterion, a link to the rule help and a fix hint.

It audits **only the pages you name**. It does not crawl links, does not sign in and does not try to get past bot protection.

#### Who is it for

- Developers and QA teams who want an accessibility check in a scheduled run or a CI job (use the Apify API or the scheduler).
- Agencies and freelancers who audit a handful of client pages and need a clean report.
- Product and compliance owners who track WCAG 2.2 AA progress page by page.

#### How to use it

1. Paste the page URLs into **Page URLs** (one per page, http or https).
2. Pick the **WCAG level** (A, AA or AAA) and **version** (2.0, 2.1 or 2.2). The default is WCAG 2.2 level AA plus axe-core best practices.
3. Optional: set the viewport (for example 390 wide for a phone), the color scheme, or a CSS selector to wait for on single-page apps.
4. Click **Start** and open the **Audit overview** table, or download JSON, CSV, Excel or HTML from the dataset.

The prefilled input audits `https://example.com` and an intentionally inaccessible demo page from the W3C Web Accessibility Initiative ("Before and After Demonstration").

#### Input

| Field | Meaning | Default |
|---|---|---|
| Page URLs | Pages to audit. Duplicates and `#fragments` are merged. | required |
| WCAG conformance level | A, AA or AAA (cumulative) | AA |
| WCAG version | 2.0, 2.1 or 2.2 | 2.2 |
| Include best-practice rules | axe-core best practices that WCAG does not require | on |
| Advanced: explicit axe-core tags | Replaces the three settings above. Valid: wcag2a, wcag2aa, wcag2aaa, wcag21a, wcag21aa, wcag22aa, best-practice | empty |
| Viewport width and height | Browser window size in pixels | 1280 x 800 |
| Color scheme | light or dark (affects contrast results) | light |
| Wait until, wait for selector, extra wait | How long to wait before auditing | load, none, 1000 ms |
| Page timeout | Seconds to open one page (up to 2 retries) | 45 |
| Maximum pages | Cap on the list | 50 |
| Maximum failing elements per rule | Keeps results small | 25 |
| Pages in parallel | Same host is always at least 2 s apart | 2 |

#### Output

One dataset item per URL. Example (shortened):

```json
{
  "url": "https://example.com/",
  "finalUrl": "https://example.com/",
  "status": "audited",
  "httpStatus": 200,
  "pageTitle": "Example Domain",
  "score": 78.6,
  "violationRuleCount": 3,
  "violationCount": 9,
  "impactCounts": { "critical": 0, "serious": 0, "moderate": 9, "minor": 0 },
  "passesCount": 11,
  "incompleteCount": 1,
  "inapplicableCount": 76,
  "violations": [
    {
      "ruleId": "landmark-one-main",
      "impact": "moderate",
      "wcagTags": ["best-practice"],
      "wcagCriteria": [],
      "help": "Document should have one main landmark",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.14/landmark-one-main",
      "selector": "html",
      "htmlSnippet": "<html lang=\"en\">",
      "fixHint": "Fix all of the following: Document does not have a main landmark"
    }
  ],
  "auditedAt": "2026-10-21T20:43:46.567Z",
  "axeVersion": "4.14.0",
  "charged": true
}
```

- **status** is `audited` when the audit completed. Other values: `blocked`, `login_required`, `http_error`, `navigation_error`, `invalid_url`, `empty_page`, `audit_error`. These items explain what happened in `error` and are never charged.
- **violations** has one entry per failing element. HTML snippets are cut to 300 characters.
- **score** is a number from 0 to 100: every rule that applied counts once, weighted by impact (critical 10, serious 7, moderate 3, minor 1), and the score is the weighted share of rules that passed. Rules that need manual review and rules that did not apply are left out. The score is a way to compare pages and track progress. It is not a conformance claim.
- A short run summary is stored in the key-value store record `SUMMARY`.

#### Pricing

Pay per event. You pay only when an audit completed.

| Event | Price | When it is charged |
|---|---|---|
| Page audited | $0.02 | One page loaded and the axe-core audit completed |

Pages that are blocked, behind a login, return an HTTP error, fail to load or render nothing are reported but **not charged**. Set a maximum cost per run in the run options and the Actor stops when it is reached. Platform events that Apify itself defines (such as the Actor start event) are charged by the platform as shown on the Pricing tab. Auditing 50 pages costs $1.00 in page events.

#### FAQ

**Does it find every accessibility problem?** No. Automated rules find only a part of the problems that real users meet. Items under "needs review" (`incompleteRules`) need a human look, and keyboard, screen reader and content checks cannot be automated. Use the results as a baseline, not as proof of conformance.

**Can it audit pages behind a login?** No. The Actor never signs in and never bypasses logins, CAPTCHAs or bot protection. If a page redirects to a login or serves a challenge page, it is reported as `login_required` or `blocked` and not charged.

**Does it crawl my whole site?** No. It audits exactly the URLs you list. Some other Actors in the Store crawl from a start page; this one is for people who want to control which pages are checked. Build the list from your sitemap if you want broad coverage.

**How polite is it?** At most one page load per host every 2 seconds, one browser, and a User-Agent that ends with `WCAGAccessibilityAuditor/1.0 (+https://apify.com/jetlaunch/wcag-accessibility-auditor; chris@jetlaunch.net)`. Only audit sites you own or have permission to test.

**Which addresses are refused?** Local and private network addresses (localhost, 10.x, 192.168.x, 169.254.x and similar) are refused so the Actor cannot be pointed at internal networks.

**Which rules and version?** axe-core 4.14.0, listed in every result as `axeVersion`.

#### Limitations

- Single page snapshot: content that appears only after clicks, scrolling or form input is not tested.
- Very large pages are capped by "Maximum failing elements per rule" and 1000 entries per page. The counts still show the full numbers and `violationsTruncated` is set.
- Some sites serve different markup to headless browsers. Results describe what Chrome received.

#### Data source, licence and attribution

Rules and results come from [axe-core](https://github.com/dequelabs/axe-core) 4.14.0 and @axe-core/playwright 4.14.0, both licensed under the Mozilla Public License 2.0 and used without modification. Copyright Deque Systems, Inc. The licence text and notices are included in the Actor source (`THIRD_PARTY_NOTICES.md`, `licenses/`). The browser automation uses Playwright (Apache-2.0). The prefilled demo page is published by the W3C Web Accessibility Initiative.

This Actor is not affiliated with, endorsed by or sponsored by Deque Systems, the W3C or Microsoft.

#### Support

Found a false positive, a missing field or a page that should work? Open a ticket in the **Issues** tab of this Actor and include the run URL. Custom reports and integrations (Slack, Google Sheets, webhooks) can be added with the standard Apify integrations.

# Actor input Schema

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

The public pages to audit, one URL each (http or https). Only these exact pages are audited, no links are followed. Pages behind a login or a bot check are reported as such and are not charged.

## `wcagLevel` (type: `string`):

Highest level to test. Levels are cumulative: AA includes A, AAA includes AA. Most laws and procurement rules refer to AA.

## `wcagVersion` (type: `string`):

Which version of the guidelines to test against. A newer version includes the rules of the older ones.

## `includeBestPractices` (type: `boolean`):

Also run axe-core best-practice rules (for example landmarks and heading order). These are good advice but are not required by WCAG.

## `axeTags` (type: `array`):

Optional. If you list any tags here, they replace the level, version and best-practice settings above. Valid tags: wcag2a, wcag2aa, wcag2aaa, wcag21a, wcag21aa, wcag22aa, best-practice.

## `viewportWidth` (type: `integer`):

Browser window width. Use 390 to test a phone layout.

## `viewportHeight` (type: `integer`):

Browser window height.

## `colorScheme` (type: `string`):

Value of the prefers-color-scheme setting. Color contrast results can differ between light and dark.

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

When the page counts as loaded. 'networkidle' is slower but suits pages that keep loading content after the load event.

## `waitForSelector` (type: `string`):

Optional. Wait up to 20 seconds for this element to appear before auditing, for example '#app main'. Useful for single-page apps.

## `waitAfterLoadMs` (type: `integer`):

Pause after the page has loaded and before the audit, so late scripts can finish.

## `pageTimeoutSecs` (type: `integer`):

Maximum time to open one page. Failed loads are retried up to two more times.

## `maxPages` (type: `integer`):

Audit at most this many of the listed URLs (the first ones in the list). Protects you from a very large accidental list.

## `maxNodesPerRule` (type: `integer`):

Per page and per rule, report at most this many failing elements. The full count is still shown in the violation counts. Keeps results small on very large pages.

## `maxConcurrency` (type: `integer`):

How many pages are audited at the same time. Requests to the same host are always at least 2 seconds apart, whatever you set here.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com"
    },
    {
      "url": "https://www.w3.org/WAI/demos/bad/before/home.html"
    }
  ],
  "wcagLevel": "AA",
  "wcagVersion": "2.2",
  "includeBestPractices": true,
  "axeTags": [],
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "colorScheme": "light",
  "waitUntil": "load",
  "waitAfterLoadMs": 1000,
  "pageTimeoutSecs": 45,
  "maxPages": 50,
  "maxNodesPerRule": 25,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `overview` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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://example.com"
        },
        {
            "url": "https://www.w3.org/WAI/demos/bad/before/home.html"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jetlaunch/wcag-accessibility-auditor").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://example.com" },
        { "url": "https://www.w3.org/WAI/demos/bad/before/home.html" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("jetlaunch/wcag-accessibility-auditor").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://example.com"
    },
    {
      "url": "https://www.w3.org/WAI/demos/bad/before/home.html"
    }
  ]
}' |
apify call jetlaunch/wcag-accessibility-auditor --silent --output-dataset

```

## MCP server setup

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

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/3kNgw37pEWb43KX6n/builds/bh6msahfnYulacYHw/openapi.json
