Flow
Crawl your whole site, including what is behind your login, and ship fixes as code
Flow crawls up to your plan’s page limit across your domains, signs in as a real user to reach the pages a public scanner never sees, and returns a patch for every barrier it can fix. Each one is labelled deterministic, inferred or declined, with the declined ones named so a person can pick them up.
Crawl, compile, ship
- Step 1
Crawl
Sitemap first, then link following from your base URL, across the domains your plan allows and in both desktop and mobile viewports. Two requests a minute by default, and configurable. Our egress IPs are published, and the crawler sends a user agent carrying a secret only you know, so one rule in your bot protection lets us through without opening a door for anyone else.
- Step 2
Compile
axe-core 4.10 plus our own rule pack, then the same taxonomy the widget uses: deterministic where the fix follows from the markup, inferred where a model proposed it from context and it survived the refusal gate, declined where neither holds and a person has to decide.
- Step 3
Ship
A patch to merge, a pull request through the GitHub app, or an auto-resolve entry that applies the fix at runtime with an expiry date attached. Fixed pages are re-audited on demand from your daily quota, so a fix is verified rather than assumed.
Code patches
A patch your developers can read, review and merge
The output of a Flow audit is not a score and a to-do list. For every finding it can fix, Flow shows the markup as it stands, the markup as it should be, why it changed, and which of the three labels the change carries. You are reviewing a diff, which is a thing your team already knows how to do.
Found on the page
<div class="cart-toggle" onclick="openCart()">
<svg viewBox="0 0 24 24"><path d="M6 6h15l-1.5 9h-12z" /></svg>
<span class="count">3</span>
</div>Suggested patch · deterministic
<button type="button" class="cart-toggle" aria-label="Open cart, 3 items">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6h15l-1.5 9h-12z" /></svg>
<span class="count">3</span>
</button>Three ways a fix reaches your codebase
When the model refuses, you see the question
An inferred fix has to pass a refusal gate before it is offered. When a model cannot tell what an icon button does from the page around it, it returns the question rather than a confident guess, because a wrong aria-label ships and silently misleads screen reader users for years, while a missing one is caught by the next audit. Those items are labelled declined and listed with the question a person has to answer.
Why we refuse rather than guessAuthenticated scanning
Scanning behind your login, without holding your keys
The pages with the worst accessibility barriers are usually the ones a public scanner cannot reach: the account area, the checkout, the admin console, the booking flow. Flow signs in and audits them. Here is exactly what happens to what you give us, because asking a team to trust a scanner with a password without saying this is not a reasonable ask.
Credentials arrive per scan, in the request body
You send them when you start an audit. They are not saved on a project, not stored for the next run, and not required for the pages that need no login.
They live in worker memory and nowhere else
They are never written to the database, the logs, telemetry, or the job record. Nothing you or a third party can later download contains them. Exports carry selectors and page URLs, never credentials.
A login is attempted exactly once, and never retried
Account lockout on a customer’s production application is unrecoverable, so a failed sign-in stops the audit and tells you which step failed. A scanner that retries a password is a scanner that locks out your staff.
Every scan gets a fresh browser context
No shared profile, no reused session, nothing carried between customers or between runs. The page being audited is running someone else’s JavaScript and it gets its own sandbox.
Query strings are redacted in stored URLs
A reset token, a session id or an email address in a query string is stripped before the URL is written to a finding, a report or an export.
Screenshots hold real production data, so they expire
Encrypted at rest, retained for 30 days or less, deletable in one click, and served only through short-lived signed links.
Three ways to let us in
- Session stateRecommended
- You log in yourself, export the browser session and paste it before the audit. This is the mode that works with SSO, two-factor authentication and magic links, because we never handle the second factor.
- Form login
- We fill your login form at audit time using selectors you provide, with the credentials sent alongside that one request. Optional success and still-on-login markers tell us whether it worked.
- No login
- Audit only what is reachable without signing in. Worth stating that this is a supported answer rather than a downgrade. Plenty of sites have their barriers in public.
Triage
Findings you can actually work through
A first crawl of a large site returns more than anyone can read in one sitting. Flow groups pages into templates by DOM shape, so a store with thousands of product pages becomes a few dozen templates, and one fix closes a column rather than a row.
Explore
- Issues, rules and web pages, each as its own view: occurrences, severity, the WCAG criteria touched, the device it was found on, the assignee and the comments.
- Filters that save per user, so the view you work from every morning is one click rather than six.
- Batch resolve, dismiss, assign and export. A dismissal records its reason (not relevant, by design, false positive, or something you type) so next quarter’s reviewer can see why.
- Verify fix runs a single-page audit from your daily quota, against the page you just changed.
Journeys and assets
- Record a journey with the browser extension, or build one by hand: up to 25 steps of clicking, typing, waiting and key presses, run on desktop and mobile on a schedule. A password step in a journey is handled the same way as a login: sent for that run, never stored.
- PDFs, Office files, audio and video found during the crawl are listed with their status. Automated remediation does not reach them, so they are listed rather than quietly counted as passing.
- Issue tracker integrations push findings into Jira, GitHub Issues or Linear, and read the status back, so a closed ticket is not still open in one of the two places.
Score history
A score with a published formula
A page scores between 15 and 100. The number is density-based and severity-weighted, and an extreme or high-severity issue caps a page at 70 no matter how clean the rest of it is. The site score is the average pulled down by the share of pages below 70, floored at the worst page. The formula is published rather than described as proprietary, so a number that moves can be explained.
History with deltas
Every audit is kept with its score delta, page delta and severity counts, so “did last quarter’s work help?” is a question with an answer.
Notifications that matter
A score drop, a new critical finding, a failed audit, an exhausted scan quota or a broken integration. Not a daily digest nobody reads.
Scheduled audits
Monthly, fortnightly or weekly depending on the tier, plus on-demand scans from a daily quota you can see.
Developer tooling
Built for the people who will merge the patch
The SDK, the MCP server and the GitHub app are on Growth and above; the trigger API and tokens come with them. What each one does:
Pricing
The prices are on this page, with the limits attached
The comparable developer platform in this market is quote-only: you book a call to find out what it costs. Ours is published, tier by tier, with the page caps, domain counts, seat counts and daily scan quotas next to the number, so you can work out whether it fits before you talk to anyone.
Questions a developer asks first
Point it at your staging site this afternoon
Seven days, no card. Crawl a domain, sign in to the part that matters, and see what the patches look like against your own markup before you decide anything.