Scan entire websites for WCAG 2.1 AA issues. Smart deduplication groups shared component issues so you fix 1 problem, not 50 duplicates.
Try It Free · Report Bug · GitHub Action
96.3% of the top 1 million websites fail WCAG compliance (WebAIM 2024). Traditional scanners make this worse by flooding you with duplicate issues.
A site with 50 pages and a broken header? That's 50 identical "missing alt text" reports. WCAG Crawler groups them into 1 actionable issue.
Traditional Scanner WCAG Crawler
────────────────── ────────────
Page 1: Missing alt text Shared Component: Header
Page 2: Missing alt text ├── Missing alt text
Page 3: Missing alt text └── Affects 50 pages
...
Page 50: Missing alt text = 1 issue to fix
= 50 issues to review
Result: Less noise. Faster fixes. Happier developers.
| Feature | Description |
|---|---|
| Full Site Crawling | Automatically discovers and scans all pages within your domain |
| WCAG 2.1 AA | Tests against WCAG 2.0 A, 2.0 AA, 2.1 A, and 2.1 AA criteria |
| Smart Deduplication | Groups shared component issues (header, nav, footer) — 50x less noise |
| Duplicate Page Detection | Detects content-identical pages served at different URLs (.action, .do, .jsf) |
| Real-Time Progress | Live updates via WebSocket as your site is scanned |
| Fix Suggestions | Before/after code examples for every issue |
| Severity Filtering | Filter by Critical, Serious, Moderate, or Minor |
| CI/CD Ready | GitHub Action for automated accessibility testing in your pipeline |
| Self-Hostable | Docker support — run it on your own infrastructure |
| Privacy-First | No data leaves your instance. Scan history in localStorage |
Go to wcag.thegridbase.com, enter a URL, and scan. No account needed.
# Clone and install
git clone https://github.com/cankilic-gh/wcag-crawler.git
cd wcag-crawler
pnpm install
# Run migrations and start
pnpm db:migrate
pnpm devOpen http://localhost:5173 (frontend) and http://localhost:3001 (API).
cd docker
docker-compose up -dEnter a URL. WCAG Crawler uses Playwright to discover all linked pages within your domain — respecting depth limits and URL patterns.
Each page is tested with axe-core, the industry-standard accessibility engine used by Google, Microsoft, and the US government.
This is the magic. WCAG Crawler:
- Fingerprints DOM regions (header, nav, footer, main, body) using SHA-256 hashes of normalized HTML structure
- Groups shared issues — if 50 pages share the same broken header, you see it once
- Detects duplicate pages —
/registrationand/displayRegistration.actionserving identical content? Merged automatically - Catches repeated selectors —
#search-buttonfailing on every page? One grouped issue
Get actionable reports with severity filtering, before/after code fixes, WCAG criteria references, and direct links to Deque University.
Add WCAG scanning to your CI/CD pipeline:
name: Accessibility Audit
on: [push, pull_request]
jobs:
a11y:
runs-on: ubuntu-latest
steps:
- uses: cankilic-gh/wcag-crawler@main
with:
url: 'https://your-site.com'
threshold: 70 # Fail if score < 70
fail-on-critical: true # Fail on critical issues| Input | Default | Description |
|---|---|---|
url |
required | URL to scan |
max-pages |
50 |
Maximum pages to crawl |
max-depth |
3 |
Crawl depth limit |
threshold |
0 |
Minimum score to pass (0-100) |
fail-on-critical |
false |
Fail if critical issues found |
The server resolves entitlement from a verified principal and clamps numeric
overages. Anonymous users receive a one-time per-scan capability token; signed-in
users can access only scans owned by their immutable Google sub. Legacy scans
without an owner or capability are admin-only.
| Role | Pages | Depth | Concurrency | Target-site credentials |
|---|---|---|---|---|
| Anonymous | 10 | 2 | 1 | No |
| Verified Google user | 50 | 3 | 2 | No |
| Allowlisted admin | 100 | 5 | 3 | Yes |
Anonymous scan creation is rate-limited by IP; authenticated scan creation is
rate-limited by Google subject. Google ID tokens are verified server-side for
signature, audience, issuer, expiration, immutable sub, and verified email.
| Option | Default | Description |
|---|---|---|
maxPages |
Role cap | Maximum pages to crawl |
maxDepth |
Role cap | How many links deep to follow |
concurrency |
Role cap | Simultaneous page scans |
delay |
500ms | Delay between batches |
excludePatterns |
[] |
URL patterns to skip (e.g., /logout, *.pdf) |
viewport |
1280x720 | Browser viewport size |
Values above a cap are clamped down to it; absolute request validation bounds still apply on top. Authentication credentials are used only to log in during a scan — they are never persisted to the database or returned by the list, detail, or report APIs.
Embed credentials only in the dedicated authentication fields. URLs containing
userinfo (user:pass@host) or credential-like query parameters such as
token, access_token, api_key, password, session, or signature are
rejected at scan creation. Legacy stored URLs and crawler-discovered URLs are
sanitized before persistence, logs, socket events, and report/export output.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/scans |
Start a new scan |
GET |
/api/scans |
List caller-owned scans (admin: all; anonymous: none) |
GET |
/api/scans/:id |
Get owned/capability-authorized scan details |
DELETE |
/api/scans/:id |
Delete a scan |
POST |
/api/scans/:id/cancel |
Cancel a running scan |
GET |
/api/reports/:scanId |
Get full report |
GET |
/api/reports/:scanId/export |
Export as HTML |
Frontend Backend Infrastructure
───────── ─────── ──────────────
React 18 Express Docker
TypeScript 5 Playwright Railway / Render
Vite axe-core Vercel (client)
Tailwind CSS SQLite Socket.IO
Zustand Node.js 20+
Government agencies — Support your Section 508 and European Accessibility Act (EAA) efforts by surfacing common issues early with automated scanning (see Automated Testing Limitations).
Web agencies — Offer accessibility audits to clients. Generate professional reports in minutes.
Enterprise — Reduce accessibility risk by catching common, ADA-related barriers before they ship. Scan hundreds of pages at once.
Developers — Integrate into CI/CD. Catch accessibility regressions before they ship.
WCAG Crawler runs axe-core, which detects only programmatically identifiable accessibility issues — a subset of the WCAG success criteria. Automated tools cannot evaluate everything: meaningful alt-text quality, logical reading and focus order, keyboard operability of complex widgets, and content clarity all require human judgment and testing with assistive technologies and real users.
As a result, WCAG Crawler:
- Does not certify WCAG 2.1, Section 508, or European Accessibility Act (EAA) compliance
- Does not replace manual evaluation by a qualified accessibility expert
- Is not legal proof of compliance or a guarantee against accessibility-related claims
Use these reports to find and fix common issues quickly and to track progress over time — then complement them with manual audits and usability testing for broader coverage.
Frontend — Vercel
cd packages/client
vercel --prodSet environment variables:
VITE_API_URL=https://your-backend.up.railway.app
VITE_SOCKET_URL=https://your-backend.up.railway.app
Backend — Railway
- Go to railway.app and connect your GitHub repo
- Railway auto-detects the Dockerfile
- Add env vars:
CLIENT_URL,NODE_ENV=production - Generate domain on port
3001
Backend — Render
- Go to render.com and connect your repo
- Click "New" > "Blueprint" (auto-detects
render.yaml) - Or manually: Web Service > Docker > Dockerfile path:
docker/Dockerfile
Environment Variables
| Variable | Description | Example |
|---|---|---|
CLIENT_URL |
Frontend URL (CORS) | https://wcag.thegridbase.com |
NODE_ENV |
Environment | production |
PORT |
Server port | 3001 |
Need continuous monitoring, team dashboards, and automated alerts? Check out AccessPulse — our managed platform built on this engine.
Contributions are welcome! Please feel free to submit a Pull Request.
If you find WCAG Crawler useful, consider giving it a star — it helps others discover the project.
MIT © TheGridBase
Try WCAG Crawler Free · AccessPulse — Managed Monitoring
Built for web accessibility.