# IS 5568 & WCAG AA Accessibility Audit (Hebrew) (`elab/il-accessibility-5568-compliance-audit`) Actor

IS 5568 (Israeli accessibility standard, WCAG 2.0 AA) audit in a real browser with axe-core. Element screenshots, flat violation rows, and a Hebrew legal-citation PDF (Equal Rights law section 19na). Automated scan only, not legal advice. Failed or blocked pages are not charged. נגישות אתרים ת"י

- **URL**: https://apify.com/elab/il-accessibility-5568-compliance-audit.md
- **Developed by:** [Barak Eliov](https://apify.com/elab) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## Israel Accessibility Compliance Audit (IS-5568 / WCAG AA)

Audits websites against IS 5568 (the Israeli accessibility standard, based on WCAG 2.0 AA) in a real Chromium browser, using the [axe-core](https://github.com/dequelabs/axe-core) engine (MIT, Deque Systems). It outputs per-page results, element screenshots, and an optional Hebrew legal-citation PDF that cites the Equal Rights for Persons with Disabilities Law (section 19na). Automated scan only, not legal advice.

This is v1 (the scope approved in `SPEC.md`). See "What's not in v1 yet" below.

### What this Actor does

1. Audits every URL you supply at **WCAG AA** - the exact level Israel's Equal Rights for Persons with
   Disabilities (Service Accessibility Adjustments) Regulations, 5773-2013, require via **Israeli
   Standard 5568 (IS-5568)**.
2. Produces a **Hebrew-language compliance report** (PDF) that cites the regulations and section 19na of
   the Equal Rights for Persons with Disabilities Law (a civil tort allowing **statutory damages of up to
   50,000 ILS without proof of actual harm**), maps every violation to its WCAG criterion in Hebrew, and
   includes screenshots and a batch summary. With `outputMode` `flat` or `both`, the **dataset** has every
   single violation row for every URL; the **PDF itself** embeds up to 200 findings in full detail per run (see "Report size
   limits" below) so a large, dense batch can't produce an unbounded file.
3. **Never charges for a failed or blocked audit** - the same guarantee verified on the English sibling.

### What makes this different from the global WCAG-audit Actors on Apify

None of the global competitors - including this Actor's own English sibling - target the Israeli market,
cite the binding Israeli legal text, or disclose the statutory-damages exposure. Confirmed zero Hebrew/
Israel-specific competitors via `search-actors` on 2026-10-02 (see `data/ledger.md`).

### Legal exposure: an existing condition, not a deadline

The legal exposure described in the report is **ongoing from the date the regulations took effect** - it
is **not** tied to any future compliance date, and does not depend on how many lawsuits have actually been
filed. This Actor deliberately does **not** claim any approaching "compliance deadline": a "June 2026"
claim found repeated across several Israeli accessibility-vendor marketing pages was checked against the
regulation's actual text and has no basis there - it is not used anywhere in this Actor's code, input
schema, or reports.

### Important legal disclaimer (read before relying on the report)

**The legal report this Actor produces is the output of an automated scan (axe-core on a real browser). It
is not a certified legal audit, not a legal opinion, and does not constitute legal advice. It does not
guarantee any legal outcome or full compliance with the law.** Consult a lawyer and/or a certified
accessibility auditor before relying on its findings.

This disclaimer is not cosmetic: overclaiming accessibility compliance is exactly what cost accessiBe a
2025 FTC fine of $1 million for misleading consumers about their sites' compliance level. This report
cites a real statutory-damages figure, so the disclaimer appears in every report the Actor produces, not
just here.

### What is cited here - and what is not

- **Cited**: the free regulation/law text (Nevo, nevo.co.il) and the official WCAG success-criterion
  numbers (free, W3C/MIT, via axe-core).
- **Not cited**: Israeli Standard 5568's own internal clause numbering. The standard document itself is
  sold by Israel's national standards institute (SII) and may be copyrighted - v1 cites the standard's
  *name* only ("Israeli Standard 5568"), never its internal numbering. The `wcagCriterionHebrewName` field
  is this Actor's own working translation of W3C's free "Understanding WCAG" titles, **not** a translation
  of IS-5568's own text.
- **Transparency note on "verbatim"**: this Actor's legal report presents a **verified summary** of the
  regulation's/law's substance, with a direct link to the authoritative source - not a character-for-
  character quote. An attempt to upgrade this to an actual verbatim quote (via WebFetch, post-build)
  surfaced a real finding worth knowing: re-fetching the same statutory section twice produced two
  different Hebrew wordings, because AI-summarizing fetch tools don't return raw page text (see
  `docs/lessons.md` #5). A true verbatim quote would need a raw HTML fetch or manual verification against
  the Nevo links in the report before any legal reliance.

### Input example

```json
{
  "urls": ["https://example.com"],
  "wcagLevel": "wcag2aa",
  "generateLegalReport": true,
  "reportLanguage": "he"
}
```

### Input defaults

Every input field has a default. `.actor/input_schema.json` is the authoritative source; this table is
generated from it and the defaults below match that file exactly.

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `urls` | array | `["https://example.com"]` | Public page URLs to audit, one audit per URL (up to 100 per run). No crawling. |
| `wcagLevel` | string | `"wcag2aa"` | WCAG level to check. `wcag2aa` is the level IS 5568 adopts. |
| `viewport` | string | `"desktop"` | Screen preset: `desktop`, `tablet`, `mobile`, or `custom`. |
| `viewportWidth` | integer | `1280` | Custom viewport width in px (used only when `viewport` is `custom`). |
| `viewportHeight` | integer | `800` | Custom viewport height in px (used only when `viewport` is `custom`). |
| `includeScreenshots` | boolean | `true` | Element screenshot per violation plus one full-page screenshot per URL. |
| `includeIncomplete` | boolean | `true` | Also return axe-core checks that need human review (`status` = `incomplete`). |
| `includePasses` | boolean | `false` | Also return the count of rules that passed. |
| `outputMode` | string | `"both"` | Row shapes: `perPage` (page rows), `flat` (one page row per URL plus one row per violation; one `page-audited` charge per successful page, issued after its rows are saved), or `both` (page row plus violation rows, charged per successful page). |
| `generateLegalReport` | boolean | `true` | Generate the Hebrew legal-citation PDF report for the run (charged only on success). |
| `reportLanguage` | string | `"he"` | Legal report language: `he`, `en`, or `both`. Legal references stay in Hebrew. |
| `generatePdfReport` | boolean | `false` | Also generate a plain English WCAG-only PDF report (charged only on success). |
| `waitForSelector` | string | `""` | Optional CSS selector to wait for before auditing. Empty means no wait. |
| `waitUntil` | string | `"load"` | Navigation readiness: `load`, `domcontentloaded`, or `networkidle`. |
| `timeoutSecs` | integer | `30` | Per-URL time budget in seconds for navigation, audit and screenshots. |
| `proxyConfiguration` | object | `{"useApifyProxy":true}` | Apify Proxy settings used for the audit requests. |
| `maxConcurrency` | integer | `5` | Maximum number of pages audited in parallel within one run. |

### Output example

The dataset has three row shapes, distinguished by `rowType`.

**Page row** (one per audited URL):

```json
{
  "rowType": "page",
  "url": "https://example.com",
  "finalUrl": "https://example.com/",
  "status": "success",
  "wcagLevel": "wcag2aa",
  "viewport": "desktop",
  "score": 92,
  "violationCount": 1,
  "incompleteCount": 0,
  "passCount": 0,
  "violationsByImpact": { "critical": 0, "serious": 0, "moderate": 1, "minor": 0 },
  "fullPageScreenshotUrl": "https://api.apify.com/v2/key-value-stores/.../records/fullpage-....png",
  "waitForSelectorTimedOut": false,
  "errorCategory": null,
  "errorMessage": null,
  "auditedAt": "2026-10-02T12:00:00.000Z",
  "engineVersion": "4.13.0"
}
```

**Violation row** (one per individual finding, when `outputMode` is `flat`/`both`):

```json
{
  "rowType": "violation",
  "pageUrl": "https://example.com",
  "ruleId": "image-alt",
  "impact": "critical",
  "status": "violation",
  "description": "Images must have alternate text",
  "helpText": "Add an alt attribute",
  "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/image-alt",
  "wcagCriteria": ["1.1.1"],
  "wcagCriterionHebrewName": "1.1.1 – תוכן שאינו טקסטואלי",
  "selector": "#logo",
  "htmlSnippet": "<img id=\"logo\">",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/.../records/violation-....png",
  "nodeCount": 1
}
```

`wcagCriterionHebrewName` is `null` when `wcagCriteria` is `null` (axe-core best-practice rules with no
numbered WCAG mapping) or when the criterion is not yet in this Actor's translation table - never guessed.

**Summary row** (exactly one per run, also saved to the key-value store as `batchSummary`):

```json
{
  "rowType": "summary",
  "totalPagesAudited": 1,
  "totalPagesFailed": 0,
  "totalViolations": 1,
  "violationsByImpact": { "critical": 0, "serious": 0, "moderate": 1, "minor": 0 },
  "topFailingRules": [{ "ruleId": "image-alt", "pageCount": 1 }],
  "pdfReportUrl": null,
  "legalReportUrl": "https://api.apify.com/v2/key-value-stores/.../records/legal-report-....pdf",
  "regulationCitation": {
    "source": "נבו (nevo.co.il)",
    "regulationUrl": "https://www.nevo.co.il/law_html/law01/500_865.htm",
    "lawUrl": "https://www.nevo.co.il/law_html/law01/p214m2_001.htm",
    "disclaimer": "דוח זה הוא תוצר של סקירה אוטומטית... / This report is an automated scan..."
  }
}
```

### Errors (never silent, never charged)

| Category | When |
|---|---|
| `invalid_url` | Malformed URL, non-http(s) URL, or the URL resolves to a private/link-local/reserved IP address (SSRF protection, always on) |
| `not_found` | DNS failure, connection refused, 404/410 |
| `blocked` | 401/403/429 response, or a Chromium block error (e.g. `ERR_BLOCKED_BY_RESPONSE`). Never retried |
| `timeout` | Navigation, the axe-core audit, or screenshot capture exceeded `timeoutSecs` combined |
| `render_error` | Browser crash or an unclassified render failure |
| `upstream_changed` | 5xx upstream server error |

A failed page is **never charged**. A legal report that cannot be produced (zero pages succeeded in the
batch) is **not charged** either - `page-audited` charges for pages that did succeed in the same batch are
unaffected.

### Report size limits (dataset vs. PDF)

With `outputMode` `flat` or `both`, the **dataset** is complete: every violation/incomplete finding for every
URL is a full row, regardless of batch size. With `perPage`, the dataset holds only page rows (with the
`violationsByImpact` summary) and the summary row. The limits below apply only to what's embedded in full detail (HTML snippet +
screenshot image) inside the **PDF report body** (`generatePdfReport` and/or `generateLegalReport`):

- **Per page**: at most 20 findings embedded in full, confirmed violations before "needs manual review"
  items, most severe first. A single dense real page (e.g. a news homepage with 150+ findings) cannot
  alone blow up the PDF.
- **Per batch**: a shared ceiling of 200 findings embedded in full across the whole run (up to the
  100-URL-per-run maximum), so many individually-small pages still can't sum to an unbounded file.
- **Per screenshot**: capped at 2000x1200 CSS pixels (width x height). Several common rules (`landmark-one-main`,
  `page-has-heading-one`, `region`, etc.) resolve to a whole-page-length element (`html`/`body` itself) -
  confirmed live on real sites (gov.il, calcalist.co.il, amazon.com) during this Actor's stress test, where
  this alone was a major driver of PDF size; the cap keeps the embedded screenshots bounded without
  changing the findings or the page count.
  Oversized elements get a top-left crop instead of a silently-giant full-length screenshot.
- Whatever is held back is **never silently dropped** - the report prints exactly how many additional
  findings exist on that page and how many of them are confirmed violations vs. items needing manual
  review, with a pointer to the full dataset.
- PDF rendering (both report types) has an internal **3-minute outer deadline** for the whole batch. If
  exceeded, generation is aborted, logged, and **not charged** - page-level `page-audited` charges already
  applied in the same run are unaffected, and `pdfReportUrl`/`legalReportUrl` in the summary row stay
  `null` for that run.

### Pay-per-event pricing

| Event key | When |
|---|---|
| `page-audited` | One page successfully audited, including screenshots |
| `legal-report-generated` | The Hebrew compliance report was produced successfully (default: on) |
| `report-generated` | The plain WCAG-only PDF report (English) was produced successfully (default: off) |

Every event name is checked against Apify Console's event-key charset (`^[a-zA-Z0-9_-]{1,256}$`, no
spaces) in `tests/events.test.ts` before a build is considered done.

### Local development / Apify run

```bash
npm install
npx playwright install chromium   # one-time
npm run typecheck
npm test
npm run build
apify run --input-file smoke-input.json --purge
```

### Use with AI agents / MCP

Call with `urls` as an array (never comma-separated). Check `rowType` first, then `status`/`errorCategory`
on page rows. `wcagCriterionHebrewName` and `summary.legalReportUrl`/`regulationCitation` are this Actor's
Israel-specific fields on top of the English sibling's schema - everything else is identical.

### FAQ

**Am I charged for a failed or blocked audit?** No. This is this Actor's central guarantee.

**Is the legal report legal advice?** No. See "Important legal disclaimer" above.

**Is `wcagCriterionHebrewName` a quote of Israeli Standard 5568?** No - it's this Actor's own working
translation of W3C's free criterion titles, not an official translation and not IS-5568's own text.

### What's not in v1 yet

Site-crawl/auto-discovery, CI/CD webhooks, scheduled audits, custom rule-set authoring - the same explicit
deferral list as the English sibling.

# Actor input Schema

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

Public page URLs to audit. Each URL produces one audit. The tool only checks the pages you provide - it does not crawl or discover other pages itself. Up to 100 URLs per run.

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

WCAG level/version to check accessibility against. 'wcag2aa' (default) is the exact level that the Equal Rights (Service Accessibility Adjustments) Regulations adopt via Israeli Standard 5568 (IS 5568). wcag21aa and wcag22aa are extended supersets that also meet this minimum and additionally cover newer criteria relevant to mobile.

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

Screen resolution used for the audit. 'mobile' catches mobile-relevant violations (e.g. the WCAG 2.2 Target Size rule) that a desktop-only check would miss.

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

Used only when Viewport is set to 'custom'.

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

Used only when Viewport is set to 'custom'.

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

A focused screenshot for each violation, plus a full-page screenshot for each URL. Included in the 'page-audited' event price - no extra charge.

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

Also include axe-core 'incomplete' checks that need human review, alongside confirmed violations. The 'status' field in each row distinguishes 'violation' (confirmed) from 'incomplete' (needs review) - they are never merged.

## `includePasses` (type: `boolean`):

Also return the count of rules that passed. Off by default to keep output focused on actionable findings.

## `outputMode` (type: `string`):

'perPage' returns one page row per URL with a violationsByImpact summary. 'flat' returns one page row per URL plus one violation row per individual finding (suited to spreadsheets and ticketing systems); each successful page is charged once, after its rows are saved. 'both' returns the same rows as 'flat', tagged by the 'rowType' field. Failed URLs get an error page row in every mode, never charged.

## `generateLegalReport` (type: `boolean`):

Generate a Hebrew PDF report per run: a reference to the Equal Rights Regulations (which adopt IS 5568 / WCAG AA), section 19na of the Equal Rights Law (statutory damages up to 50,000 ILS without proof of harm), each violation mapped to its WCAG criterion, screenshots, and a batch summary. Enabled by default. Automated scan only, not legal advice (see README). Charged separately as 'legal-report-generated', only when generation succeeds.

## `reportLanguage` (type: `string`):

Language of the legal compliance report. 'he' (default) is the tool's main purpose: a Hebrew report with the legal citations inline. 'en': an English report body, with the Hebrew legal citations appended in full (the Hebrew findings body is not rendered). 'both': the Hebrew body, then the English body, then the Hebrew citations. Legal references are always in their original Hebrew and are never replaced by a translation.

## `generatePdfReport` (type: `boolean`):

Generate an additional plain PDF report without the Israeli legal context (as in the English sister Actor), for multinational sites that want a pure WCAG report. Charged separately as 'report-generated', only when generation succeeds. Off by default; the Hebrew legal report above is the recommended report for this Actor's target audience.

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

Optional CSS selector to wait for before auditing (for SPAs and client-rendered content). If the selector does not appear within the time budget, the page is still audited and 'waitForSelectorTimedOut' is set to true instead of failing.

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

When to start the audit. 'load' (default, recommended) is reliable even on complex sites with continuous ad/analytics network activity, which is very common on Israeli sites. 'networkidle' waits for the network to go quiet - more thorough for slow-loading content, but often never happens on many sites and causes timeouts. 'domcontentloaded' is fastest but may run before late-loading content.

## `timeoutSecs` (type: `integer`):

Maximum seconds for navigation, axe-core checks and screenshot combined, before a URL is marked as a timeout error (not charged).

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

Apify Proxy settings for the audit request.

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

Maximum number of pages audited in parallel within a single run.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "wcagLevel": "wcag2aa",
  "viewport": "desktop",
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "includeScreenshots": true,
  "includeIncomplete": true,
  "includePasses": false,
  "outputMode": "both",
  "generateLegalReport": true,
  "reportLanguage": "he",
  "generatePdfReport": false,
  "waitForSelector": "",
  "waitUntil": "load",
  "timeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 5
}
```

# Actor output Schema

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

One row per audited URL (rowType "page"), optionally one row per individual finding (rowType "violation", when outputMode is "flat"/"both", including a Hebrew WCAG-criterion name), and exactly one batch rollup row (rowType "summary", including the regulationCitation pointer and legalReportUrl).

## `files` (type: `string`):

Full-page and element-cropped PNG screenshots referenced by fullPageScreenshotUrl/screenshotUrl in dataset rows; the 'batchSummary' record; the Hebrew legal-citation PDF (when generateLegalReport is true, the default) referenced by summary.legalReportUrl; and the optional plain English WCAG PDF (when generatePdfReport is true) referenced by summary.pdfReportUrl.

# 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://example.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("elab/il-accessibility-5568-compliance-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://example.com"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("elab/il-accessibility-5568-compliance-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://example.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call elab/il-accessibility-5568-compliance-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,elab/il-accessibility-5568-compliance-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/3FPDoG1wA5Ti8AXqu/builds/YKcO0htlIYi1X3oxT/openapi.json
