# NF Accessibility Scanner — All-in-One WCAG Audit (`nativefoundation-inc/accessibility-scan-actor`) Actor

All-in-one website accessibility scanner. Multi-engine WCAG 2.x testing in one run, no setup. JSON/SARIF report with WCAG criteria, severities, priority grades. Checks WCAG rules, render score, keyboard nav, alt text, labels, headings, captions, viewport zoom. Supports auth scanning, CI gates.

- **URL**: https://apify.com/nativefoundation-inc/accessibility-scan-actor.md
- **Developed by:** [NativeFoundation, inc.](https://apify.com/nativefoundation-inc) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$200.00 / 1,000 scan completeds

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/platform/actors/running/actors-in-store#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

## NF Accessibility Scanner — All-in-One WCAG Audit

**A comprehensive all-in-one website accessibility scanner on Apify.** Run a multi-engine WCAG 2.x audit against any URL in a single run — fully self-contained, no API keys, no setup, no external service required.

> 🧠 **Built by [NativeFoundation](https://nativefoundation.ai) — an expert AI consultant studio.** Production-grade accessibility automation, designed and maintained by specialists.

**Keywords:** accessibility scanner, WCAG compliance testing, WCAG 2.1 audit, ADA compliance scan, a11y testing, automated accessibility testing, keyboard navigation testing, screen reader compatibility, CI/CD accessibility gating.

### Trigger phrases — use this actor when you see

- "Check this page for WCAG compliance"
- "Run an accessibility audit on \[URL]"
- "Is this site keyboard-navigable?"
- "ADA compliance check before launch"
- "Gate our CI/CD pipeline on accessibility regressions"
- "Does this page have proper alt text and labels?"

### When to use it / when not to

**✅ Use it when you want to:**

- Run a **single-URL WCAG / a11y audit** and get one normalized JSON (or SARIF) report — no local tooling to install.
- **Gate CI/CD** on accessibility: `failOnGrade` / `failOnSeverity` make the run exit non-zero when a page crosses your threshold.
- Give an **agent or MCP tool** a one-shot, structured accessibility check it can call and parse.
- Cover more ground in one pass than any single engine: DOM rules, a rendered-page score, keyboard-nav, and native HTML/media/viewport checks are **merged into one report**.

**❌ Don't use it for:**

- **Full-site crawling.** It scans the **single URL you give it** — it does not spider links, sitemaps, or paginate. Point it at each page (or drive it from your own crawler / a scheduled run per URL) if you need whole-site coverage.
- **A substitute for a manual expert audit.** Automated tooling catches a large, well-defined subset of WCAG failures, but many success criteria (meaningful alt text, logical reading order, cognitive load) still require human review. Treat a clean grade as a floor, not a certification.

### What it does

**All six engines run by default** — deselect any you don't want in the `engines` input. Their results are merged into a single, normalized report.

| Engine | What it does | Typical findings |
|--------|--------------|------------------|
| **WCAG audit** | Full axe-core ruleset — DOM-based WCAG 2.x violation detection | 5–30 findings |
| **Render audit** | Rendered-page accessibility score via Lighthouse's accessibility category — a different rule engine, catches some issues axe doesn't | 0–15 findings |
| **Keyboard nav** | Simulates Tab-key navigation: focus indicators, unreachable elements, focus traps | 0–5 findings |
| **HTML structure** | Alt text, form labels, heading hierarchy, document title, duplicate ids, unlabeled links/buttons | 0–10 findings |
| **Media captions** | Missing captions/transcripts on `<video>`/`<audio>`, missing titles on embedded video iframes | 0–5 findings |
| **Viewport a11y** | Viewport meta configuration that disables pinch-to-zoom | 0–1 findings |

### Input

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `url` | string | Yes | — | Target URL to scan |
| `engines` | string\[] | No | all six | Which engines to run — remove any you don't want |
| `requestHeaders` | object | No | — | Extra HTTP headers (e.g. `{"Authorization": "Bearer …"}`) for **authenticated scanning**. Sent only to the target's origin, never to third-party hosts. Carried by `wcag-audit`, `keyboard-nav`, and the native engines — `render-audit` (Lighthouse) has no per-request origin scoping and remains unauthenticated |
| `cookies` | string | No | — | A `Cookie` header value (e.g. `session=…`) for authenticated scanning |
| `outputFormat` | string | No | `"json"` | `json`, `sarif` (also writes an `OUTPUT.sarif` SARIF 2.1.0 record for code scanning), or `both` |
| `failOnGrade` | string | No | — | **CI gate:** exit non-zero if the grade is this letter or worse (`B`/`C`/`D`/`F`). Report is still written and charged |
| `failOnSeverity` | string | No | — | **CI gate:** exit non-zero if any finding is at this severity or higher (`minor`/`moderate`/`serious`/`critical`) |

> **Scope:** each run scans one URL (see [When to use it / when not to](#when-to-use-it--when-not-to) above — it does not crawl), so the grade reflects the page actually reached. A full six-engine run typically takes 1–2 minutes.

> **Proxy:** the browser-based engines always route through Apify's **Residential** proxy — not configurable via input. Datacenter IPs get throttled or served a degraded page variant by many bot-defended sites (ecommerce, social), which skews the audit toward a page real users never see. If Residential access is unavailable on the account running this Actor, the scan falls back to a direct connection automatically and `report.proxy.note` records why. `html-structure`, `media-captions`, and `viewport-a11y` always connect directly regardless.

### Output

A single **unified, deduplicated report**, written both to the default key-value store under the record `OUTPUT` and as one item in the default **dataset**. When `outputFormat` is `sarif`/`both`, a SARIF 2.1.0 rendering is also written to `OUTPUT.sarif`.

```jsonc
{
  "target": "https://example.com",
  "engines": ["wcag-audit", "html-structure"],
  "status": { "wcag-audit": "completed", "html-structure": "completed" },
  "meta": {
    "reportVersion": "1.0.0",
    "startedAt": "2026-07-02T13:38:49.128Z",
    "finishedAt": "2026-07-02T13:39:41.902Z",
    "durationMs": 52774,
    "enginesRequested": 2,
    "enginesCompleted": 2,
    "enginesErrored": 0,
    "enginesTimedOut": 0
  },
  "summary": {
    "totalFindings": 4,
    "score": 82,
    "grade": "B",
    "duplicatesMerged": 1,
    "bySeverity": { "serious": 2, "moderate": 2 },
    "byPriority": { "p1": 2, "p2": 2 },
    "byEngine": { "wcag-audit": 3, "html-structure": 1 }
  },
  "findings": [
    {
      "id": "NF-A11Y-0001",
      "engines": ["wcag-audit"],
      "severity": "serious",
      "priority": "p1",
      "title": "Images must have alternate text",
      "description": "...",
      "location": "img.hero",
      "occurrences": 1,
      "wcagCriterion": "1.1.1",
      "wcagLevel": "A",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/image-alt"
    }
  ],
  "engineOutput": {
    "wcag-audit": { "status": "completed" },
    "html-structure": { "status": "completed" }
  }
}
```

#### Score & grade

`summary.score` is a single **0–100** headline number (higher = more accessible, matching the Lighthouse/axe convention), weighted by severity. It maps to a letter **`grade`** (`A` best → `F` worst): `A` ≥ 90, `B` ≥ 75, `C` ≥ 50, `D` ≥ 25, `F` < 25.

#### Deduplication

When more than one engine reports the same issue at the same location, the findings are **merged into a single entry** rather than duplicated — non-destructively, keeping every engine that reported it (`engines`), the highest severity, the most detailed description, and the number of raw matches (`occurrences`).

#### CI/CD gating

Set `outputFormat: "sarif"` (or `"both"`) to emit a SARIF 2.1.0 record you can upload to GitHub code scanning or GitLab SAST. Set `failOnGrade` and/or `failOnSeverity` to make the run **exit non-zero** when the scan crosses your threshold.

### Compared to alternatives

Most accessibility tools wrap **one** engine and run locally (a browser extension, a CLI you install, or a paid SaaS dashboard). This Actor's differentiator: it merges **axe-core + a Lighthouse accessibility pass + a headless-Chromium keyboard-navigation walk + native HTML / media-caption / viewport checks** into **one hosted run**, then emits a single **de-branded, normalized report** (plus SARIF 2.1.0) with **CI gating** (`failOnGrade` / `failOnSeverity`) — nothing to install, callable as an Apify Actor or MCP tool.

| Tool | Engine coverage | Runs as | Multi-engine merge | SARIF output | CI gate built in |
|------|-----------------|---------|--------------------|--------------|------------------|
| **This Actor** | axe-core + Lighthouse a11y + keyboard-nav + native HTML/media/viewport | Hosted Apify Actor / MCP tool — no install | ✅ one normalized report | ✅ 2.1.0 | ✅ `failOnGrade` / `failOnSeverity` |
| **axe DevTools** (Deque) | axe-core | Browser extension / paid SaaS | ✗ axe only | ✗ | ✗ (manual/in-app) |
| **Deque axe-core CLI** | axe-core | Local CLI you install | ✗ axe only | ✗ | Via exit code, self-scripted |
| **WAVE** (WebAIM) | WAVE engine | Browser extension / web UI / paid API | ✗ WAVE only | ✗ | ✗ |
| **Pa11y / pa11y-ci** | axe-core **or** HTML\_CodeSniffer (pick one) | Local CLI/Node you install | ✗ one runner per pass | ✗ | ✅ threshold, self-hosted |
| **Lighthouse CI** | Lighthouse accessibility category | Local CLI / your CI runner | ✗ Lighthouse only | ✗ | ✅ assertions, self-hosted |
| **Siteimprove** | Proprietary crawler-based suite | Paid enterprise SaaS | n/a (single vendor suite) | ✗ | Dashboard/policy, not a per-run exit code |

Notes: the comparison reflects each tool's core, out-of-the-box behavior. Several competitors are excellent at what they do — **Siteimprove** adds whole-site crawling and governance this Actor deliberately doesn't (it scans a single URL); **Lighthouse CI** and **pa11y-ci** gate CI well but each on a **single** engine you host yourself. This Actor's niche is a **zero-install, multi-engine, agent-callable single-URL audit with a normalized report and SARIF/CI gating** in one run.

### FAQ

**Why use this instead of just running axe-core myself?**
axe-core alone catches a good DOM-rule subset, but misses issues a different engine catches — keyboard-nav focus traps, Lighthouse's render-based accessibility score, missing captions, zoom-disabling viewports. This Actor merges six engines into one normalized report so you get that coverage without wiring up and maintaining six separate tools yourself.

**Why not just use a browser extension like WAVE or axe DevTools?**
Those are manual, one-page-at-a-time, human-in-the-loop tools. This Actor is built to be called programmatically — from a CI pipeline, a script, or an AI agent/MCP tool — and returns structured JSON (or SARIF) instead of a UI overlay you have to read yourself.

**Can this replace a manual accessibility audit?**
No, and it doesn't claim to. Automated tooling reliably catches a large, well-defined subset of WCAG failures (missing alt text, label associations, focus traps, contrast, etc.), but things like meaningful alt-text quality, logical reading order, and cognitive load still need human review. Treat a clean grade as a floor, not a certification.

**Why run this in CI instead of just checking manually before each release?**
`failOnGrade` / `failOnSeverity` let you fail a build automatically the moment a regression crosses your threshold, catching accessibility regressions the same way a test suite catches functional ones — before they ship, not after a manual pass someone forgot to run.

**Is this useful for AI agents, not just CI pipelines?**
Yes — it's designed to be one-shot and agent-callable: give it a URL, get back a single structured report an agent or MCP tool can parse directly, no scraping a UI or interpreting a DOM overlay.

**Which WCAG version and level does this test — 2.0, 2.1, 2.2, A/AA/AAA?**
The `wcag-audit` engine runs axe-core's full ruleset, which covers WCAG 2.0, 2.1, and 2.2 success criteria at levels A and AA (axe-core doesn't test AAA, since most AAA criteria require subjective, human judgment rather than automated rules). `render-audit` (Lighthouse) and the native engines add checks that overlap several of the same criteria from a different angle, rather than adding AAA coverage.

***

#### Licenses & attribution

This Actor packages third-party open-source accessibility tooling (axe-core, Lighthouse, Puppeteer, chrome-launcher). Full license texts and source references are included in the [`NOTICE`](../NOTICE) file distributed with the image. All components are redistributed in accordance with their respective licenses (MPL-2.0, Apache-2.0). `html-structure`, `media-captions`, and `viewport-a11y` are native engines written in-house with no bundled third-party scanner.

# Actor input Schema

## `url` (type: `string`):

The website URL to scan (e.g. https://example.com). Must be publicly accessible.

## `engines` (type: `array`):

Which accessibility engines to run. Defaults to all six: wcag-audit (full WCAG 2.x ruleset violations), render-audit (rendered-page accessibility score), keyboard-nav (keyboard navigation, focus order & focus-trap testing), html-structure (alt text, form labels, heading hierarchy, landmarks, duplicate IDs), media-captions (video/audio/iframe caption & transcript checks), and viewport-a11y (zoom-disabling viewport checks). Deselect any you don't want to run.

## `requestHeaders` (type: `object`):

Extra HTTP headers to send to the target, as a JSON object (e.g. {"Authorization": "Bearer <token>"}). Use this for authenticated scanning so the engines reach the logged-in surface instead of only public pages. Sent only to the target's own origin — never forwarded to third-party hosts.

## `cookies` (type: `string`):

A Cookie header value (e.g. "session=abc123") sent to the target for authenticated scanning. Same origin scoping as Custom request headers.

## `outputFormat` (type: `string`):

What to write. "json" (default) writes the normalized JSON report to the OUTPUT key-value record and the dataset. "sarif" also writes a SARIF 2.1.0 record (OUTPUT.sarif) for GitHub/GitLab code scanning. "both" is an alias for json + sarif.

## `failOnGrade` (type: `string`):

Optional. If set, the run exits with a non-zero code when the accessibility grade is this letter or worse — so a CI pipeline can block a deploy on it. The report is still written and the run is still charged. Leave unset to always exit 0.

## `failOnSeverity` (type: `string`):

Optional. If set, the run exits with a non-zero code when any finding is at this severity or higher. Independent of Fail run at grade; either condition triggers a failure.

## Actor input object example

```json
{
  "url": "https://example.com",
  "engines": [
    "wcag-audit",
    "render-audit",
    "html-structure"
  ],
  "outputFormat": "json",
  "failOnGrade": "",
  "failOnSeverity": ""
}
```

# Actor output Schema

## `scanReport` (type: `string`):

Full accessibility scan report with normalized findings.

# 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 = {
    "url": "https://defaultinput.com"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nativefoundation-inc/accessibility-scan-actor").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 = { "url": "https://defaultinput.com" }

# Run the Actor and wait for it to finish
run = client.actor("nativefoundation-inc/accessibility-scan-actor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "url": "https://defaultinput.com"
}' |
apify call nativefoundation-inc/accessibility-scan-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=nativefoundation-inc/accessibility-scan-actor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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