# Website Accessibility Checker: WCAG 2.2 & EAA Audit (axe-core) (`latamdatatools/accessibility-audit`) Actor

Audit web pages or whole sites for WCAG 2.0, 2.1 and 2.2 accessibility issues with axe-core in a real browser: each violation with severity, WCAG criterion, offending element and how to fix it, plus a score and site summary. Useful for the European Accessibility Act.

- **URL**: https://apify.com/latamdatatools/accessibility-audit.md
- **Developed by:** [Julian Genuario](https://apify.com/latamdatatools) (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

from $5.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

## Website Accessibility Checker: WCAG 2.2 & EAA Audit (axe-core)

Check web pages, or whole websites, for **WCAG accessibility problems** with **axe-core**, the open-source engine used by most accessibility tools, running in a real headless Chrome browser.

For every page you get:

- an **accessibility score** (0-100) and the number of failed rules and failing elements
- issues by **severity**: critical, serious, moderate, minor
- the **WCAG success criteria** that fail (e.g. `1.1.1`, `1.4.3`, `2.4.4`) and their level (A / AA / AAA)
- each **violation** with a plain explanation, a link to the fix guide, and the **offending elements** (CSS selector, HTML snippet and what to fix)
- "**needs review**" items that a human should check (e.g. text over images)
- a **site summary** (average score, worst issues across pages) when you audit several pages of the same site

Pick **WCAG 2.0, 2.1 or 2.2**, level **A, AA or AAA**, desktop or mobile viewport, and optionally axe-core best practices.

### What does Website Accessibility Checker do?

Website Accessibility Checker audits web pages or whole sites for WCAG 2.0, 2.1 and 2.2 accessibility issues with axe-core in a real browser. Each violation comes with severity, WCAG success criterion, the offending element and how to fix it, plus a score and site summary, which helps with European Accessibility Act (EAA) compliance work. Automated checks find a part of WCAG issues, not all of them.

### How to use Website Accessibility Checker

1. Click **Try for free** on this page (a free Apify account is enough to start).
2. Fill in the input (see the examples below) or keep the prefilled example.
3. Click **Start** and wait for the run to finish.
4. Download the results from the **Output** tab as JSON, CSV, Excel or HTML, or read them with the Apify API.
5. Optional: create a **Schedule** to run it daily or weekly, and connect a webhook or an integration (Make, Zapier, n8n, Slack).

### Why now: the European Accessibility Act

Since **28 June 2025** the European Accessibility Act (EAA) requires many websites and online shops selling in the EU to be accessible, using **EN 301 549**, which points to **WCAG 2.1 AA**. This Actor lets agencies, developers and e-commerce teams find the issues that automated testing can detect, across many pages, in minutes.

### Use cases

- **Agencies**: audit a prospect's or client's website and show concrete, prioritised issues
- **E-commerce and SaaS**: check key templates (home, category, product, checkout entry, signup) before and after releases
- **Monitoring**: schedule weekly runs and compare scores over time
- **Lead generation for accessibility services**: score a list of company websites

### Input

```json
{
  "urls": ["https://www.example.com/", "https://www.example.com/products/"],
  "wcagLevel": "wcag21aa",
  "crawlSameSite": true,
  "maxPagesPerSite": 10,
  "viewport": "desktop"
}
```

URLs can also come from an **Apify dataset** or a **CSV / Google Sheet** by URL (**URL field** = the column with the URL).

### Output (one row per page, shortened)

```json
{
  "url": "https://www.w3.org/WAI/demos/bad/before/home.html",
  "status": "ok",
  "title": "Welcome to CityLights! [Inaccessible Home Page]",
  "score": 27,
  "violationRules": 5,
  "violationElements": 44,
  "critical": 34,
  "serious": 10,
  "moderate": 0,
  "minor": 0,
  "failedWcagCriteria": ["1.1.1", "1.4.3", "2.4.4", "3.1.1", "4.1.2"],
  "violations": [
    {
      "id": "image-alt",
      "impact": "critical",
      "help": "Images must have alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.14/image-alt",
      "wcagCriteria": ["1.1.1"],
      "wcagLevel": "A",
      "nodesCount": 33,
      "nodes": [
        { "target": "img[src$=\"border_left_top.gif\"]", "html": "<img src=\"./img/border_left_top.gif\">", "failureSummary": "Fix any of the following: Element does not have an alt attribute ..." }
      ]
    }
  ],
  "needsReview": [],
  "passedRules": 18,
  "axeVersion": "4.14.0"
}
```

Every row has the same keys. Pages that cannot be audited have `status: "failed"` or `"blocked_by_robots"` and an `error`, and are not charged. The **SITE_SUMMARY** record in the key-value store has one summary per site (pages audited, average score, totals by severity, top 15 violations with how many pages they affect); **RUN_SUMMARY** has the run totals.

### Pricing

Pay per event: **USD 0.005 per page audited** (USD 5 per 1,000 pages) plus **USD 0.001 per run start** (per GB of memory; it covers launching the browser). Failed pages and pages blocked by robots.txt are free. Your "max charge per run" is respected: the Actor stops opening pages when the next one would exceed it. A real browser is used for every page, which is why this costs more than plain-HTTP tools.

### Good to know

- **Automated testing finds part of the problems, not all.** axe-core reports no false positives by design, but issues like meaningful alt text, logical reading order or keyboard traps need a human review. A score of 100 does not mean a site is fully WCAG-compliant or legally compliant.
- The browser does not download images, video and fonts (not needed by the rules, faster and lighter). Colour-contrast checks on text over images therefore go to "needs review".
- **robots.txt is respected**: it is checked for every page and every redirect before the browser opens the page, with an identifiable user agent (`AccessibilityAuditBot`). Each site gets at most one page every 1.5 seconds. Login-protected pages are not audited.
- Memory: 1 GB (the minimum: heavy news and shop pages crash a browser with less) audits 2 pages in parallel; give 2-4 GB for 3-4 pages in parallel.

### Credits and licences

Accessibility rules engine: **axe-core** by Deque Systems, Inc., used unmodified, licensed under the **Mozilla Public License 2.0** (source: https://github.com/dequelabs/axe-core). See `THIRD_PARTY_NOTICES.md` in the Actor source. This Actor is not affiliated with or endorsed by Deque Systems or the W3C.

### FAQ

**Can I call it from my own code or from an AI agent?** Yes. Start runs and fetch results with the Apify API or the JavaScript / Python clients, or use it as a tool from Claude, Cursor and other MCP clients through the Apify MCP server (`mcp.apify.com`).

**Can I run it automatically?** Yes. Create a Schedule in Apify Console (for example every morning) and add a webhook or an integration to get the results where you need them.

**Which export formats are available?** JSON, JSONL, CSV, Excel (XLSX), XML, RSS and HTML table, from the Output tab or the API.

**What does it cost?** See the Pricing section above. You only pay for the events listed there.

# Actor input Schema

## `urls` (type: `array`):

One URL (or domain = its home page) per line.

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

Which axe-core rule set to run. WCAG 2.1 AA is the level referenced by the European Accessibility Act (EN 301 549) and most laws.

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

axe-core best practices that are not WCAG requirements (landmarks, heading order, region...).

## `includeNeedsReview` (type: `boolean`):

Checks axe-core could not decide automatically (e.g. text over background images). Listed in "needsReview" for a human to check.

## `viewport` (type: `string`):

Desktop (1366 px) or mobile (390 px, touch).

## `maxElementsPerRule` (type: `integer`):

How many offending elements (selector, HTML and how to fix) to list for each failed rule. The total count is always given.

## `crawlSameSite` (type: `boolean`):

Also audit pages linked from each start URL on the same host (no login, cart or account pages), up to "Max pages per site".

## `maxPagesPerSite` (type: `integer`):

Including the start URL(s) of that site.

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

Hard cap for the run (up to 2,000). Your max charge per run is respected too.

## `datasetId` (type: `string`):

Optional: audit the URLs stored in an Apify dataset. Use "URL field" to say which field holds the URL.

## `csvUrl` (type: `string`):

Optional: a public CSV file with a header row (Google Sheets links work if shared as "Anyone with the link").

## `urlField` (type: `string`):

Field / CSV column that holds the URL, e.g. url, website.

## `keepFields` (type: `array`):

Optional: copy these fields of each dataset record / CSV row into the output (under "source").

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

Browser tabs at the same time. 2 fits in 1 GB of memory; use 3-4 with 2 GB or more.

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

If the page is still loading after this time, the audit runs on what has loaded.

## `waitAfterLoadSecs` (type: `integer`):

Extra time for JavaScript to render the page before the audit.

## Actor input object example

```json
{
  "urls": [
    "https://www.w3.org/WAI/demos/bad/before/home.html",
    "https://www.gov.uk/"
  ],
  "wcagLevel": "wcag21aa",
  "includeBestPractices": false,
  "includeNeedsReview": true,
  "viewport": "desktop",
  "maxElementsPerRule": 10,
  "crawlSameSite": false,
  "maxPagesPerSite": 10,
  "maxPages": 100,
  "urlField": "url",
  "maxConcurrency": 2,
  "pageTimeoutSecs": 45,
  "waitAfterLoadSecs": 1
}
```

# Actor output Schema

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

No description

## `runSummary` (type: `string`):

No description

## `siteSummary` (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 = {
    "urls": [
        "https://www.w3.org/WAI/demos/bad/before/home.html",
        "https://www.gov.uk/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("latamdatatools/accessibility-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 = { "urls": [
        "https://www.w3.org/WAI/demos/bad/before/home.html",
        "https://www.gov.uk/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("latamdatatools/accessibility-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 '{
  "urls": [
    "https://www.w3.org/WAI/demos/bad/before/home.html",
    "https://www.gov.uk/"
  ]
}' |
apify call latamdatatools/accessibility-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,latamdatatools/accessibility-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/znq46CqX4KJ4v57bG/builds/PcVM3wqbmGrGECiIp/openapi.json
