<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Romain</title>
    <description>The latest articles on DEV Community by Romain (@lawebe).</description>
    <link>https://dev.to/lawebe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3940661%2F59263845-5148-44e0-8c86-31d1fda90fc7.png</url>
      <title>DEV Community: Romain</title>
      <link>https://dev.to/lawebe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lawebe"/>
    <language>en</language>
    <item>
      <title>How Often Should You Run Accessibility Scans?</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Mon, 08 Jun 2026 17:01:47 +0000</pubDate>
      <link>https://dev.to/lawebe/how-often-should-you-run-accessibility-scans-2cnn</link>
      <guid>https://dev.to/lawebe/how-often-should-you-run-accessibility-scans-2cnn</guid>
      <description>&lt;p&gt;&lt;strong&gt;It is the second question every merchant asks after the first scan comes back: &lt;em&gt;how often should I be doing this?&lt;/em&gt; Most tools answer with a pricing tier — weekly on the cheap plan, daily on the expensive one — as if accessibility decays on a schedule. It does not. A WCAG violation does not appear because a week went by. It appears because **something on the page changed&lt;/strong&gt;: a deploy, a theme edit, a new product image, a third-party script update. The right scan cadence tracks your rate of change, not the calendar. This guide shows how to pick a frequency per site, why hourly is usually wasted, and why the cadence that actually catches regressions is the one tied to your deploys.**&lt;/p&gt;

&lt;p&gt;Pick the row that matches how often the site changes. Then add a scan on every deploy — that is where regressions are actually born.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question is per-site, not per-account
&lt;/h2&gt;

&lt;p&gt;The first mistake is treating scan cadence as one global setting. A merchant typically runs more than one property: a marketing homepage that changes quarterly, a Shopify storefront that gets edited weekly, and maybe a help centre that almost never moves. Forcing all three onto the same schedule either over-scans the static ones (wasted runs, noisy history) or under-scans the active one (regressions sit undetected for days).&lt;/p&gt;

&lt;p&gt;Cadence is a property of the &lt;em&gt;site&lt;/em&gt;, not the account. The site that ships a new theme version every Tuesday needs a different rhythm than the one-page landing that has not changed since launch. Good monitoring lets you set the frequency independently on each tracked site, with your plan defining the fastest cadence available rather than dictating a single rate for everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tie cadence to change, not to a calendar
&lt;/h2&gt;

&lt;p&gt;A scan is a measurement. Measuring the same unchanged page every hour produces the same report every hour — that is not monitoring, it is a loop. The value of a scan comes from the &lt;strong&gt;delta&lt;/strong&gt;: what is different since the last clean run. So the useful cadence is whatever frequency keeps the delta small enough to act on without drowning you in identical reports.&lt;/p&gt;

&lt;p&gt;Concretely, accessibility regressions enter a site through a handful of events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deploys.&lt;/strong&gt; A developer ships a new component, a refactor changes the DOM, a dependency bump alters rendered markup. This is the single largest source of new violations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme and template edits.&lt;/strong&gt; On Shopify and similar platforms, a non-technical edit in the theme editor can break heading order, remove a label, or drop contrast below the threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content and catalogue changes.&lt;/strong&gt; A new product with a missing alt text, a banner image with text baked in, a promo block pasted from a supplier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party scripts.&lt;/strong&gt; A chat widget update, an A/B testing tool, an embedded video player — code you did not write, mutating your page at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice what is &lt;em&gt;not&lt;/em&gt; on that list: the passage of time. Nothing about Tuesday becoming Wednesday introduces a contrast failure. This is why mapping cadence to your change rate — rather than picking the biggest number your plan allows — is the whole game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended cadences by site type
&lt;/h2&gt;

&lt;p&gt;Use this as a starting point, then adjust based on what your scan history shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static brochure or landing page&lt;/strong&gt; — changes a few times a year. &lt;strong&gt;Monthly&lt;/strong&gt; is plenty. The monthly run mostly proves nothing regressed, which is exactly the dated evidence you want for compliance anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active e-commerce store&lt;/strong&gt; — weekly content and catalogue edits, occasional theme tweaks. &lt;strong&gt;Weekly&lt;/strong&gt; keeps the delta small enough that any new violation is traceable to that week's changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-velocity site&lt;/strong&gt; — frequent deploys, seasonal promos, multiple editors. &lt;strong&gt;Daily&lt;/strong&gt;. At this pace a week is too long; a daily baseline narrows any regression to a single day of changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anything with continuous deployment&lt;/strong&gt; — see the next section. The calendar cadence becomes a backstop; the deploy trigger does the real work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why hourly is usually overkill
&lt;/h2&gt;

&lt;p&gt;Hourly scanning sounds thorough, and there are narrow cases for it — a high-traffic site during a launch window, or a page assembled from rapidly-changing third-party feeds. But for the overwhelming majority of e-commerce sites, hourly scanning measures the same unchanged page 24 times a day. WCAG conformance is not a metric that drifts hour to hour like CPU load; it steps when the markup steps. An hourly cadence on a site that deploys twice a week generates 333 identical reports for every one that actually shows a change.&lt;/p&gt;

&lt;p&gt;That noise has a cost. A scan history full of identical runs makes it harder to spot the run that matters. The signal — the report where something broke — is buried under hundreds of green duplicates. We deliberately do not push hourly as the default recommendation, even though the top plan supports it, because for a normal store it trades a real benefit (a clean, readable history) for a theoretical one (catching a regression an hour sooner that a deploy-triggered scan would have caught instantly anyway).&lt;/p&gt;

&lt;h2&gt;
  
  
  Scan-on-deploy: the cadence that actually matters
&lt;/h2&gt;

&lt;p&gt;If a scan should run when the site changes, and a deploy is the biggest source of change, then the highest-value trigger is obvious: &lt;strong&gt;scan on every deploy&lt;/strong&gt;. Instead of hoping your daily timer happens to fire after a risky deploy, you wire the scan into the moment the change ships.&lt;/p&gt;

&lt;p&gt;For teams with a CI pipeline, this is a single step: after the deploy job succeeds, hit the scan endpoint (or run an &lt;a href="https://dev.to/blog/accessibility-testing-playwright-cypress"&gt;axe-core pass in CI directly&lt;/a&gt;) against the URLs that changed. The scan becomes part of the release, the same way a smoke test is. A regression is caught in the same pipeline run that introduced it — before a customer, a regulator, or a plaintiff firm ever sees it.&lt;/p&gt;

&lt;p&gt;For merchants without a CI pipeline — most Shopify stores — the equivalent is a tight calendar cadence (daily or weekly) plus a manual scan after any theme publish or large catalogue update. The discipline is the same: scan when the site changes, not just when the clock ticks.&lt;/p&gt;

&lt;p&gt;Scan-on-deploy also fixes the noise problem from the previous section. You no longer need an aggressive timer to feel safe, because the timer was never what caught regressions — the change trigger was. A weekly backstop scan plus a scan on every deploy beats an hourly timer on both coverage and signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the delta tells you
&lt;/h2&gt;

&lt;p&gt;Once cadence tracks change, your scan history becomes a changelog of your site's accessibility. Each run is a diff against the last: violations resolved, violations introduced, score moved. That history is more useful than any single report, because it answers the question that matters in a remediation programme — &lt;em&gt;are we getting better or worse, and which change caused which?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is also where the &lt;a href="https://dev.to/blog/website-accessibility-audit-guide"&gt;audit workflow&lt;/a&gt; and continuous monitoring meet. A one-shot audit gives you a baseline. Cadenced scanning turns that baseline into a trend line. When a violation reappears, the timestamp tells you which deploy or edit reintroduced it, which is half the work of fixing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping cadence to your plan
&lt;/h2&gt;

&lt;p&gt;Here is how the per-site model works in practice. Your plan sets the &lt;em&gt;fastest&lt;/em&gt; cadence you can choose; you then set each site at or below that ceiling based on its change rate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Starter&lt;/strong&gt; — up to 5 sites, weekly ceiling. Set the active store to weekly, the brochure site to monthly. Good for a single merchant with a couple of properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt; — up to 25 sites, daily ceiling. Set high-velocity sites to daily, steady stores to weekly, static pages to monthly. This is the typical agency or multi-store setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business&lt;/strong&gt; — many sites, hourly ceiling available. Use hourly only on the rare site that genuinely needs it; keep the rest on the cadence their change rate justifies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point of independent per-site cadence is that you are not paying the "scan everything daily" tax on sites that change twice a year. You spend frequency where change happens. &lt;a href="https://dev.to/pricing"&gt;See the plans and ceilings&lt;/a&gt; for the exact limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  The compliance angle: dated evidence
&lt;/h2&gt;

&lt;p&gt;There is a second reason cadence matters, beyond catching regressions: it produces a paper trail. The &lt;a href="https://dev.to/blog/ada-web-accessibility-lawsuit-checklist-2026"&gt;ADA&lt;/a&gt; and the European Accessibility Act both reward contemporaneous evidence — proof that you were actively monitoring and remediating, dated, before any complaint. A site scanned monthly with a clean history of dated reports is in a materially stronger position than one with a single scan from eighteen months ago.&lt;/p&gt;

&lt;p&gt;Even a static site that "never changes" benefits from a monthly scan for this reason alone. The runs are nearly identical, but each one is a dated record that conformance held. That record is the artifact a corporate buyer asks for in a &lt;a href="https://dev.to/blog/how-to-write-vpat-accessibility-conformance-report"&gt;VPAT&lt;/a&gt; request, and the one plaintiff counsel cannot easily dispute.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to set your cadence
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;List your sites and their change rate.&lt;/strong&gt; Be honest: how often does each actually change? Most accounts have one active site and several near-static ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match each site to the table above.&lt;/strong&gt; Static to monthly, active to weekly, high-velocity to daily. Start conservative; you can always tighten it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a deploy trigger where you can.&lt;/strong&gt; If you have CI, wire a scan into the release. If you are on Shopify, scan manually after every theme publish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch the first month of history.&lt;/strong&gt; If every run is identical, you can loosen the cadence. If you see regressions you missed, tighten it — or improve your deploy trigger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the dated reports.&lt;/strong&gt; They are your evidence trail, independent of whether they ever catch a regression.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have not set a baseline yet, start there: &lt;a href="https://dev.to/free-wcag-scan"&gt;run a free WCAG 2.2 scan on any URL&lt;/a&gt; — full violation list, severity breakdown, no signup. Then walk the &lt;a href="https://dev.to/blog/how-to-do-accessibility-audit"&gt;step-by-step audit&lt;/a&gt; on the findings, set a per-site cadence that matches how often the page changes, and let the deploy trigger do the heavy lifting. Cadence is not about scanning more. It is about scanning &lt;em&gt;when it counts&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/how-often-to-run-accessibility-scans?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_crosspost" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>wcag</category>
    </item>
    <item>
      <title>Why Our WCAG Scanner Is Free (And What That Costs Us)</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Thu, 28 May 2026 08:39:28 +0000</pubDate>
      <link>https://dev.to/lawebe/why-our-wcag-scanner-is-free-and-what-that-costs-us-2e7d</link>
      <guid>https://dev.to/lawebe/why-our-wcag-scanner-is-free-and-what-that-costs-us-2e7d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Run a search for "free WCAG scanner" and the pattern repeats. You land on a page that promises a free audit, then asks for your email, your role, your company size, and sometimes your phone number. &lt;em&gt;Then&lt;/em&gt; it shows you violations. We took the other side of that bet. &lt;a href="https://dev.to/free-wcag-scan"&gt;/free-wcag-scan&lt;/a&gt; runs a full axe-core pass on any URL — about 120 rules covering WCAG 2.2 A and AA — and returns the report in roughly 90 seconds. No account, no card, no email gate. Here is the math behind that decision and what it actually costs us per scan.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The gated funnel sells "the report" as a lead magnet. The open funnel sells the platform — and lets the report itself do the qualifying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The math behind a single scan
&lt;/h2&gt;

&lt;p&gt;A real WCAG scan is not a clever algorithm. It is a browser. We boot a containerised Chromium, load the URL, wait for paint and idle, inject &lt;a href="https://dev.to/blog/what-is-axe-core-evidence-based-audits"&gt;axe-core&lt;/a&gt; (the same engine Lighthouse uses), run the 120-rule pass, capture screenshots of every violation, and emit a structured JSON report. The pipeline runs on a small Fly.io worker, around 1.5 GB of RAM, that idles when nobody is scanning.&lt;/p&gt;

&lt;p&gt;The unit economics break down like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chromium time&lt;/strong&gt; — about 8 to 14 seconds of compute per URL, depending on page weight. At Fly.io's &lt;code&gt;shared-cpu-1x:2048MB&lt;/code&gt; rate, that works out to roughly $0.0008 to $0.0014 in raw compute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bandwidth&lt;/strong&gt; — a typical e-commerce homepage is 2 to 5 MB. Outbound is free on Fly within our allowance; inbound from origin is essentially zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt; — screenshots and JSON reports for a free scan are kept 7 days and then purged. Average storage cost per scan: under $0.0001.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fully-loaded number&lt;/strong&gt; — counting amortised infra (DB, Redis, the worker reservation that keeps cold-start under 2 seconds), we land at roughly $0.03 per free scan. Three cents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If 1,000 visitors run a scan in a month, that is $30 of marginal compute. Less than a single Google Ads click in our category.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you actually get
&lt;/h2&gt;

&lt;p&gt;The free scan is not a teaser. It returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A WCAG 2.2 A + AA compliance score&lt;/strong&gt; — the same headline number we display inside the paid product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The full list of violations&lt;/strong&gt; — sorted by severity (Critical, Serious, Moderate, Minor), with the failing selector, the rule ID, the WCAG criterion, and a screenshot of the element.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain-English explanations&lt;/strong&gt; — for each rule, what it means and the typical fix. No "consult our enterprise team to learn more."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issue prioritisation&lt;/strong&gt; — the five issues most likely to appear in a demand letter, called out at the top.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What it does &lt;em&gt;not&lt;/em&gt; include — and this is the honest answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No PDF report.&lt;/strong&gt; Generating a PDF reliably costs us about ten times the scan, in Chromium time, because we render the report with print layout. PDF is a paid-plan feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No history.&lt;/strong&gt; The free scan is one-shot. You get a URL to share for 7 days, then we purge it. Tracked sites with re-scan history are a paid-plan feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No multi-page crawl.&lt;/strong&gt; The free scan runs against the URL you paste. The paid plans crawl the sitemap and audit every page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No screen reader narration check.&lt;/strong&gt; Automated tools, ours included, do not catch what a screen reader user actually hears. About 30% of real accessibility issues need human review — see the &lt;a href="https://dev.to/blog/website-accessibility-audit-guide"&gt;pillar guide&lt;/a&gt; for the full breakdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The bet
&lt;/h2&gt;

&lt;p&gt;Most accessibility SaaS treats the report as a lead magnet. Logical, on paper: the violation list is what the buyer wants, and the email is what the sales team wants. Trade one for the other.&lt;/p&gt;

&lt;p&gt;We think that funnel is broken for our product specifically, for three reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One.&lt;/strong&gt; A merchant who hands over their email under a "free scan" pretext converts on different intent than a merchant who has already read their own violation list. The first wants the scan. The second wants the fix. The economics of a SaaS that sells continuous monitoring favour the second cohort heavily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two.&lt;/strong&gt; Our category is saturated with &lt;a href="https://dev.to/blog/overlay-widgets-vs-real-wcag-scanners"&gt;overlay widgets&lt;/a&gt; that promise compliance and deliver a documented liability. Trust is the bottleneck. If we ask for an email before showing a single rule failure, we are using the same playbook as the overlays. We are not the overlays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three.&lt;/strong&gt; The cost of a scan is below the cost of a single ad click. The math only works against us if we measure success by leads captured. Measured by qualified pipeline — merchants who arrive having seen their own report and ready to talk about the fix — it works the other way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens after the scan
&lt;/h2&gt;

&lt;p&gt;Nothing happens automatically. We do not capture an email, so there is no drip sequence. We do not have your phone number, so nobody calls. The shareable URL expires in 7 days. The Chromium worker forgets you existed.&lt;/p&gt;

&lt;p&gt;If you want the rest — PDF, history, multi-page crawl, tracked sites — you self-select into the &lt;a href="https://dev.to/pricing"&gt;paid plans&lt;/a&gt;. Starter at $29/month covers 5 sites with weekly scans. Pro at $99 covers 25 sites daily. The first scan stays free because it was always supposed to be free.&lt;/p&gt;

&lt;h2&gt;
  
  
  The regulatory backdrop
&lt;/h2&gt;

&lt;p&gt;The European Accessibility Act came into force on 28 June 2025. EU member states are now actively enforcing it for consumer-facing digital services, with the bulk of e-commerce sites in scope. The US side is older — Title III of the ADA has been interpreted to cover websites since at least 2017 — and the cadence of &lt;a href="https://dev.to/blog/ada-demand-letters-what-to-do"&gt;ADA demand letters&lt;/a&gt; targeting websites grew roughly 14% year-over-year through 2024 and accelerated again in Q1 2026.&lt;/p&gt;

&lt;p&gt;Two regimes, one reality: if your e-commerce isn't audited, you're working on borrowed time. The deadline isn't "later this year." It's whichever comes first — the regulator inspection, the plaintiff firm crawler, or the corporate buyer asking for your &lt;a href="https://dev.to/blog/how-to-write-vpat-accessibility-conformance-report"&gt;VPAT&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A scan that costs us three cents and gives a merchant a baseline they can act on is, in that context, the cheapest pre-emptive action available.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run it on your homepage first.&lt;/strong&gt; Most demand letters cite the homepage and the checkout flow. The homepage is the easiest to fix and the highest-visibility win.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run it on a competitor's homepage too.&lt;/strong&gt; Useful to know whether your category is well-audited or whether you are entering a space where compliance is broadly poor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skim the Critical and Serious findings.&lt;/strong&gt; Those are what plaintiff firms screenshot. If you have fewer than five, you are ahead of the median.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Walk the &lt;a href="https://dev.to/blog/how-to-do-accessibility-audit"&gt;7-step manual audit workflow&lt;/a&gt; on the items the scan flags.&lt;/strong&gt; Automated catches the patterns. The 7-step walk catches the rest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide whether you want this continuously.&lt;/strong&gt; A one-shot scan is a baseline. Conformance is a rhythm. The paid plans exist for the rhythm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the whole pitch. &lt;a href="https://dev.to/free-wcag-scan"&gt;/free-wcag-scan&lt;/a&gt;. No email, no card, no overlay. Three cents on our side, a real baseline on yours.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/why-our-wcag-scanner-is-free" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Website Accessibility Audit: The Complete Guide (WCAG 2.2)</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Wed, 27 May 2026 09:39:22 +0000</pubDate>
      <link>https://dev.to/lawebe/website-accessibility-audit-the-complete-guide-wcag-22-3p7k</link>
      <guid>https://dev.to/lawebe/website-accessibility-audit-the-complete-guide-wcag-22-3p7k</guid>
      <description>&lt;p&gt;&lt;strong&gt;A **website accessibility audit&lt;/strong&gt; is a structured review of a website against the Web Content Accessibility Guidelines (WCAG) — the technical standard cited by the ADA (United States), the EAA (European Union, June 2025), and Section 508 (US federal). Done properly, an audit produces two things you can actually use: a prioritized list of issues to fix, and dated evidence that you are conforming on an ongoing basis. This guide explains what an audit covers, who needs one, what tools and methods exist, and what the deliverable should look like.**&lt;/p&gt;

&lt;h2&gt;
  
  
  What an audit actually checks
&lt;/h2&gt;

&lt;p&gt;WCAG 2.2 has 86 success criteria across four principles: Perceivable, Operable, Understandable, Robust. An audit checks each criterion that applies to your pages, at the conformance level you target (A, AA, or AAA). Most legal contexts target &lt;strong&gt;WCAG 2.2 Level AA&lt;/strong&gt; — that is what the ADA case law and EAA technical specifications converge on.&lt;/p&gt;

&lt;p&gt;For each criterion, the audit answers three questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Does this criterion apply?&lt;/strong&gt; (e.g., 1.2.2 Captions only applies if you have pre-recorded video)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Are you passing?&lt;/strong&gt; If yes, document the evidence (which page, which element, which check).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If failing, what is the severity?&lt;/strong&gt; Critical / Serious / Moderate / Minor — driven by user impact and legal exposure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who needs an audit
&lt;/h2&gt;

&lt;p&gt;Three groups commonly trigger an audit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sites that received an ADA demand letter or a settlement notice.&lt;/strong&gt; The audit is the first artefact your counsel will ask for. See &lt;a href="https://dev.to/blog/ada-demand-letters-what-to-do"&gt;our 72-hour ADA demand-letter playbook&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EU-facing businesses preparing for the European Accessibility Act&lt;/strong&gt; (enforcement started June 28, 2025). Even non-EU companies trading into the EU above defined thresholds are in scope. See &lt;a href="https://dev.to/eaa-2025-requirements"&gt;EAA 2025 requirements&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SaaS and ecommerce teams responding to procurement&lt;/strong&gt;. Enterprise buyers, government, education, and healthcare procurement increasingly attach a VPAT request (or its EU equivalent, a Conformance Report) to their RFP. See &lt;a href="https://dev.to/blog/how-to-write-vpat-accessibility-conformance-report"&gt;how to produce a VPAT&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automated vs manual vs user testing
&lt;/h2&gt;

&lt;p&gt;Industry consensus is that &lt;strong&gt;automated tools catch 30 to 50 percent&lt;/strong&gt; of WCAG failures. The exact figure depends on the site — heavy on forms and dynamic widgets, automated coverage drops; mostly static text content, automated coverage peaks. The remaining 50 to 70 percent requires manual checks: keyboard-only navigation, screen reader walk-throughs, 400% zoom layout, focus management on modals and drawers, cognitive load on error states and form recovery. The last 5 to 10 percent — checks like "is the workflow understandable to a screen reader user under time pressure" — only emerges from user testing with people who actually rely on assistive technology.&lt;/p&gt;

&lt;p&gt;A reasonable audit balances all three layers. &lt;strong&gt;Automated runs continuously&lt;/strong&gt; (CI on every deploy, plus a scheduled scan), &lt;strong&gt;manual is done quarterly or per major release&lt;/strong&gt;, &lt;strong&gt;user testing is done annually or for new flagship features&lt;/strong&gt;. The &lt;a href="https://dev.to/blog/how-to-do-accessibility-audit"&gt;step-by-step workflow we use&lt;/a&gt; covers the manual layer in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools we actually use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated&lt;/strong&gt; — &lt;a href="https://dev.to/blog/what-is-axe-core-evidence-based-audits"&gt;axe-core&lt;/a&gt; via AccessProof (continuous), Lighthouse, WAVE for spot checks. axe-core has the lowest false-positive rate of the open-source engines. See &lt;a href="https://dev.to/blog/axe-core-vs-lighthouse-accessibility"&gt;axe-core vs Lighthouse&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard&lt;/strong&gt; — Tab, Shift+Tab, Enter, Space, Esc, arrow keys. Every interactive element must be reachable and operable. No keyboard traps. Focus indicators visible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen reader&lt;/strong&gt; — NVDA (Windows, free), VoiceOver (macOS / iOS, built-in), JAWS (Windows, dominant in enterprise) on at least Chrome and Safari. &lt;a href="https://dev.to/blog/screen-reader-testing-basics"&gt;Basics here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color contrast&lt;/strong&gt; — automated for normal text and UI, manual review of brand colors and adjacent surfaces. &lt;a href="https://dev.to/tools/color-contrast-checker"&gt;Free contrast checker&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zoom &amp;amp; reflow&lt;/strong&gt; — 400% zoom in a 1280-wide viewport. Content must reflow to one column, no horizontal scrolling except for data tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the deliverable should look like
&lt;/h2&gt;

&lt;p&gt;A defensible audit report contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date and scope&lt;/strong&gt; — which URLs were audited, which standard and conformance level was targeted, when (timestamps matter — they bound the plaintiff's claims).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methodology&lt;/strong&gt; — automated tools used (with version), manual checks performed, assistive technology versions tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-criterion finding&lt;/strong&gt; — pass / fail / not applicable, with evidence for each failure (selector, screenshot, expected behavior).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Severity-ranked remediation list&lt;/strong&gt; — Critical and Serious first, with effort estimate and owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-test plan&lt;/strong&gt; — when the next audit happens, what the cadence is. Continuous improvement is what most plaintiff firms settle around.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How often to audit
&lt;/h2&gt;

&lt;p&gt;Three rhythms run in parallel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Continuous (automated)&lt;/strong&gt; — every deploy. Catches regressions before they ship. AccessProof Starter covers 5 sites weekly; Pro covers 25 sites daily; Business covers unlimited hourly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quarterly (manual + automated)&lt;/strong&gt; — a human walks the critical flows on top of the continuous scans.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Annually (full audit + user testing)&lt;/strong&gt; — comprehensive, all pages, all flows, with assistive technology users where budget allows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost and effort
&lt;/h2&gt;

&lt;p&gt;An automated baseline scan is essentially free (we run them under a minute on our infrastructure for $0 on the Free plan). A manual quarterly review by an internal team typically takes 8 to 24 hours per site depending on complexity. A full external audit by a specialist agency runs $5k to $25k per site, more for SPAs and dashboards. The math almost always favours running automated continuously and reserving manual / specialist time for the criteria automation cannot cover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auditing once and shipping it.&lt;/strong&gt; An audit dated more than 90 days ago is stale evidence — the site has likely changed underneath it. Continuous beats one-shot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring focus management.&lt;/strong&gt; Modals, drawers, and dynamic content are where most lawsuits originate. Automated tools rarely catch focus-trap failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color contrast on hover and disabled states.&lt;/strong&gt; The default state passes, the interactive states fail. Audit every state, not just resting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forms without programmatically associated labels.&lt;/strong&gt; Placeholder text is not a label. We see this on roughly 40% of new audits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relying on an overlay widget.&lt;/strong&gt; &lt;a href="https://dev.to/blog/overlay-widgets-vs-real-wcag-scanners"&gt;Why overlays are a documented liability&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to start
&lt;/h2&gt;

&lt;p&gt;If you have not run any kind of accessibility check on your site, start with the smallest commitment that produces dated evidence: &lt;a href="https://dev.to/free-wcag-scan"&gt;run a free WCAG 2.2 scan on any URL&lt;/a&gt;. You get a compliance score, the four-tier severity breakdown, and the top five issues — no signup, no overlay, no marketing loop. Use that as the baseline against which to plan the rest of the audit work. For continuous monitoring across multiple sites, the &lt;a href="https://dev.to/pricing"&gt;Starter plan ($29/mo)&lt;/a&gt; covers 5 sites with weekly scans and PDF reports; Pro and Business escalate to daily and hourly cadence.&lt;/p&gt;

&lt;p&gt;Once you have a baseline, walk the &lt;a href="https://dev.to/blog/how-to-do-accessibility-audit"&gt;7-step manual workflow&lt;/a&gt; on your three most critical flows: signup, checkout (or primary conversion), and the dashboard or member area. Those three flows are what plaintiff firms screenshot in demand letters. Fix the Critical and Serious findings first. Document each fix with a date, a commit, and the next re-scan result that confirms it. That documented sequence — issue identified, fix shipped, re-scan green — is the contemporaneous evidence the ADA and EAA processes expect.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/website-accessibility-audit-guide" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>wcag</category>
    </item>
    <item>
      <title>We Leaked 1,368 Customers into Our LIVE Stripe Account via E2E Tests</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 26 May 2026 14:08:49 +0000</pubDate>
      <link>https://dev.to/lawebe/we-leaked-1368-customers-into-our-live-stripe-account-via-e2e-tests-58kk</link>
      <guid>https://dev.to/lawebe/we-leaked-1368-customers-into-our-live-stripe-account-via-e2e-tests-58kk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Six weeks ago we wired up signup-to-paid-plan E2E tests against our staging stack. Last week we found 1,368 fake customers in our &lt;em&gt;production&lt;/em&gt; Stripe account. No charges. No invoices. No alert ever fired. Here is what went wrong, the boring fix, and a checklist to see whether the same pattern is silently filling your own Stripe.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The pattern fires silently. Stripe charges nothing for Customer objects, so the usual monitoring catches none of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup that looked fine
&lt;/h2&gt;

&lt;p&gt;Our signup flow does what every SaaS signup flow does. POST email and password → create a row in &lt;code&gt;users&lt;/code&gt; → call &lt;code&gt;stripe.Customer.create&lt;/code&gt; with the email → store the returned &lt;code&gt;cus_xxx&lt;/code&gt; on the user row → send a welcome email. Nothing exotic.&lt;/p&gt;

&lt;p&gt;Our E2E suite, run on every commit to master, signs up a fresh user, walks the onboarding, hits the dashboard, signs out. Around 30 signups per CI run. Test emails follow a pattern: &lt;code&gt;{slug}+e2e@access-proof.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two assumptions, both wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We assumed the CI environment was configured with the Stripe &lt;strong&gt;TEST&lt;/strong&gt; secret key. It was not. Someone had set it to LIVE during a debugging session a couple of months back. The CI variable was never reverted.&lt;/li&gt;
&lt;li&gt;We assumed Stripe would somehow flag the obviously-fake emails. It does not. Creating a Customer object is rate-limited but otherwise free. There is no fraud signal, no review queue, no email-bounce side effect, no soft alert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Six weeks of pushes × ~30 signups × CI = ~1,400 fake customers. Almost all of them disposable email addresses ending in &lt;code&gt;+e2e@access-proof.com&lt;/code&gt;, but a handful with other test patterns we use in scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we found it
&lt;/h2&gt;

&lt;p&gt;By accident, looking at the "Customers" page of the Stripe dashboard during a debugging session for something else. The total count surprised us — we have maybe 80 real signups so far. Sorting by recency showed a torrent of &lt;code&gt;+e2e@&lt;/code&gt; addresses.&lt;/p&gt;

&lt;p&gt;What didn't catch it: no monitoring, no Stripe webhook (we listen for invoices and subscriptions, not raw Customer creates), no email alert (Stripe doesn't send any), no quota issue (we are nowhere near Stripe's account-level limits).&lt;/p&gt;

&lt;p&gt;The lesson is uncomfortable. Compliance debt — and this is a flavour of GDPR-relevant data hygiene — does not always announce itself. It accumulates quietly in places nobody has a reason to look.&lt;/p&gt;

&lt;h2&gt;
  
  
  The boring fix
&lt;/h2&gt;

&lt;p&gt;Two changes. First, the email-pattern skip at the boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# app/services/billing.py

TEST_EMAIL_PATTERNS = (
    re.compile(r".+\+e2e@access-proof\.com$"),
    re.compile(r".+\+test@.+$"),
    re.compile(r".+@mailosaur\.io$"),
)

def is_test_email(email: str) -&amp;gt; bool:
    return any(p.match(email) for p in TEST_EMAIL_PATTERNS)

async def create_stripe_customer_if_real(user: User) -&amp;gt; str | None:
    if is_test_email(user.email):
        logger.info("stripe.customer.skip", email=user.email)
        return None
    customer = await stripe.Customer.create_async(email=user.email)
    return customer.id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, the boot-time guard so the same drift cannot happen again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# app/main.py

if settings.STRIPE_SECRET_KEY.startswith("sk_live_") and os.getenv("CI") == "true":
    raise RuntimeError(
        "Refusing to boot: LIVE Stripe key detected in CI environment. "
        "Set STRIPE_SECRET_KEY to a TEST key (sk_test_...) for CI."
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the fix that pays back. The first change makes the bug impossible at the application level. The second makes the misconfiguration loud at startup, so it surfaces during the next pipeline run, not six weeks later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The purge
&lt;/h2&gt;

&lt;p&gt;Cleaning up the 1,368 ghosts was a one-shot script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scripts/purge_stripe_test_customers.py

import stripe, time

stripe.api_key = os.environ["STRIPE_LIVE_KEY"]
DELETED = []

for c in stripe.Customer.list(limit=100).auto_paging_iter():
    if is_test_email(c.email or ""):
        stripe.Customer.delete(c.id)
        DELETED.append({"id": c.id, "email": c.email})
        time.sleep(0.1)  # respect rate limit

print(f"Deleted {len(DELETED)} test customers")
# write CSV audit trail
with open(f"deleted-{date.today()}.csv", "w") as f:
    csv.DictWriter(f, ["id", "email"]).writerows(DELETED)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;About 12 minutes of script time. A CSV with the 1,368 IDs and emails went into our audit folder. Stripe's rate limit on the Customer endpoint is about 100 requests per second; our 10-per-second pace is conservative and avoids any 429s.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else might be leaking silently
&lt;/h2&gt;

&lt;p&gt;Once you start looking, the pattern repeats. Things that get created in tests but never trigger a charge, an invoice, or an alert:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mailgun / SendGrid contacts&lt;/strong&gt; — every welcome email adds a contact unless you skip on test addresses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixpanel / Segment / Amplitude identify calls&lt;/strong&gt; — every test signup becomes a real user in your analytics, polluting funnel data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algolia / Meilisearch indexes&lt;/strong&gt; — if you index users for admin search, your index fills with fake rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CRMs (HubSpot, Pipedrive)&lt;/strong&gt; — every signup creates a contact. Sales calls a real-looking lead address that bounces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 / R2 buckets&lt;/strong&gt; — if test signups create folders or default assets, you grow object storage forever.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each one, the fix is the same: pick a stable test-email pattern, skip the call at the boundary, add a boot-time guard against mode drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit trail matters more than the deletion
&lt;/h2&gt;

&lt;p&gt;If you discover a leak like this and there is any chance the data flowed to a third party, keep a dated record. GDPR Article 5 (data minimisation) and Article 32 (security) are about being able to show what you did. A CSV of the 1,368 IDs you purged, dated and committed somewhere durable, is better than a cleaner slate with no record.&lt;/p&gt;

&lt;p&gt;We also added the leak to our internal &lt;code&gt;PITFALLS.md&lt;/code&gt; — the running register of mistakes we never want to repeat. If you do not keep one already, the entry takes one line: date, what happened, root cause, the boring fix that prevents the recurrence.&lt;/p&gt;

&lt;h2&gt;
  
  
  One last check
&lt;/h2&gt;

&lt;p&gt;Go open your Stripe dashboard. Sort customers by recency. Skim the last 100. If you see emails with &lt;code&gt;+test&lt;/code&gt;, &lt;code&gt;+e2e&lt;/code&gt;, &lt;code&gt;@example.com&lt;/code&gt;, &lt;code&gt;@mailosaur&lt;/code&gt;, or your CI-tagged patterns — you are doing the same thing we were. Apply the four-step fix above. The whole job is under an hour.&lt;/p&gt;

&lt;p&gt;For everything else that runs silently in the background of a SaaS — accessibility regressions, RGPD lapses, broken email deliverability — the &lt;a href="https://dev.to/free-wcag-scan"&gt;free WCAG scan&lt;/a&gt; we run is the same flavour of low-effort, dated audit. It will not catch a Stripe leak. But it will catch the accessibility issues your tests are not even trying to find.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/stripe-customer-leaks-e2e-tests" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Overlay Widgets vs Real WCAG Scanners: A 2026 Buyer’s Guide</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 26 May 2026 14:08:18 +0000</pubDate>
      <link>https://dev.to/lawebe/overlay-widgets-vs-real-wcag-scanners-a-2026-buyeraposs-guide-1mha</link>
      <guid>https://dev.to/lawebe/overlay-widgets-vs-real-wcag-scanners-a-2026-buyeraposs-guide-1mha</guid>
      <description>&lt;p&gt;&lt;strong&gt;Two categories of tool dominate the accessibility software market. Overlay widgets — accessiBe, UserWay, AudioEye — inject WAI-ARIA attributes at runtime and promise instant ADA compliance for a flat monthly fee, typically **$490 to $1,490 per site per year&lt;/strong&gt;. Real scanners — Pope Tech, Silktide, Monsido, axe-core, AccessProof — audit your actual rendered DOM and report issues you then have to fix. Real scanners cost &lt;strong&gt;~10x less&lt;/strong&gt; and ship the work back to your codebase, where it belongs. This guide is the version of the comparison we wish merchants had before signing one.**&lt;/p&gt;

&lt;p&gt;The architectures differ at the foundation. The pitch differs at the surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What overlays actually do
&lt;/h2&gt;

&lt;p&gt;An overlay is a JavaScript snippet you paste into your site. It loads on every page, scans the DOM at runtime, and adds ARIA attributes (&lt;code&gt;role&lt;/code&gt;, &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;tabindex&lt;/code&gt;, etc.) to elements it detects as missing them. Most overlays also expose a sidebar widget letting the user toggle visual settings — high-contrast, larger fonts, dyslexia-friendly typeface.&lt;/p&gt;

&lt;p&gt;That part — the visual toolbar — is benign. It mimics what the operating system already provides and what every modern browser supports natively. The disabled-user research community has been clear for years that the toolbar duplicates capabilities most users either already have or do not want.&lt;/p&gt;

&lt;p&gt;The other part — automatic ARIA injection — is where the harm is. Overlays cannot infer semantic intent from broken HTML. A `&lt;code&gt;styled as a button gets&lt;/code&gt;role="button"&lt;code&gt;bolted on, but no keyboard handler, no focus state, no proper&lt;/code&gt;aria-pressed` for toggles. A screen reader receives a button that is not really a button. A keyboard user receives a focus target that does nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What real scanners do
&lt;/h2&gt;

&lt;p&gt;A real scanner runs an audit engine — typically &lt;a href="https://dev.to/blog/what-is-axe-core-evidence-based-audits"&gt;axe-core&lt;/a&gt; — against the actual rendered HTML. It enumerates violations by WCAG success criterion, severity (critical / serious / moderate / minor), and DOM node. The output is a list. You read it, you fix the source code, you re-scan.&lt;/p&gt;

&lt;p&gt;Automated scanners catch roughly 30 to 50 percent of real WCAG issues — color contrast, missing alt, broken heading hierarchy, label-input pairs, ARIA misuse, target size. The remaining issues — keyboard traps, screen-reader logic, dynamic content, focus management — require manual review by someone with assistive-technology experience. Honest scanner vendors say this upfront. Overlays vendors claim 95 percent or more, sometimes "full compliance," through automation alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six tools we benchmarked
&lt;/h2&gt;

&lt;p&gt;The market splits cleanly into the two categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overlay vendors
&lt;/h3&gt;

&lt;p&gt;VendorMechanismPricing (small site)Notable&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accessiBeJS overlay + AI-driven ARIA injection~$490–$1,490/yrLargest vendor. Named in the Federal Trade Commission settlement (2024) over deceptive accessibility claims.&lt;br&gt;
UserWayJS overlay + user toolbar~$490–$890/yrOwned by Audioeye since 2023. Same overlay-injection approach.&lt;br&gt;
AudioEyeJS overlay + claimed human audit overlay~$590–$1,490/yrPositions as "automation + human review." The human review is shallow on the smaller tiers.&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Real scanners&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;VendorMechanismPricing (small site)Notable&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pope TechWAVE engine (real DOM audit)~$59–$199/yr (small)Built by WebAIM partner. Honest scope: catches what automated rules catch.&lt;br&gt;
SilktideProprietary scanner + page-level audits~$199–$990/yrStronger CMS-style reporting. Designed for content teams.&lt;br&gt;
MonsidoSite-wide scan + accessibility + SEO + QA~$3,000+/yrEnterprise-skewed. Bundle of compliance scanners.&lt;br&gt;
&lt;strong&gt;AccessProof&lt;/strong&gt; (us)axe-core engine + monitoring + reports$0–$49/moFree no-signup scan, monitoring, dated reports for defense file.&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  What the courts have said&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;The legal picture has shifted decisively against overlays in the United States.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FTC enforcement (January 2024)&lt;/strong&gt; — the Federal Trade Commission concluded that accessiBe's claims of automatic ADA and WCAG compliance were deceptive. The company settled for $1 million and was prohibited from making similar claims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active litigation&lt;/strong&gt; — overlay-installed sites continue to be sued under ADA Title III. Courts have consistently rejected the argument that an overlay is a defense; the underlying HTML is what determines accessibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The disabled community position&lt;/strong&gt; — over 800 accessibility specialists have signed the &lt;a href="https://overlayfactsheet.com" rel="noopener noreferrer"&gt;Overlay Fact Sheet&lt;/a&gt; recommending against overlay use. Many screen-reader users actively block overlays.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An overlay does not protect you from an ADA lawsuit. If anything, it can complicate the defense: a plaintiff can argue the merchant knew about accessibility but chose a tool that does not actually fix the underlying issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision framework — how to pick
&lt;/h2&gt;

&lt;p&gt;Three questions, answered honestly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Are you optimising for the appearance of compliance, or for the experience of disabled users?&lt;/strong&gt; The first is short-term — until the next demand letter. The second is the only thing that holds up in front of a screen-reader user, a regulator, or a judge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can your team or vendor fix the source HTML?&lt;/strong&gt; If yes, you want a scanner. If absolutely not (legacy CMS you cannot touch, third-party platform with no edit access), the conversation is about platform migration, not overlay rescue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do you need defense evidence?&lt;/strong&gt; Dated reports of audits performed and remediation history are a real defense in an ADA case. A scanner produces them; an overlay does not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you would rather see what your site actually scores before deciding, our &lt;a href="https://dev.to/free-wcag-scan"&gt;free WCAG scan&lt;/a&gt; runs the axe-core engine on any public URL, no signup, in under a minute. The same engine powers our paid plans. If the free scan returns 8 critical violations, an overlay does not make them go away — it papers over them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The market has been mature enough for long enough that the comparison should not feel controversial. Real scanners cost less, do less marketing, and produce work that survives legal scrutiny. Overlays cost more, market more, and produce work that has now drawn FTC enforcement against the largest vendor. We bet on the scanner path. We think you should too.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/overlay-widgets-vs-real-wcag-scanners" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How an Accessibility SaaS Broke Its Own Landing (and How We Fixed It)</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 26 May 2026 14:07:47 +0000</pubDate>
      <link>https://dev.to/lawebe/how-an-accessibility-saas-broke-its-own-landing-and-how-we-fixed-it-5802</link>
      <guid>https://dev.to/lawebe/how-an-accessibility-saas-broke-its-own-landing-and-how-we-fixed-it-5802</guid>
      <description>&lt;p&gt;&lt;strong&gt;We sell accessibility audits. Last week, we shipped a marketing landing for our scanner. It used scroll-triggered reveals. Under &lt;code&gt;prefers-reduced-motion&lt;/code&gt; the reveals never resolved — the content stayed invisible. Our own landing failed the test we sell. Here is the one-line CSS fix, the Playwright assertion that locks it in CI, and what to look at in your own codebase.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Same visual intent, two implementations. Only the right one is safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug
&lt;/h2&gt;

&lt;p&gt;Modern marketing pages use reveal-on-scroll animations. The element starts invisible (or off-position), then animates into view when it enters the viewport. The canonical CSS looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 600ms ease, transform 600ms ease;
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An IntersectionObserver toggles &lt;code&gt;.is-visible&lt;/code&gt; as the element scrolls in. Looks great.&lt;/p&gt;

&lt;p&gt;Then someone with vestibular disorder, migraine sensitivity, or ADHD opens your site. Their OS-level setting is &lt;em&gt;Reduce motion&lt;/em&gt;. Their browser exposes this via &lt;code&gt;prefers-reduced-motion: reduce&lt;/code&gt;. Most animation libraries respect it correctly: when reduced motion is requested, transitions are disabled.&lt;/p&gt;

&lt;p&gt;That is precisely the problem. With transitions disabled, the element never moves from its start state. &lt;code&gt;opacity: 0&lt;/code&gt; stays at &lt;code&gt;opacity: 0&lt;/code&gt;. The reveal never resolves. Your visitor sees a blank page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why opacity-driven reveals are an accessibility bug, not a feature
&lt;/h2&gt;

&lt;p&gt;It is tempting to think the browser is being "too literal." It is not. Reduced motion is a contract: &lt;strong&gt;do not animate&lt;/strong&gt;. The browser honours it by not running the keyframe. The bug is in your CSS: you encoded the visible state as the &lt;em&gt;end&lt;/em&gt; of an animation that you have just told the browser to skip.&lt;/p&gt;

&lt;p&gt;WCAG 2.3.3 (Animation from Interactions, AAA) and the broader principle in WCAG 2.1 §2.3 are about avoiding harm. But here we are not even debating triggers — we are removing the visible content entirely. The reveal becomes a &lt;code&gt;display: none&lt;/code&gt; for anyone with reduced motion enabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  The transform-only fix
&lt;/h2&gt;

&lt;p&gt;Stop animating opacity. Animate only &lt;code&gt;transform&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.reveal {
  transform: translateY(20px);
  transition: transform 600ms ease;
}
.reveal.is-visible {
  transform: translateY(0);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;opacity&lt;/code&gt; stays at its default of &lt;code&gt;1&lt;/code&gt;. Under reduced motion, the browser skips the transform, the element appears at its final position immediately, content visible from first paint. With motion enabled, the translate plays as before. Same visual intent, no regression.&lt;/p&gt;

&lt;p&gt;For the genuine case where you need opacity (a fade-in modal, a real cross-fade), wrap the rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transition: none; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says, plainly: under reduced motion, no transition, content visible. Two lines, no library needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Locking the regression out with Playwright
&lt;/h2&gt;

&lt;p&gt;Code fixes are easy to lose during a refactor. A test makes the rule permanent. In Playwright:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { test, expect } from '@playwright/test'

test('reveals remain visible under prefers-reduced-motion', async ({ page }) =&amp;gt; {
  await page.emulateMedia({ reducedMotion: 'reduce' })
  await page.goto('/')
  const reveals = page.locator('.reveal')
  const count = await reveals.count()
  for (let i = 0; i  getComputedStyle(el).opacity)
    expect(Number(opacity)).toBeGreaterThan(0.99)
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wire it into your CI as a blocking job. Now no future commit can re-introduce the bug without the pipeline turning red.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other places this pattern hides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hero text fade-in&lt;/strong&gt; — same opacity issue. Replace with translateY or remove entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stagger reveals on cards&lt;/strong&gt; — each card with &lt;code&gt;opacity: 0&lt;/code&gt; until a delay-based trigger fires. Same fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skeleton loaders that fade out&lt;/strong&gt; — if the real content fades in via opacity, under PMRM you get both layers stuck. Use display swap or set opacity:1 under PMRM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Off-canvas drawers&lt;/strong&gt; with opacity transitions on inner content — drawer opens, content invisible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toast notifications&lt;/strong&gt; that animate in with opacity — the toast appears empty.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to find every offender in your codebase
&lt;/h2&gt;

&lt;p&gt;A blunt grep is usually enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;grep -rE "opacity:\s*0" --include="*.css" --include="*.scss" --include="*.tsx" .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything that returns deserves a look. The fix is repetitive but mechanical.&lt;/p&gt;

&lt;p&gt;If you ship motion at all, audit your codebase once and add the Playwright guard once. After that the rule self-enforces. Total cost: an hour. Cost of skipping it: any user with reduced motion enabled cannot see your landing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run a free scan of your own landing
&lt;/h2&gt;

&lt;p&gt;If you have not audited your own marketing site lately, our &lt;a href="https://dev.to/free-wcag-scan"&gt;free WCAG scanner&lt;/a&gt; runs axe-core on any public URL, no signup, returns a triaged report in under a minute. It will not catch &lt;em&gt;this&lt;/em&gt; specific bug (reduced-motion testing is not part of WCAG conformance criteria — axe-core does not emulate user preferences), but it will catch most other things. For the reduced-motion case specifically, run the Playwright test above. It is the cheapest insurance you can buy against an entire class of accessibility regressions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/prefers-reduced-motion-transform-only-fix" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Web Accessibility Statement: Template + Examples</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 22 May 2026 07:27:21 +0000</pubDate>
      <link>https://dev.to/lawebe/web-accessibility-statement-template-examples-465e</link>
      <guid>https://dev.to/lawebe/web-accessibility-statement-template-examples-465e</guid>
      <description>&lt;p&gt;&lt;strong&gt;An accessibility statement is a public page declaring your conformance target, known limitations, and how to report problems. It is not legally required everywhere, but it is one of the cheapest, highest-leverage things you can publish — and it matters in an ADA dispute.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why publish one
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It signals good faith — a documented commitment with a feedback channel is part of the defensible posture plaintiffs settle around.&lt;/li&gt;
&lt;li&gt;It is required by some laws (EU public-sector bodies under the Web Accessibility Directive must publish one; the EAA expects accessibility information).&lt;/li&gt;
&lt;li&gt;It gives real users a way to report barriers and get help.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to include
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Commitment&lt;/strong&gt; — a sentence stating you are committed to accessibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conformance target&lt;/strong&gt; — e.g. we aim to conform to WCAG 2.2 Level AA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current status&lt;/strong&gt; — fully conformant, partially conformant, or in progress (be honest).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Known limitations&lt;/strong&gt; — areas you know fall short, with a plan to fix them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback mechanism&lt;/strong&gt; — an email or form, with a response-time commitment (e.g. 5 business days).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date&lt;/strong&gt; — when the statement was last reviewed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Copy-paste template
&lt;/h2&gt;

&lt;p&gt;Adapt the following to your organisation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Accessibility Statement for [Company]

[Company] is committed to ensuring digital accessibility for people
with disabilities. We aim to conform to WCAG 2.2 Level AA.

Status: Partially conformant — most of the site meets WCAG 2.2 AA;
some areas are being remediated.

Known limitations: [list, with target dates].

Feedback: If you encounter a barrier, email accessibility@[company].com.
We aim to respond within 5 business days.

This statement was last reviewed on [date].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Claiming "fully accessible" or "100% WCAG compliant" — overclaiming can be used against you. State your target and honest status.&lt;/li&gt;
&lt;li&gt;No working feedback channel. An ignored contact address is worse than none.&lt;/li&gt;
&lt;li&gt;Never updating the review date.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Generate one in seconds
&lt;/h2&gt;

&lt;p&gt;Use the free &lt;a href="https://dev.to/tools/accessibility-statement-generator"&gt;accessibility statement generator&lt;/a&gt; to produce a tailored statement, then back it with continuous scans so the status line stays true. A statement that claims conformance you cannot show is a liability; one backed by dated audits is an asset.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/accessibility-statement-template-examples" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>ada</category>
      <category>legal</category>
    </item>
    <item>
      <title>PDF Accessibility: How to Make PDFs WCAG Compliant</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 22 May 2026 07:26:50 +0000</pubDate>
      <link>https://dev.to/lawebe/pdf-accessibility-how-to-make-pdfs-wcag-compliant-2ebe</link>
      <guid>https://dev.to/lawebe/pdf-accessibility-how-to-make-pdfs-wcag-compliant-2ebe</guid>
      <description>&lt;p&gt;&lt;strong&gt;WCAG and the ADA apply to document content, not just HTML pages. A scanned, untagged PDF is invisible to a screen reader — and PDFs (statements, guides, forms) are often the most important documents on a site. Here is how to make them conformant.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why PDFs are an accessibility blind spot
&lt;/h2&gt;

&lt;p&gt;Teams audit their web pages and forget the PDFs linked from them. But a fee schedule, a benefits guide, or an application form in PDF is subject to the same WCAG criteria. An untagged PDF fails WCAG 1.3.1 (Info and Relationships), 1.1.1 (Non-text Content), and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tags and reading order
&lt;/h3&gt;

&lt;p&gt;The PDF must have a tag tree that reflects the logical reading order. This is the single most important fix — it is what lets a screen reader navigate headings, paragraphs, and lists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document structure
&lt;/h3&gt;

&lt;p&gt;Use real heading tags (H1, H2, H3) in order, real lists, and real paragraphs — not just visually styled text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alt text on images
&lt;/h3&gt;

&lt;p&gt;Every informative image needs alternative text; decorative images are marked as artifacts so they are skipped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tables
&lt;/h3&gt;

&lt;p&gt;Data tables need header cells defined so screen readers can associate each value with its row and column.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document language and title
&lt;/h3&gt;

&lt;p&gt;Set the document language (so the screen reader uses the right pronunciation) and a descriptive document title in the metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forms
&lt;/h3&gt;

&lt;p&gt;PDF form fields need labels (tooltips), a logical tab order, and accessible instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Color and contrast
&lt;/h3&gt;

&lt;p&gt;Same thresholds as the web: 4.5:1 for normal text. Never use color alone to convey meaning.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check a PDF
&lt;/h2&gt;

&lt;p&gt;Adobe Acrobat Pro has a built-in Accessibility Checker (Prepare for accessibility). The free PAC (PDF Accessibility Checker) tests against PDF/UA and WCAG. Always finish with a manual screen-reader pass — tags can be present but illogical.&lt;/p&gt;

&lt;h2&gt;
  
  
  The better long-term fix
&lt;/h2&gt;

&lt;p&gt;Where you can, publish content as HTML instead of PDF. HTML is accessible by default when authored correctly, reflows on mobile, and is far easier to keep conformant than a binary document.&lt;/p&gt;

&lt;h2&gt;
  
  
  How AccessProof helps
&lt;/h2&gt;

&lt;p&gt;AccessProof audits the HTML pages of your site and flags where PDF downloads are linked, so you can route those documents into a PDF remediation workflow. For the web layer itself, a &lt;a href="https://dev.to/free-wcag-scan"&gt;free scan&lt;/a&gt; shows your current WCAG status in under a minute.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/pdf-accessibility-wcag-guide" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>wcag</category>
    </item>
    <item>
      <title>Image Alt Text: WCAG Rules and Best Practices</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 22 May 2026 07:21:09 +0000</pubDate>
      <link>https://dev.to/lawebe/image-alt-text-wcag-rules-and-best-practices-49l8</link>
      <guid>https://dev.to/lawebe/image-alt-text-wcag-rules-and-best-practices-49l8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Alt text (the alt attribute on images) is how screen readers describe pictures to people who cannot see them. It satisfies WCAG 1.1.1 Non-text Content (Level A) — the most fundamental accessibility rule. Getting it right is mostly about &lt;em&gt;context&lt;/em&gt;, not description.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  WCAG 1.1.1 in one sentence
&lt;/h2&gt;

&lt;p&gt;Every non-text element that conveys information needs a text alternative that serves the equivalent purpose. Decorative elements need an empty alternative so assistive tech skips them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four kinds of images
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Informative
&lt;/h3&gt;

&lt;p&gt;Conveys meaning. Alt text describes the information, not the picture. For a chart showing rising sales, use &lt;code&gt;alt="Sales up 24% from Q1 to Q2"&lt;/code&gt;, not &lt;code&gt;alt="bar chart"&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decorative
&lt;/h3&gt;

&lt;p&gt;Adds no information (background textures, dividers, eye-candy). Use &lt;code&gt;alt=""&lt;/code&gt; — empty, not missing — so screen readers skip it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functional
&lt;/h3&gt;

&lt;p&gt;Inside a link or button. Alt text describes the &lt;em&gt;action&lt;/em&gt;, not the icon. A magnifying-glass search button is &lt;code&gt;alt="Search"&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex
&lt;/h3&gt;

&lt;p&gt;Charts, infographics, maps. Use a short alt for the gist plus a longer description nearby — a caption, adjacent text, or a linked data table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules that catch most failures
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Never start with "image of" or "picture of" — the screen reader already announces "image".&lt;/li&gt;
&lt;li&gt;Do not keyword-stuff. Alt text is for users, not bots (good alt text helps SEO honestly anyway).&lt;/li&gt;
&lt;li&gt;Logos: the alt text is the company name, e.g. &lt;code&gt;alt="AccessProof"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the same information is in adjacent text, the image is decorative — use an empty alt.&lt;/li&gt;
&lt;li&gt;Text in images: the alt must contain the exact text (and avoid text-in-images where you can).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick examples
&lt;/h2&gt;

&lt;p&gt;ImageBad altGood alt&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Team photo on About page"team""The AccessProof team at the 2026 a11y summit"&lt;br&gt;
PDF download icon link"icon""Download the WCAG checklist (PDF)"&lt;br&gt;
Decorative section divider"divider line"empty alt&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  How AccessProof helps&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;AccessProof flags every image missing an alt attribute and every empty alt where the image appears informative — mapped to WCAG 1.1.1, with the exact selector. No tool can judge whether your alt text reads &lt;em&gt;well&lt;/em&gt;, but AccessProof guarantees none are missing. Run a &lt;a href="https://dev.to/free-wcag-scan"&gt;free scan&lt;/a&gt; to see your image findings.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/image-alt-text-wcag-guide" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>wcag</category>
    </item>
    <item>
      <title>How to Do a Website Accessibility Audit (Step by Step)</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 22 May 2026 07:20:38 +0000</pubDate>
      <link>https://dev.to/lawebe/how-to-do-a-website-accessibility-audit-step-by-step-21jo</link>
      <guid>https://dev.to/lawebe/how-to-do-a-website-accessibility-audit-step-by-step-21jo</guid>
      <description>&lt;p&gt;&lt;strong&gt;An accessibility audit checks a website against the Web Content Accessibility Guidelines (WCAG). Done well, it produces two things: a prioritized list of issues to fix, and dated evidence that you are actively conforming. Here is the 7-step workflow we use.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated scanning catches about 30-40%
&lt;/h2&gt;

&lt;p&gt;Automated tools (axe-core, Lighthouse, AccessProof) reliably catch issues like color contrast, missing alt text, unlabeled form fields, and ARIA misuse. They cannot judge whether alt text is &lt;em&gt;meaningful&lt;/em&gt;, whether focus order makes sense, or whether an error message is understandable. A real audit combines automation with manual testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 7 steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Define scope and standard
&lt;/h3&gt;

&lt;p&gt;Pick the pages that represent your templates (home, a content page, a form, a listing, checkout or login). Set your target: WCAG 2.2 Level AA is the practical standard for ADA and the EAA.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Run an automated scan
&lt;/h3&gt;

&lt;p&gt;Scan each template with &lt;a href="https://dev.to/free-wcag-scan"&gt;a WCAG scanner&lt;/a&gt;. Export the findings as your baseline and group them by severity — critical and serious first.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Test with the keyboard only
&lt;/h3&gt;

&lt;p&gt;Put the mouse aside. Tab through every page. Can you reach and operate every control? Is the focus indicator always visible? Can you escape every menu and modal? Keyboard traps are critical failures automation often misses.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Test with a screen reader
&lt;/h3&gt;

&lt;p&gt;Use NVDA (Windows) or VoiceOver (Mac). Listen to the page title, headings, link text, and form labels. Anything that reads as "link" or "button" with no name is a failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Check contrast and zoom
&lt;/h3&gt;

&lt;p&gt;Verify text contrast (4.5:1 for normal text, 3:1 for large) with &lt;a href="https://dev.to/tools/color-contrast-checker"&gt;a contrast checker&lt;/a&gt;. Zoom the browser to 200% and 400% — content must reflow without horizontal scrolling or clipping.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Audit forms and error states
&lt;/h3&gt;

&lt;p&gt;Submit forms with empty and invalid data. Are errors announced and tied to the right field? Are required fields and formats communicated in text, not color alone?&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Document and schedule
&lt;/h3&gt;

&lt;p&gt;Record every finding with its WCAG criterion, the page, and the fix. Then schedule the scan to repeat — the dated record of continuous remediation is what matters legally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Running one tool and calling it an audit (you miss the majority of issues).&lt;/li&gt;
&lt;li&gt;Auditing only the marketing pages, never the logged-in app where users spend time.&lt;/li&gt;
&lt;li&gt;Fixing once and never re-scanning — conformance drifts with every deploy.&lt;/li&gt;
&lt;li&gt;Trusting an overlay widget to "fix" issues. Courts increasingly reject them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How AccessProof helps
&lt;/h2&gt;

&lt;p&gt;AccessProof automates steps 2, 5, and 6 with the axe-core 4.9.1 engine, prompts you for the manual checks in steps 3-4, and archives each scan as a timestamped PDF — so step 7 happens by default. Schedule weekly or per-deploy scans and your audit trail builds itself.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/how-to-do-accessibility-audit" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Shopify Store Accessibility Checklist (WCAG 2.2)</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 19 May 2026 18:42:52 +0000</pubDate>
      <link>https://dev.to/lawebe/the-shopify-store-accessibility-checklist-wcag-22-2bd5</link>
      <guid>https://dev.to/lawebe/the-shopify-store-accessibility-checklist-wcag-22-2bd5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Shopify's Dawn theme (and most marketplace themes) ships with several WCAG 2.2 issues out of the box. Here's a checklist we use when auditing Shopify stores, in priority order.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Critical (fail an audit on their own)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Color contrast&lt;/strong&gt; on sale price tags (red on light pink), placeholder text in inputs, and the cart drawer headers. Threshold: 4.5:1 normal text, 3:1 large/bold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buttons without accessible names&lt;/strong&gt;: the icon-only quantity steppers (+ / −) often have no &lt;code&gt;aria-label&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form labels&lt;/strong&gt; on the checkout: most "floating label" implementations fail when the label moves outside the input's accessible name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Serious
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Carousel autoplay with no pause control.&lt;/li&gt;
&lt;li&gt;Keyboard trap in the predictive search drawer (focus stays inside even after closing).&lt;/li&gt;
&lt;li&gt;Modal product quick-view returns focus to the top of the page instead of the trigger.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WCAG 2.2-specific
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target size 2.5.8&lt;/strong&gt;: social icons in the footer are typically 16×16. Bump to 24×24 minimum.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drag movements 2.5.7&lt;/strong&gt;: any custom slider or sortable wishlist needs a click/tap fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessible authentication 3.3.8&lt;/strong&gt;: Shopify's default checkout is fine; custom checkouts that ban paste in the password field fail this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick wins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Audit your &lt;code&gt;theme.liquid&lt;/code&gt; for hardcoded colors against your background tokens.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;aria-label&lt;/code&gt; to every `` that contains only an icon or SVG.&lt;/li&gt;
&lt;li&gt;Set focus styles globally: &lt;code&gt;:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Test the keyboard tab order through a full checkout. If you can't complete a purchase keyboard-only, the score doesn't matter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AccessProof scans Shopify stores out of the box (we follow redirects through the storefront) and groups findings by template so your dev team can fix them theme-wide instead of page-by-page.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/shopify-accessibility-checklist" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>shopify</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>axe-core vs. Lighthouse: Which Catches More Accessibility Issues?</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 19 May 2026 18:42:21 +0000</pubDate>
      <link>https://dev.to/lawebe/axe-core-vs-lighthouse-which-catches-more-accessibility-issues-3624</link>
      <guid>https://dev.to/lawebe/axe-core-vs-lighthouse-which-catches-more-accessibility-issues-3624</guid>
      <description>&lt;p&gt;&lt;strong&gt;Lighthouse and axe-core are the two automated accessibility scanners most teams reach for. They share a heritage (Lighthouse's a11y category embeds axe-core), but they catch different things in practice. We ran both against 50 production websites — here's what we found.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;50 sites, mix of e-commerce, SaaS, and content (avg 8 issues/site between the two).&lt;/li&gt;
&lt;li&gt;Lighthouse 11 (default a11y category, mobile preset).&lt;/li&gt;
&lt;li&gt;axe-core 4.9 with rules at &lt;code&gt;wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22aa&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;MetricLighthouseaxe-core 4.9&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Avg issues found per site4.27.8&lt;br&gt;
Unique rules triggered2756&lt;br&gt;
WCAG 2.2 coveragepartialfull&lt;br&gt;
False positive rate (manual review)~5%~3%&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  What axe-core catches that Lighthouse misses&lt;br&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;WCAG 2.2 target-size violations (2.5.8).&lt;/li&gt;
&lt;li&gt;ARIA misuse on custom widgets (axe is much stricter on role/state mismatch).&lt;/li&gt;
&lt;li&gt;Region/landmark issues on complex layouts.&lt;/li&gt;
&lt;li&gt;Color contrast on text inside images (axe has better OCR-aware checks).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Lighthouse adds
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Performance correlation: an accessibility score next to LCP/CLS gives leadership a single dashboard.&lt;/li&gt;
&lt;li&gt;Crawl-style scoring out of 100, easier to track over time at a high level.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;Use both. Lighthouse is great for &lt;em&gt;tracking&lt;/em&gt; a top-line score in CI dashboards. axe-core is what you want when you need to &lt;em&gt;fix&lt;/em&gt; issues — its rule set is broader, its node-level reporting is more actionable, and it's the engine behind most professional audits. AccessProof runs axe-core under the hood, mapped to WCAG 2.2 and exportable as PDF.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://access-proof.com/blog/axe-core-vs-lighthouse-accessibility" rel="noopener noreferrer"&gt;access-proof.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
