Clients:

Own product — lukeduff.co.uk

Category:

Software / SaaS Product

A11y Shield — Accessibility Compliance Platform for the European Accessibility Act

Client: Own product, built by lukeduff.co.uk · Multi-tenant SaaS · EAA & EN 301 549 Accessibility Compliance

1 | Brief

The European Accessibility Act applies to a large number of commercial websites, and the practical obligations that come with it — testing every page, understanding which standard a failure breaches, and publishing a formal Accessibility Statement — are difficult to meet by hand. Most accessibility tools stop at listing violations and leave the legal and remediation work to the customer.

A11y Shield was built to cover the whole loop instead of one step of it: crawl a site, audit every page with axe-core running in real headless Chromium, score conformance against EN 301 549, generate the Accessibility Statement that the regulation requires, export a remediation plan the development team can actually work from, and then keep monitoring for regressions after each deploy.

This is an in-house product rather than client work, and it is written up here as an engineering case study. The platform is around 17,100 lines across 156 files, has been verified end-to-end against real websites, and the public marketing and legal site is live. The logged-in product is not yet transacting — it is gated on the final third-party provisioning (Clerk Organizations, a production Supabase project and the Fly worker deploy), so there are no customers, users or revenue figures to report.

2 | Key Goals

  • Run genuine accessibility audits in a real browser rather than static HTML parsing, using axe-core 4.12 in headless Chromium.
  • Produce a defensible conformance score and grade instead of a raw violation count that tells the customer nothing about priority.
  • Map every finding from an axe rule through to the specific WCAG success criterion and EN 301 549 Chapter 9 clause it relates to.
  • Generate the legally required Accessibility Statement automatically, as both a hosted page and a PDF.
  • Export a remediation plan in formats a development team already uses — CSV and Jira import.
  • Build proper multi-tenancy from the start, so agencies can hold multiple client organisations under one account.
  • Make the whole system degrade gracefully without optional third-party keys, so it never hard-fails on a missing integration.

3 | Solution Snapshot

Problem Solution Implemented
A list of violations does not tell anyone what to fix first or how bad the site actually is Built a scoring model that weights each finding by severity and feeds a logarithmic element multiplier into exponential decay, producing a bounded, monotonic 0–100 conformance score and an A–F grade. The risk band is anchored on that score and escalated when critical barriers sit on a transactional journey.
Findings from an automated tool are not expressed in the language the regulation uses Wrote a zero-dependency mapping layer of 406 lines that translates axe rule tags into WCAG 2.2 success criteria and then into EN 301 549 Chapter 9 clauses, with plain-English framing so a non-technical stakeholder can follow what each failure means.
Driving a real browser to arbitrary user-supplied URLs is a serious server-side request forgery risk Implemented a byte-canonicalised SSRF guard with per-hop connection pinning — the addresses validated during the check are the exact addresses reused for the connection via a per-hop undici agent, so DNS cannot be rebound in between. A second network egress filter runs in the worker container because a headless browser resolves independently of the application.
Deciding whether a page sits on a transactional path needs to be accurate, not a naive substring match Made the transactional-path detection boundary-aware, so a URL such as /my-account is correctly identified while /accountant-services is not — which matters because that classification is what escalates the risk band.
Auditing a full site is long-running work that cannot sit inside a single web request Split the system into a Next.js 16 application and a standalone Fastify, Playwright and axe-core worker, with Inngest handling the durable crawl and per-page audit fan-out, so a scan survives restarts and each page is retried independently.
Optional integrations should not be able to break the core product Built graceful degradation throughout: without an Anthropic key the statement prose and fix examples fall back to deterministic templates, without Resend email quietly no-ops, and without Stripe the billing screens show a reference and a clear message rather than erroring.

4 | Impact

  • The engine has been proven end-to-end on a real site: a 25-page scan produced a D grade at 52/100 with 50 serious issues, a 227 KB Accessibility Statement PDF and a 26-row remediation CSV.
  • The product was dogfooded against itself — its own eleven surfaces went from eight axe violation groups to zero, which is the minimum bar for a tool that sells accessibility.
  • Three adversarial multi-agent QA passes were run against the codebase, the third using 25 agents, covering security, tenancy isolation, billing edge cases and the accessibility of the app itself.
  • The public marketing and legal site is live with all thirteen routes returning 200 and zero axe violations.
  • The euro exposure figures the platform produces are deliberately framed as indicative and carry a disclaimer in the code itself — they are a prioritisation signal, not legal advice, and are never presented as a legal figure.
  • The remaining work is provisioning rather than engineering: enabling Clerk Organizations, standing up the production Supabase project and deploying the worker to Fly. Until those land the product is not transacting, so no customer, usage or revenue claims are made here.
Need something like this built? Get in touch →

What are you waiting waiting for?

Start Your Project Today
Book a FREE Call
footer shape