# WCAG 2.0 Evidence Audit (axe-core, report + screenshots) (`finespun_acorn/wcag-evidence-audit`) Actor

Runs axe-core against your pages, maps results to all 38 WCAG 2.0 A/AA success criteria, and produces a downloadable HTML/PDF evidence report with screenshots and CSS selectors.

- **URL**: https://apify.com/finespun\_acorn/wcag-evidence-audit.md
- **Developed by:** [Finespun Acorn](https://apify.com/finespun_acorn) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$60.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?

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

## WCAG 2.0 Evidence Audit

Runs [axe-core](https://github.com/dequelabs/axe-core) against the pages you give it, maps every finding onto the
**38 WCAG 2.0 Level A/AA success criteria**, and produces a client-ready evidence report (HTML + PDF + JSON) with
screenshots and the exact CSS selector of every failing element — not just a raw rule dump.

### What it does

1. For each start URL: validates it isn't a private/loopback address (SSRF guard), loads the page, and checks for
   bot-challenge / interstitial pages (Cloudflare, CAPTCHA, etc.) so you never get a false "pass" from a page that
   never actually loaded.
2. Runs axe-core (`wcag2a`, `wcag2aa`, `wcag2a-obsolete` rule tags) and aggregates the results per WCAG 2.0 success
   criterion into one of three statuses: **不適合 / non-compliant**, **要手動確認 / needs manual review**, or
   **適合 / compliant (automated)**.
3. Optionally captures a full-page mobile-width screenshot per page.
4. Writes one row per page to the **Dataset**, and a combined **report.json / report.html / report.pdf** to the
   **Key-Value Store** (linked from `OUTPUT`).

### Why this instead of a generic axe-core Actor

Most accessibility-testing Actors on the Store dump raw axe-core rule violations as dataset rows. This Actor is
built for **handing evidence to a client or auditor**, not just triaging rules yourself:

- **WCAG 2.0 success-criterion mapping** (all 38 A/AA criteria, not just the axe rule IDs) — the format auditors and
  clients actually expect (JIS X 8341-3:2016 / WCAG 2.0 style reporting).
- **Evidence report** (HTML + PDF) with the disclaimer, environment/version block (Node/Playwright/axe-core
  versions + a `report_json_sha256` for reproducibility), and per-violation CSS selectors/help text/help URL — ready
  to attach to an email or deliverable, not just a JSON blob.
- **Interstitial/bot-challenge detection**: if the page you asked for came back as a Cloudflare challenge or similar,
  that page is reported as a failure with `interstitial_detected` rather than silently "passing" an empty shell page.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `startUrls` | array of `{ "url": "..." }` | — (required) | Pages to audit |
| `maxPages` | integer | 10 | Hard cap 50; extra URLs are skipped (reported in `OUTPUT.pages_skipped_by_max_pages`) |
| `includeScreenshots` | boolean | true | Full-page mobile-width (390px) screenshot per audited page, uploaded to the key-value store |
| `outputPdf` | boolean | true | Also render `report.pdf` (one extra headless render at the end of the run) |
| `reportTitle` | string | "WCAG 2.0 Evidence Audit Report" | Title shown on the HTML/PDF report |
| `locale` | `en` | `ja` | `en` | Controls axe-core's own rule/help text language. The report's structural labels (headers, disclaimer) are Japanese in both modes — see Limitations |

### Output

**Dataset** — one row per requested URL:

```json
{
  "url": "https://example.com/",
  "final_url": "https://example.com/",
  "status": "不適合",
  "criteria_summary": { "不適合": 3, "要手動確認": 12, "適合": 23 },
  "violations": [{ "rule_id": "image-alt", "help": "...", "selectors": ["img.logo"], "help_url": "..." }],
  "incomplete_nodes": 4,
  "screenshot_url": "https://api.apify.com/v2/key-value-stores/.../records/screenshot-0"
}
```

Rejected/failed URLs get `{ "url": ..., "status": "error", "error": "..." }` instead, and are **not charged**.

**Key-Value Store** (linked from the default `OUTPUT` record):

- `report.json` — full machine-readable report (all 38 criteria × all pages)
- `report.html` — client-ready HTML report
- `report.pdf` — same report as PDF (if `outputPdf` is true)
- `screenshot-{i}` — per-page PNG screenshots (if `includeScreenshots` is true)

### Pricing (pay-per-event)

This Actor uses **pay-per-event** pricing with a single event, `page-audited`, charged once per successfully audited
page (navigation + axe-core run completed). URLs rejected by the SSRF guard, that fail to load, or that are
detected as bot-challenge/interstitial pages are **not charged**.

### Limitations

- **Automated checks only.** This is not a legal conformance statement or a substitute for a manual WCAG audit —
  many success criteria (keyboard operability, meaningful reading order, correct use of ARIA semantics, etc.)
  require human review and are reported as "要手動確認 / needs manual review" rather than a pass.
- **Report chrome is Japanese-labeled** (table headers, disclaimer text) regardless of the `locale` input; only
  axe-core's own rule/help text follows `locale`. Full bilingual templating is a possible future improvement.
- Pages that require login, JavaScript-gated content beyond initial page load, or that block headless browsers
  (some bot-detection products) will show up as `error` / `interstitial_detected` rather than a real result.

# Actor input Schema

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

Pages to audit. Each item is an object with a `url` field (Apify's standard request-list format).

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

Upper bound on number of URLs to audit in a single run. Extra URLs beyond this are skipped.

## `includeScreenshots` (type: `boolean`):

Capture a full-page mobile-width screenshot per audited page and store it in the key-value store.

## `outputPdf` (type: `boolean`):

Also render the evidence report as a PDF (in addition to HTML/JSON). Adds one extra headless page render at the end of the run.

## `reportTitle` (type: `string`):

Title shown at the top of the HTML/PDF report.

## `locale` (type: `string`):

Language for axe-core rule text and report labels.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://dequeuniversity.com/demo/mars/"
    }
  ],
  "maxPages": 10,
  "includeScreenshots": true,
  "outputPdf": true,
  "reportTitle": "WCAG 2.0 Evidence Audit Report",
  "locale": "en"
}
```

# Actor output Schema

## `pages` (type: `string`):

One item per audited URL: status, counts of violations / needs-review / passes, and the criteria breakdown.

## `reportJson` (type: `string`):

No description

## `reportHtml` (type: `string`):

No description

## `reportPdf` (type: `string`):

Only present when the outputPdf input is true.

## `screenshots` (type: `string`):

Keys screenshot-0, screenshot-1, ... Only present when includeScreenshots is true.

# 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://dequeuniversity.com/demo/mars/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("finespun_acorn/wcag-evidence-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://dequeuniversity.com/demo/mars/" }] }

# Run the Actor and wait for it to finish
run = client.actor("finespun_acorn/wcag-evidence-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://dequeuniversity.com/demo/mars/"
    }
  ]
}' |
apify call finespun_acorn/wcag-evidence-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,finespun_acorn/wcag-evidence-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/tPIfdM423nQEzxLeN/builds/sNaNR3pd5CkHKrMup/openapi.json
