DEV Community

Cover image for From Scanner Warnings to Verified WCAG Findings: A Technical Accessibility Audit Workflow
Auditzo
Auditzo

Posted on • Originally published at auditzo.com

From Scanner Warnings to Verified WCAG Findings: A Technical Accessibility Audit Workflow

A developer-focused look at turning automated accessibility candidates into verified findings, evidence, remediation ownership, and retestable fixes.


Automated accessibility scanners are useful.

But a scanner warning is not the same thing as a verified accessibility finding.

That sounds obvious, but it has a major impact on how accessibility audits should be designed.

In a recent website accessibility review, we tested 7 representative pages and ended with 29 verified findings.

The interesting part was not the number.

It was everything that happened between automated detection and the final finding.

The workflow looked roughly like this:

Automated discovery
        |
        v
Candidate normalization
        |
        v
Manual verification
        |
        +------> Dismissed / not reproducible
        |
        +------> Needs additional review
        |
        v
Verified finding
        |
        v
Evidence capture
        |
        v
WCAG mapping
        |
        v
Remediation ownership
        |
        v
Priority assignment
        |
        v
Retest
Enter fullscreen mode Exit fullscreen mode

That middle layer is where much of the real accessibility work happens.

Scanner output should be treated as a queue, not a report

A common accessibility workflow looks like this:

Run scanner -> Export results -> Send PDF
Enter fullscreen mode Exit fullscreen mode

Technically, that produces a report.

But it does not necessarily produce a useful audit.

Automated tools can identify many patterns efficiently:

  • missing attributes
  • possible color contrast failures
  • structural issues
  • form-related patterns
  • invalid ARIA
  • semantic inconsistencies
  • certain accessible-name problems

They are very useful for candidate discovery.

But there are many things they cannot fully determine from static analysis.

For example:

  • Is keyboard focus visible throughout a real interaction?
  • Does focus move logically when a menu opens or closes?
  • Is a control understandable in its actual context?
  • Does a form still make sense after placeholder text disappears?
  • Is an iframe usable through the complete keyboard journey?
  • Does responsive reflow make content unusable at a narrow viewport?
  • Does an apparently duplicated link become ambiguous to a screen-reader user?
  • Is the defect controlled by the website team or by a third-party widget?

Those questions require interaction and context.

So architecturally, I prefer treating scanner results as candidates.

Conceptually:

type FindingState =
  | "candidate"
  | "verified"
  | "dismissed"
  | "needs_manual_review";
Enter fullscreen mode Exit fullscreen mode

A candidate should not become a reportable finding simply because a tool emitted it.

Normalize findings before verification

When multiple tools are used, they often report the same underlying problem differently.

Imagine three checks identify something around the same form field:

Tool A:
Input missing label

Tool B:
Form control has no accessible name

Tool C:
Possible WCAG 1.3.1 issue
Enter fullscreen mode Exit fullscreen mode

Those are not necessarily three findings.

They may all describe one underlying implementation problem.

A useful audit pipeline therefore needs normalization.

A simplified conceptual model could look like this:

interface AccessibilityCandidate {
  page: string;
  component?: string;
  selector?: string;

  sourceTool?: string;
  sourceRule?: string;

  category:
    | "keyboard"
    | "focus"
    | "forms"
    | "names"
    | "structure"
    | "contrast"
    | "reflow"
    | "third_party"
    | "other";

  observation: string;

  state:
    | "candidate"
    | "verified"
    | "dismissed"
    | "needs_manual_review";
}
Enter fullscreen mode Exit fullscreen mode

This gives the reviewer something more useful than several unrelated scanner exports.

Verification needs a reproducible test

For each serious candidate, the reviewer should be able to answer:

Can another person reproduce what I observed?

That changes how findings are written.

Instead of:

Button is inaccessible.
Enter fullscreen mode Exit fullscreen mode

A useful finding needs considerably more context.

For example:

Page:
Mobile navigation

Component:
Menu toggle

Test method:
Keyboard interaction and accessible-name inspection

Observation:
The control is visually recognizable as the navigation trigger,
but its programmatic name does not clearly communicate its purpose.

Evidence:
Screenshot + inspected accessibility properties

Remediation direction:
Provide a meaningful accessible name and verify keyboard,
focus, and expanded/collapsed state behavior.

Retest:
Repeat keyboard and accessibility-tree inspection after remediation.
Enter fullscreen mode Exit fullscreen mode

The point is not that every report needs this exact structure.

The point is that the finding should survive handoff.

A developer who was not present during the audit should still understand what was observed.

Evidence should travel with the finding

This becomes especially important when accessibility work involves:

  • developers
  • agencies
  • compliance teams
  • external counsel
  • third-party vendors
  • multiple rounds of remediation

A useful finding therefore needs traceability.

Conceptually:

interface VerifiedAccessibilityFinding {
  id: string;

  page: string;
  component: string;

  severity: "high" | "medium" | "low";

  observation: string;
  userImpact: string;

  reproductionSteps: string[];

  wcagReferences: string[];

  evidence: {
    screenshots?: string[];
    notes?: string[];
    selectors?: string[];
  };

  remediation: string;

  owner:
    | "site"
    | "shared_component"
    | "third_party_vendor"
    | "unknown";

  retestRequired: boolean;
}
Enter fullscreen mode Exit fullscreen mode

This is not meant as a universal specification.

It illustrates an important principle:

The evidence model should be designed before the final report is generated.

Otherwise screenshots, test notes, selectors, scanner output, and remediation recommendations tend to become disconnected artifacts.

Keyboard testing exposes problems static scanning cannot

Keyboard accessibility is one of the clearest examples.

A DOM scanner can inspect markup.

It cannot fully experience an interaction sequence the way a user does.

A basic manual keyboard pass may include:

1. Load page from a clean state
2. Do not use the mouse
3. Press Tab through interactive elements
4. Observe focus visibility
5. Check focus order
6. Activate buttons and links
7. Open menus/dialogs
8. Verify focus movement
9. Close overlays
10. Verify where focus returns
Enter fullscreen mode Exit fullscreen mode

For complex UI, you also need to consider:

Escape
Enter
Space
Arrow keys
Shift + Tab
Enter fullscreen mode Exit fullscreen mode

depending on the component.

A navigation menu might technically contain focusable links and still create a poor keyboard experience.

A modal may open correctly but fail to manage focus.

A custom dropdown may work perfectly with a mouse while being unusable from the keyboard.

These are behavioral defects, not just markup defects.

Accessible names need context too

Accessible-name problems are another area where raw scanner counts can be misleading.

Consider a page containing several cards:

<a href="/property/1">View More</a>
<a href="/property/2">View More</a>
<a href="/property/3">View More</a>
Enter fullscreen mode Exit fullscreen mode

Visually, each link may appear directly below a different property name.

But depending on implementation and assistive-technology navigation, repeated generic link names can become difficult to distinguish.

The technical question is not merely:

Does the <a> element contain text?
Enter fullscreen mode Exit fullscreen mode

It is:

Does the accessible name communicate the purpose of the link
in the context in which users may encounter it?
Enter fullscreen mode Exit fullscreen mode

That requires review.

Forms require interaction, not just markup inspection

Forms are another major source of accessibility findings.

One pattern we encountered involved fields relying heavily on placeholder text.

Conceptually:

<input
  type="text"
  placeholder="First Name"
>
Enter fullscreen mode Exit fullscreen mode

The concern is not simply that placeholder text exists.

The concern is when placeholder text effectively becomes the only persistent labeling mechanism.

Once the user begins typing:

"First Name" -> disappears
Enter fullscreen mode Exit fullscreen mode

A stronger pattern generally separates the visible label from optional guidance:

<label for="first-name">First name</label>

<input
  id="first-name"
  name="first_name"
  type="text"
  autocomplete="given-name"
>
Enter fullscreen mode Exit fullscreen mode

But even that does not finish the review.

You may still need to verify:

  • required-state communication
  • validation
  • error identification
  • error association
  • focus behavior
  • instructions
  • status messages
  • keyboard submission

Again, accessibility is behavioral.

Third-party widgets create an ownership problem

One of the most useful lessons from this audit came from embedded third-party property functionality.

Suppose the website architecture looks like:

Main website
|
+-- Header
+-- Content
+-- Lead form
|
+-- iframe
    |
    +-- Third-party property application
        |
        +-- Search
        +-- Filters
        +-- Cards
        +-- Dialogs
Enter fullscreen mode Exit fullscreen mode

An accessibility review might detect a problem inside the iframe.

But who owns the fix?

That matters operationally.

The website team may control:

iframe title
surrounding instructions
embed configuration
fallback links
alternative access path
Enter fullscreen mode Exit fullscreen mode

The vendor may control:

internal button names
keyboard behavior
dialog focus
ARIA relationships
internal heading structure
widget rendering
Enter fullscreen mode Exit fullscreen mode

A remediation report that ignores this boundary can create impossible tickets.

For example:

Developer ticket:
Fix keyboard behavior inside vendor iframe.
Enter fullscreen mode Exit fullscreen mode

The developer may have no access to that code.

A better finding identifies remediation ownership:

Issue owner: Third-party vendor

Site-controlled mitigation:
- Review embed configuration
- Improve surrounding context
- Provide alternative path if appropriate

Vendor action:
- Correct keyboard interaction
- Correct accessible names
- Review focus management
Enter fullscreen mode Exit fullscreen mode

That distinction dramatically improves remediation planning.

Shared components should affect prioritization

Severity alone is not enough for remediation planning.

Imagine these two issues:

Issue A
Medium severity
Appears once

Issue B
Medium severity
Exists inside global navigation
Appears on 80 pages
Enter fullscreen mode Exit fullscreen mode

Both may have the same severity label.

They do not have the same remediation leverage.

A useful prioritization model therefore considers at least:

user impact
x journey importance
x component reuse
x frequency
x remediation effort
Enter fullscreen mode Exit fullscreen mode

You do not necessarily need a mathematical score.

But those dimensions should influence planning.

In our review, findings naturally grouped into workstreams such as:

Critical user journeys
        |
        +-- navigation
        +-- forms
        +-- primary interactions

Shared components
        |
        +-- header
        +-- footer
        +-- cards
        +-- reusable buttons

Third-party dependencies
        |
        +-- embeds
        +-- property tools
        +-- vendor widgets

Structural / visual issues
        |
        +-- headings
        +-- contrast
        +-- alternative text
        +-- responsive behavior
Enter fullscreen mode Exit fullscreen mode

This is much easier for an engineering team to consume than 29 unrelated tickets.

Accessibility remediation should behave like a verification loop

Another mistake is considering a ticket finished as soon as the code changes.

Accessibility remediation should work more like:

Observe
   |
   v
Reproduce
   |
   v
Fix
   |
   v
Deploy
   |
   v
Retest
   |
   +------ Fail ------> Fix again
   |
   v
Verified
Enter fullscreen mode Exit fullscreen mode

Why?

Because accessibility fixes can introduce regressions.

For example:

Add ARIA label
        |
        +--> accessible name improves
        |
        +--> but duplicate naming appears elsewhere
Enter fullscreen mode Exit fullscreen mode

or:

Modify focus management
        |
        +--> modal opens correctly
        |
        +--> but focus no longer returns to trigger
Enter fullscreen mode Exit fullscreen mode

or:

Increase text size / layout flexibility
        |
        +--> improves readability
        |
        +--> causes another control to become clipped
Enter fullscreen mode Exit fullscreen mode

A fix is a hypothesis until it has been tested.

What the 7-page audit produced

After candidate discovery, manual review, normalization, and verification, the final review contained 29 verified findings across 7 representative pages.

The useful output was not simply:

29 accessibility problems
Enter fullscreen mode Exit fullscreen mode

It was a structured set of observations with context around:

  • affected pages
  • components
  • keyboard behavior
  • focus behavior
  • accessible names
  • forms
  • page structure
  • image alternatives
  • contrast
  • responsive behavior
  • third-party functionality
  • evidence
  • remediation direction
  • ownership
  • retesting

That creates something an engineering team can actually work from.

The architecture I would recommend for an accessibility audit system

If I were designing the technical system from scratch, I would separate it into six layers.

Layer 1: Collection

Capture:

URLs
DOM state
scanner output
screenshots
viewport data
interaction observations
component context
Enter fullscreen mode Exit fullscreen mode

Layer 2: Candidate normalization

Deduplicate tool output and map similar detections into common categories.

axe candidate
WAVE candidate
manual observation
custom rule
        |
        v
normalized candidate
Enter fullscreen mode Exit fullscreen mode

Layer 3: Human verification

Every candidate becomes one of:

verified
dismissed
needs more review
not applicable
Enter fullscreen mode Exit fullscreen mode

Layer 4: Evidence

Associate the verified observation with enough information to reproduce it.

finding_id
page
component
steps
screenshot
selector/context
notes
Enter fullscreen mode Exit fullscreen mode

Layer 5: Remediation planning

Add:

severity
ownership
recommended direction
shared component impact
priority
Enter fullscreen mode Exit fullscreen mode

Layer 6: Retesting

The same finding ID should survive remediation.

A11Y-017

Initial:
verified

After remediation:
retest_pending

Retest:
passed
Enter fullscreen mode Exit fullscreen mode

That gives you a real lifecycle instead of a one-time PDF.

The bigger engineering lesson

Accessibility testing is often discussed as a tooling problem.

I think that framing is incomplete.

The harder problem is evidence management and verification.

Tools can produce thousands of observations.

The valuable system is the one that can reliably answer:

What was detected?

What was actually verified?

What evidence supports it?

Where does it occur?

Who controls the remediation?

What should change?

Was the change retested?
Enter fullscreen mode Exit fullscreen mode

That is a much more interesting engineering problem than simply running another scanner.

And it is also where automated accessibility testing and human accessibility review complement each other rather than compete.

Automation gives us scale.

Human verification gives us context.

Evidence gives us traceability.

Remediation ownership gives us an execution path.

Retesting closes the loop.

For accessibility work that needs to survive real engineering handoffs, all five matter.


This article is adapted from a real-world accessibility review covering 7 representative pages and 29 verified findings.

Original case study:

https://www.auditzo.com/case-study/real-estate-website-accessibility-evidence-review

Disclosure: This article was prepared with AI writing assistance and reviewed and edited by Shivam Sharma based on the actual audit workflow and underlying case study.

Top comments (0)