Open-source web accessibility auditing and VPAT reporting.
a11yVault audits HTML pages against WCAG 2.2 (A / AA / AAA) and generates VPAT 2.5 Rev WCAG conformance report data. It combines automated scanning (axe-core + Puppeteer), optional AI-powered remediation and deeper analysis, and a multi-tenant application layer with organization isolation, billing hooks, and a developer API.
This repository is intended for self-hosting and development. There is no affiliated hosted service claimed by this project.
- Automated scanning — headless Chromium +
@axe-core/puppeteer, with retry logic, a site crawler, and weighted scoring - Authenticated crawling — login automation (selector-based and guided browser session) for pages behind auth
- AI fix suggestions — structured remediation suggestions and corrected HTML (requires an AI API key)
- Enhanced analysis — AI-assisted review of WCAG criteria not fully covered by axe-core
- Manual review checklist — AI-assisted checklist for criteria that need human judgment
- Media accessibility — captions (VTT), transcripts, and audio-description scripts for video/audio (WCAG 1.2.x), with separate media-minute metering
- VPAT 2.5 exports — JSON, CSV, Markdown, and DOCX with level filtering
- Remediation tracking — per-violation status with aggregate stats
- Auth — Google + Microsoft OIDC, session-based, org-scoped data isolation
- Billing hooks — credit-based plans via Stripe (optional)
- Developer API & webhooks —
/api/v1/with API keys and OAuth2 client-credentials, HMAC-signed webhooks - Figma integration — optional design-side audit workflows
- Admin console — metrics, user/org management, and an internal accuracy benchmark suite
For security design notes, see threat_model.md.
| Layer | Technology |
|---|---|
| Frontend | React + TypeScript, Vite, Tailwind CSS, shadcn/ui, wouter, TanStack Query |
| Backend | Express.js, session auth (express-session + connect-pg-simple) |
| Database | PostgreSQL + Drizzle ORM (file-based migrations) |
| Scanning | Puppeteer, @axe-core/puppeteer, Pa11y, Lighthouse, Chromium |
| AI | OpenAI-compatible HTTP API (default base URL points at xAI; model IDs via env) |
| Auth | openid-client, Passport (Google + Microsoft OIDC) |
| Billing | Stripe (optional) |
| Resend (optional) |
client/ React frontend (pages, components, hooks)
server/ Express API, scanning engine, AI services, routes
shared/ Drizzle schema and types shared by client + server
migrations/ SQL migrations (also applied at server startup)
script/ Production build script (esbuild + Vite)
scripts/ Operational scripts
tests/ Vitest suites
benchmark/ Accuracy benchmark fixtures
- Node.js 20+ and npm
- PostgreSQL
- Chromium (for Puppeteer scans)
- API credentials for the optional services you enable (see below)
git clone <your-fork-or-clone-url>
cd a11yVault
npm installCopy .env.example to .env and fill in values. At minimum you need:
DATABASE_URLSESSION_SECRETXAI_API_KEY(only if you want AI features)
Set model IDs with XAI_CODE_MODEL, XAI_FAST_MODEL, and XAI_BATCH_MODEL to match whatever models your AI provider currently supports.
npm run db:pushMigrations under migrations/ also run automatically when the server starts.
npm run devDefault port is 5000 (PORT env var).
npm run build
npm start| Command | Description |
|---|---|
npm run dev |
Dev server |
npm run build |
Build client + server into dist/ |
npm start |
Run production build |
npm run check |
TypeScript check (tsc) |
npm run db:push |
Push Drizzle schema |
Secrets are never committed. Use a local .env or your host’s secret store.
| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
SESSION_SECRET |
Signs session cookies |
| Variable | Purpose |
|---|---|
XAI_API_KEY |
API key for the OpenAI-compatible AI provider |
XAI_BASE_URL |
API base URL (default https://api.x.ai/v1) |
XAI_CODE_MODEL |
Model id for code-fix generation |
XAI_FAST_MODEL |
Model id for fast/vision analysis |
XAI_BATCH_MODEL |
Model id for batch jobs |
| Variable | Purpose |
|---|---|
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google OIDC |
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET |
Microsoft Entra ID |
OAUTH_JWT_SECRET |
Signs OAuth2 client-credentials tokens (falls back to SESSION_SECRET) |
CSRF_SECRET |
CSRF token signing |
ADMIN_EMAILS |
Comma-separated super-admin emails |
| Variable | Purpose |
|---|---|
STRIPE_SECRET_KEY |
Stripe secret key |
STRIPE_WEBHOOK_SECRET |
Stripe webhook signing secret |
STRIPE_*_PRICE_ID |
Price ids for plan tiers (see .env.example) |
| Variable | Purpose |
|---|---|
RESEND_API_KEY |
Resend API key |
RESEND_FROM_EMAIL |
From address |
| Variable | Purpose |
|---|---|
PORT |
HTTP port (default 5000) |
APP_URL |
Public base URL for links in emails/reports |
NODE_ENV |
development / production |
CHROME_BIN / PUPPETEER_EXECUTABLE_PATH |
Chromium binary |
MEDIA_TRANSCRIBE_DIR |
Optional external transcription tool project path |
MEDIA_TRANSCRIBE_BIN |
Optional CLI name inside that project |
npx vitest run
npx vitest run tests/scoring.test.ts
npx tsx server/benchmark/run-smoke.tsThe benchmark suite validates scanning accuracy against versioned baselines. Results can be viewed in-app at /admin/benchmarks when admin is configured.
The app runs as a single Node process serving the API and built client. You need Node, PostgreSQL, and Chromium available.
GET /health checks database connectivity for health probes.
a11yVault handles multi-tenant data, server-side fetches of user-supplied URLs, and optional billing state. Protections include tenant isolation, SSRF checks, rate limiting, CSRF protection, input validation, HMAC-signed webhooks, and PII scrubbing where applicable. See threat_model.md.
MIT — see LICENSE.