# Accessibility Audit on a Preview URL

> Ranks accessibility findings by who is blocked, not by count — with selectors, fixes, and an honest list of what automation can't check. Never certifies.

- Agent: Claude Code
- Plan: Starter (1 vCPU, 2 GiB RAM, 10 GiB disk)
- Forks: 0 · Stars: 0
- Creator: https://www.jurniti.com/creator-ca0ff2
- Tags: a11y, accessibility, claude-code, frontend, qa, software-factory, wcag
- Requires config (you provide): ANTHROPIC_API_KEY
- Skills: a11y-pass

**To fork:** open https://www.jurniti.com/templates/accessibility-audit-on-a-preview-url and use the Fork action — it starts a Stripe Checkout for a new VM seeded with this template's persist disk (same flat plan price, no fork fee).

## README

# "47 issues found." So the team fixed 40 alt attributes.

The checkout form still can't be completed with a keyboard. The audit passed. The
site is still unusable for the people it was supposed to help.

That's what a report sorted by count does.

## Impact before count

This one opens with **who is blocked**, in plain sentences — *"keyboard users
cannot submit the signup form"* — before any number appears.

Every finding is **BLOCKING** (a user cannot complete a task) or **DEGRADING**
(harder, not impossible). Fix BLOCKING first even though DEGRADING is usually
easier. That ordering is the entire point.

## Five checks that account for most real failures

1. **Missing alt** — and it distinguishes `alt=""` on a decorative icon (*correct*)
   from an absent `alt` (a failure). Checkers routinely conflate these.
2. **Unlabelled inputs** — no `<label for>`, no `aria-label`. **A placeholder is not
   a label**, and that gets flagged explicitly, because it's the most common thing
   teams do believing they fixed it.
3. **Contrast** — the computed ratio and the threshold, not a verdict. Unresolvable
   CSS returns `UNRESOLVED`, never a guess.
4. **Click handlers on non-buttons** — a `div` with an onclick, no role, no
   tabindex. Invisible to keyboard and screen reader.
5. **Heading order** — skipped levels, multiple `h1`s.

Every finding cites the selector and the failing attribute.

## It will not tell you you're compliant

Automated checks catch **roughly a third** of WCAG issues. The rest need a human
and real assistive tech. That caveat is line one of every report, and asking it to
certify gets a refusal.

A "passed" automated audit on an unusable page is worse than no audit — it's a
paper trail of false assurance.

## The section people skip

**Needs a human.** Focus order, screen-reader announcement, motion sensitivity, and
whether your alt text is *useful* — `alt="image"` is present and worthless, and only
a person can call that. Those are listed as unautomatable rather than quietly
passed.

Plus **UNRESOLVED**: checks it couldn't complete and why. A gap stated is not a pass
implied.

## What you supply

Your own Claude Code login. Nothing else — it audits public URLs, including Vercel
and Netlify previews.

It saves the fetched HTML to `~/a11y/pages/` so findings stay reproducible against a
fixed snapshot.

## Where this stops

It finds problems and cites selectors. It does not certify WCAG conformance, issue
a VPAT, or declare a page accessible.

It won't report screen-reader behaviour it didn't observe — it reads a DOM, it
doesn't run NVDA — and it won't opine on ADA risk.

Verified on build: the skill, the working tree, the `NEVER_CLAIM_COMPLIANT` guard,
all five checks, the impact-before-count rule and both honesty rules are present on
a fresh fork. Running it on your own preview is yours to do.
