andridejager.me
All projects

November 2024

A11y Audit

Automated web accessibility auditing tool that crawls sites, runs axe-core scans via headless browser, and generates AI-powered summaries of violations for both developers and clients.

React TypeScript Supabase AWS Fargate Docker Puppeteer axe-core OpenAI Accessibility Automation

Accessibility audits typically produce dense technical output that is useful for developers but difficult to act on for clients and stakeholders. A11y Audit addresses this by crawling a site, running a full axe-core scan via headless browser, and generating two distinct outputs from the same results — one for the development team and one for the client.

What It Does

The tool takes a website URL, crawls the target pages, and runs automated WCAG compliance scans using Puppeteer and axe-core. Once the scan completes, OpenAI generates a plain-language summary of the violations, translating technical findings into something meaningful for non-technical stakeholders. The result is a developer report with violation details and remediation guidance, and a client-ready document suitable for presenting in reviews or submitting as part of a compliance process.

Tech Stack

  • Frontend: React 19 with TypeScript, Material UI, React Router v7, hosted on Netlify
  • Backend: Supabase (Postgres and Edge Functions on Deno), OpenAI for AI-generated audit summaries
  • Scanner: Node.js and Express, Puppeteer and axe-core for headless browser-based scanning, containerised with Docker and deployed via AWS Fargate

Scan Flow

The scanner is the only containerised piece of the system. The full flow works as follows:

  1. The React frontend calls ScannerService.ts, which POSTs to a Supabase Edge Function (trigger-fargate-scan)
  2. The Edge Function spins up an AWS Fargate task — a one-shot container that runs for the duration of the scan and tears itself down when done
  3. The Fargate container runs Puppeteer and axe-core against the target site and writes results to the scan_results table in Supabase
  4. The React frontend polls Supabase directly every 2 seconds until all expected page results are written, with a 5-minute timeout

No persistent scanner infrastructure runs between jobs. Each scan gets a fresh container, which keeps costs low and removes any state bleed between runs.

Containerisation

The scanner Dockerfile uses Node 16 slim with Chrome Stable installed for Puppeteer, exposing port 3001. A docker-compose.yml handles local development. In production, the image is built and pushed to ECR via a CI pipeline, and Fargate pulls it from there to run as a one-shot task per scan job.