About the two scanning models: static source vs live DOM
b8e can look for accessibility defects in two ways, and the command you run decides which you get.
b8e scan . reads your source files and never opens a browser. b8e scan --url, --crawl, and
--story drive a real browser and inspect the rendered page. They find different things, so
it is worth knowing which question you are asking.
What each one can see
Section titled “What each one can see”A source scan asks what does the code say? It parses your components across eight stacks —
React/TSX, Astro, Shopify Liquid, iOS SwiftUI and UIKit, Interface Builder scenes (.storyboard
and .xib), Jetpack Compose, Android XML layouts, and Unity scenes — and checks the accessibility
contract each element declares. An <img> with no alt, an Image
with no accessibilityLabel, a control with no accessible name, a heading level that skips: all
visible without running anything. A run prints one coverage line per stack it found, and a stack it
recognises but cannot analyze says so rather than passing quietly.
A live-DOM scan asks what does the page become? It launches a browser, navigates, waits for the framework to hydrate and the JavaScript to run, then reads the accessibility tree a screen reader would actually get. That tree is the product of routing, data fetching, client-side rendering, portals, and conditional branches.
Neither covers the other. A defect can be plainly wrong in the source and gone by the time the page renders, because a wrapper injected the missing value. Another is invisible in the source and only appears once the page runs — a modal that traps focus, a live region that never announces.
When to reach for which
Section titled “When to reach for which”Source scan when you want speed and repeatability. The same source produces the same findings every time, with no network and no browser, which is what makes it usable on every commit and trustworthy as a pull-request gate. Its limit is that it can only reason about code it can resolve; when it cannot, it tells you rather than guessing — see About components the scanner can and cannot see.
Live-DOM scan when the question is about runtime: focus order, dynamic ARIA state, live-region announcements, contrast against actually-painted pixels, what a route does after client navigation. Three flags run the same live-DOM scan, differing in what gets rendered:
--urlrenders specific pages and aggregates them into one report.--crawlexpands a seed URL into a same-origin page set first, for breadth without listing every route.--storyrenders Storybook stories — often the most useful during development, since components appear in the states their authors care about.
The cost is the mirror image: richer, closer to real experience, but it needs a browser, a network,
and a page that renders predictably. For flags and defaults, see the
b8e scan reference.
Where b8e audit fits
Section titled “Where b8e audit fits”b8e audit is a third thing, and worth not confusing with either scan. It runs journeys through a
real browser and a real screen reader, and answers whether a person can complete a task — not
whether the markup is well formed. A scan reports defects on a surface; an audit reports whether a
journey succeeds. See the b8e audit reference.
Three separate questions, then: does the code declare the right thing, does the rendered page expose the right thing, and can someone actually get through the flow. Each has its own command.