# EAA Accessibility Reporter: WCAG Findings and Fixes (`fractionalhqforyou/eu-accessibility-act-reporter`) Actor

I find automated WCAG 2.1 A/AA issues with plain-language fixes, selectors and EN 301 549 references. Get a report for remediation and manual review. This scan does not establish EAA or WCAG conformance.

- **URL**: https://apify.com/fractionalhqforyou/eu-accessibility-act-reporter.md
- **Developed by:** [Jessy Mariau](https://apify.com/fractionalhqforyou) (community)
- **Categories:** Developer tools, MCP servers, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 pages

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## EAA Accessibility Reporter: WCAG Findings and Fixes

Give developers the evidence to fix an accessibility issue and give everyone else a report they can read. This Actor runs automated WCAG 2.1 A/AA checks, maps findings to WCAG criteria and EN 301 549 references, and explains the user barrier and a possible fix.

Use it to prepare a remediation backlog and a manual audit. **An automated scan does not establish EAA or WCAG conformance.** The output keeps undecided checks visible and never labels an empty findings list as certified compliance.

**See the report shape:** leave Websites empty and run the bundled demo with no Actor event charge. A real five-page audit costs $0.05 in Actor events; 100 audited pages cost $1.00. Failed pages are not charged. Optional proxy costs are additional.

### Inside the sample report

The fixtures below are fictional pages. These values were read from the actual demo output on 8 September 2026.

| Sample | Automated state | Rules failing | Elements affected |
| --- | --- | ---: | ---: |
| demo-shop.example | `FAIL` | 6 | 29 |
| demo-clean.example | `NO AUTOMATED FAILURES` | 0 | 0 |

For the sample shop, the leading issue is an image without a text alternative. The report explains what a screen-reader user misses, then supplies a fix summary, affected selectors and reference links. An empty automated findings list still needs keyboard, screen-reader and other human checks.

### What it does

Give it a website. It opens the page in a real Chromium, crawls up to 25 internal pages, and runs the axe-core WCAG 2.1 A and AA rule set against the rendered DOM. Then it writes up what it found.

Per page you get a state, and there are only three of them. `FAIL` means at least one rule failed outright. `NEEDS REVIEW` means nothing failed but something came back undecided and a human has to look. `NO AUTOMATED FAILURES` means the automated pass found nothing at all, which is the strongest thing a machine is entitled to say.

Per finding you get the rule id, its severity, how many elements it hits and three sample selectors, plus the WCAG criteria and EN 301 549 clauses. Then the part that makes it a report rather than a log: one sentence on what the visitor experiences, and one on the fix. A missing alt attribute comes back as a screen reader announcing nothing where sighted visitors see a picture, rather than as the string `image-alt`.

Per site you get the totals, the ten issues affecting the most elements, and `eaa_report_text`, which is a few plain paragraphs you can paste into an email.

There is also a scope flag, and it is deliberately modest. `likely_in_eaa_scope` is set from features the Actor can actually see on the page, such as a basket, a checkout, a login, a booking flow or consumer banking wording, and `eaa_scope_reasoning` says in words which ones were seen. It never claims a business is legally in scope. It cannot know that. Scope depends on what a company sells and how big it is, not on what one page displays.

### What you need

Nothing. No API key, no account anywhere, no proxy for most sites. Run it with no input at all and it returns two sample rows, one failing and one clean, so you can see the shape before you spend anything.

### How to run it

```json
{
  "websites": [
    "https://www.your-shop.de/",
    "https://www.your-bank.fr/"
  ],
  "maxPages": 5,
  "wcagLevel": "AA",
  "includeIncomplete": true
}
```

`maxPages` defaults to 5 and caps at 25. The URL you give is always audited first, then internal links found on it. `wcagLevel` is `AA` by default, for automated WCAG 2.1 A/AA checks mapped to EN 301 549 clause 9. Drop it to `A` for the smaller rule set.

The Actor also runs in Standby mode as an MCP server, so an AI agent can call `audit_accessibility` as a tool and get the same report back live.

### Output fields

| Field | What it holds |
|---|---|
| `input`, `final_url`, `site` | what you asked for, where it ended up after redirects, and the hostname |
| `conformance_state` | `FAIL`, `NEEDS REVIEW` or `NO AUTOMATED FAILURES` for the site |
| `pages_audited` | how many pages were rendered and audited |
| `violations_count` | distinct rules failing across the site |
| `violating_elements` | how many elements those rules hit in total |
| `critical_count`, `serious_count`, `moderate_count`, `minor_count` | affected elements by severity |
| `passes_count` | checks that came back clean |
| `incomplete_count`, `incomplete_elements` | checks axe could not decide, which need a person |
| `violations[]` | every failing rule: `rule_id`, `impact`, `wcag_criteria[]`, `en301549_clauses[]`, `element_count`, `pages_affected`, `sample_selectors[]`, `plain_english`, `fix_summary`, `help_url` |
| `top_10_issues[]` | the ten rules affecting the most elements |
| `top_issue` | the plain-English line for the worst one |
| `wcag_criteria_failed[]` | every WCAG criterion broken, such as `1.1.1` |
| `en301549_clauses_failed[]` | the matching EN 301 549 clauses, such as `9.1.1.1` |
| `likely_in_eaa_scope` | whether the pages showed features of the kind the directive covers |
| `eaa_scope_signals[]`, `eaa_scope_reasoning` | which features were seen, and the same in words; this is a page observation, not legal applicability |
| `eaa_report_text` | the plain-paragraph report |
| `pages[]` | the same breakdown per page, including the undecided checks |
| `error` | why a site could not be audited, or null |
| `checked_at` | when the run happened |

The `OUTPUT` record in the key-value store holds the run summary: sites audited, how many failed, how many need review, how many came back with no automated failures, and how many pages were charged.

### Pricing

Pay per event, at one `page-audited` charge for every page that is rendered and audited. A page that could not be fetched costs nothing, and neither does a site that times out, gets bot-blocked or answers with an error. The demo run charges nothing at all.

### Limits

Read this part before you send the output to anyone.

**Automated testing finds some of the problem, never all of it.** Deque's Automated Accessibility Coverage Report puts automated coverage at 57% of accessibility issues by volume, while noting that only 16 of the 50 WCAG 2.1 AA success criteria have automated checks at all. Those are their numbers, not mine, and they are the most generous credible figures I could find. A machine cannot tell you whether your alternative text is actually descriptive. Nor can it judge focus order, the helpfulness of an error message, or the accuracy of captions. A keyboard-only pass and a screen-reader pass are still needed, and so is a person who knows what they are looking at.

**A clean run is a floor, not a certificate.** `NO AUTOMATED FAILURES` says the automated checks found nothing. It does not say the site is accessible and it does not say you are compliant.

**Scope flags are observations, not legal findings.** The Actor reports the features it saw on the pages you gave it. Whether the directive applies to your business is a question about your business, and it needs a lawyer rather than a scraper. Microenterprises providing services are treated differently under the directive, which is another thing no page scan can see.

**This is not legal advice and it is not a certified audit.** It is an engineering to-do list with the right legal references attached, which is a genuinely useful thing to have before you commission the real audit, and no substitute for one.

**Practical limits.** Only public http and https pages are audited. Bare IPs and local hostnames are refused. A site behind a hard bot wall fails its row honestly rather than reporting a page nobody could open as clean, which happened to w3.org during testing and is the correct behaviour. Fonts and media are blocked to keep runs cheap, since axe judges an image from its markup rather than its pixels.

### Pair it with a workflow

If you run n8n, my free templates on https://n8n.io/creators/fractional-hq can take this Actor's output and turn it into a tracked remediation backlog, a scheduled re-audit or a report that lands in someone's inbox without another tool in the chain.

I have written up the build and its honest limits at https://fractionalhq.uk/use-cases/accessibility-act-audit

### Use it from an AI agent

Agents get the same report through MCP. The endpoint is `https://fractionalhqforyou--eu-accessibility-act-reporter.apify.actor/mcp` and the one tool on it is `audit_accessibility`, which takes a site URL and returns the audit findings without a separate dataset read. Per-event pricing is unchanged for agent calls. For clients that cannot add a raw endpoint, use `apify/actors-mcp-server` with `fractionalhqforyou/eu-accessibility-act-reporter` in its Actor list.

### Related Actors I publish

The accessibility act is one of several EU rules landing on the same teams, so I publish these companions to it.

- [E-Invoice Validator](https://apify.com/fractionalhqforyou/eu-einvoice-validator): validates XRechnung, ZUGFeRD and Peppol invoices before they bounce.
- [EU Pay Transparency Job Ad Auditor](https://apify.com/fractionalhqforyou/eu-pay-transparency-job-ad-auditor): checks job ads for the pay information the EU directive now expects.
- [Website Redesign Lead Scorer](https://apify.com/fractionalhqforyou/website-redesign-lead-scorer): reads a list of websites and scores its measured redesign opportunities.

### Built by Fractional HQ

Independent design and automation by Jessy Mariau. For setup or a custom integration, [send a brief](https://fractionalhq.uk/brief).

# Actor input Schema

## `websites` (type: `array`):

One website or page URL per line. A bare domain gets https:// added. Leave this empty to see a free demo of the report shape.

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

How many pages to audit per site. The URL you give is always audited first, then internal links found on it. Every page audited is charged.

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

AA runs the WCAG 2.1 A and AA rules, mapped to EN 301 549 clause 9. Pick A for the smaller rule set. Automated checks alone do not establish conformance.

## `includeIncomplete` (type: `boolean`):

axe-core returns some checks it cannot decide alone, usually text over an image. These are not failures and not passes, and someone has to look. Keep this on to see them.

## `maxSites` (type: `integer`):

A safety cap on how many sites from your list get audited in one run.

## `proxyConfiguration` (type: `object`):

Optional. Most sites are audited fine without one. Use a proxy if a target blocks datacentre traffic.

## Actor input object example

```json
{
  "websites": [],
  "maxPages": 5,
  "wcagLevel": "AA",
  "includeIncomplete": true,
  "maxSites": 50
}
```

# Actor output Schema

## `sites` (type: `string`):

One row per site: the automated check state, every failing rule with its WCAG success criteria and EN 301 549 clauses, plain-language descriptions and fixes, the per-page breakdown, and the report paragraphs.

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

The OUTPUT record: how many sites were audited, how many failed, how many need a human review, how many had no automated failures, and how many pages were charged.

# 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 = {
    "websites": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("fractionalhqforyou/eu-accessibility-act-reporter").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 = { "websites": [] }

# Run the Actor and wait for it to finish
run = client.actor("fractionalhqforyou/eu-accessibility-act-reporter").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 '{
  "websites": []
}' |
apify call fractionalhqforyou/eu-accessibility-act-reporter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fractionalhqforyou/eu-accessibility-act-reporter"
        }
    }
}

```

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/XbcJjGk8Xej6LAGKf/builds/2v3ajxfeveelJouSE/openapi.json
