Accessibility feedback during local development
Accessibility fixes are easy to get subtly wrong. An aria-label added to a button can override the visible text a speech-recognition user says out loud. Correcting one heading level can break the outline further down the page. Reordering a form to fix focus order can strip a label off the field below it. In each case the rule you were working on starts passing and a different one starts failing, and you don't find out until the next CI run.
Recording a spec from your own machine closes that gap. One command produces the same Cypress Accessibility report your CI runs produce, processed in Cypress Cloud with the same App Quality Config and the same Axe Coreยฎ version. You can confirm a fix, spot the violation the fix introduced, and iterate before you write the commit message.
Record the specs you're working onโ
Record only the specs that exercise the code you changed:
- npm
- Yarn
- pnpm
- Bun
npx cypress run --record --key <record_key> --spec "cypress/e2e/checkout.cy.js"
yarn cypress run --record --key <record_key> --spec "cypress/e2e/checkout.cy.js"
pnpm cypress run --record --key <record_key> --spec "cypress/e2e/checkout.cy.js"
bunx cypress run --record --key <record_key> --spec "cypress/e2e/checkout.cy.js"
Recording is what produces the report, so this has to be cypress run --record. Interactive mode (cypress open) never records a run to Cypress Cloud, so it never generates accessibility results.
When the run finishes, Cypress prints its URL at the end of the run summary:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Recorded Run: https://cloud.cypress.io/projects/7s5okt/runs/1042
Open that URL and go to the Accessibility tab.
CYPRESS_RECORD_KEY must be set as an actual operating system environment
variable (for example via export CYPRESS_RECORD_KEY=... or your CI provider's
secrets). Cypress reads it directly from your shell or CI environment โ it is
not read from cypress.env.json or the env block of your Cypress
configuration, since those only populate test environment variables. If you
don't want to set an environment variable, pass the key inline with the --key
flag instead.
Nothing else is required.
The requirements are the same as for any recorded run, with one that catches people locally: reports need a Chromium-based or Electron browser, so a habit of running --browser firefox locally produces no report at all. See No accessibility report was generated for a run for the full list.
To stay in your editor for the whole loop rather than switching to the browser after each recording, configure Cypress Cloud MCP and ask your agent for the run's results. See Work with AI agents for prompt patterns.
When the report is readyโ
Each spec's data starts processing as soon as that spec finishes uploading, but the run-level report is assembled only once Cypress Cloud marks the run complete.
For grouped and parallelized runs, completion waits out the project's Run Completion Delay, a grace period (60 seconds by default) that lets late machines join the run before it closes. Report finalization waits with it, so on a CI run the accessibility report can trail the last machine by that much.
A single local run without --group or --parallel skips the delay entirely. Cypress Cloud completes it as soon as its specs are done, which is why the loop on this page stays fast. You inherit the delay only when you reproduce a CI invocation locally with grouping or parallelization. If you do, shorten the delay in project settings or close the run yourself with the Run Completion API.
Compare two local runs to prove a fix landedโ
Seeing zero violations for the rule you fixed is weaker evidence than seeing that rule move from failing to resolved. Branch Review gives you that, and it works just as well with two runs recorded from your own machine. Cypress reads your branch and commit from your local .git directory on every recorded run, whether or not it detects a CI provider, so local runs land on the correct branch and can be compared like any other run.
-
Record the specs from your base branch first, before you start work, or by stashing your changes:
- npm
- Yarn
- pnpm
- Bun
npx cypress run --record --spec "cypress/e2e/checkout.cy.js"yarn cypress run --record --spec "cypress/e2e/checkout.cy.js"pnpm cypress run --record --spec "cypress/e2e/checkout.cy.js"bunx cypress run --record --spec "cypress/e2e/checkout.cy.js" -
Make your fix, then record the same specs again from your branch.
-
In Cypress Cloud, open Branch Review with your branch's run as the Changed run and the base branch's run as the Base run.

The Resolved elements section should list the rule you worked on in every view where it was failing, which is how you confirm the fix reached more than the one element you tested by hand. The New failed elements section is the more valuable half: it's where the aria-label that duplicates visible text shows up.
Recording the same specs in both runs is what makes the comparison trustworthy. Branch Review compares what each run actually saw, so a base run covering the whole suite and a changed run covering one spec produces a long list of "resolved" elements that only means those pages weren't visited.
The score for a two-spec local run isn't comparable to the score for a full CI run. A run's accessibility score averages every snapshot in that run, so changing which specs ran changes the denominator. Compare rules and element counts between local runs, and leave score tracking to your full suite.
Make your configuration match localhostโ
The one thing that may differ between a local run and a CI run is the URL your tests visit. viewFilters patterns that name a hostname match that hostname exactly, so a configuration written for a deployed environment silently stops applying when you run against http://localhost:3000. Pages you meant to exclude reappear, and the local report stops matching the one your team sees in CI.
Path-only patterns match any hostname, so they work in both places:
{
"viewFilters": [
{
"pattern": "/auth/*",
"include": false,
"comment": "Hosted sign-in provider, out of scope. Path-only so it matches localhost and deployed environments alike"
}
]
}
When a rule has to name a hostname, add a profile for local runs and override just that setting:
{
"viewFilters": [
{ "pattern": "https://app.example.com/*", "include": true },
{
"pattern": "*",
"include": false,
"comment": "Report only on our own application"
}
],
"profiles": [
{
"name": "aq-config-local",
"comment": "Local runs serve the app from localhost, so the hostname rules above never match",
"config": {
"viewFilters": [
{ "pattern": "http://localhost:*/*", "include": true },
{ "pattern": "*", "include": false }
]
}
}
]
}
Select the profile by tagging the run:
- npm
- Yarn
- pnpm
- Bun
npx cypress run --record --tag "aq-config-local" --spec "cypress/e2e/checkout.cy.js"
yarn cypress run --record --tag "aq-config-local" --spec "cypress/e2e/checkout.cy.js"
pnpm cypress run --record --tag "aq-config-local" --spec "cypress/e2e/checkout.cy.js"
bunx cypress run --record --tag "aq-config-local" --spec "cypress/e2e/checkout.cy.js"
A profile replaces each setting it defines rather than merging with it, so repeat any base rules the local run still needs. See profiles for how selection and overriding work.
Keep local runs from cluttering the projectโ
Local runs land in the same project as your CI runs, and their reports are just as real. To keep them recognizable, tag them:
- npm
- Yarn
- pnpm
- Bun
npx cypress run --record --tag "local" --spec "cypress/e2e/checkout.cy.js"
yarn cypress run --record --tag "local" --spec "cypress/e2e/checkout.cy.js"
pnpm cypress run --record --tag "local" --spec "cypress/e2e/checkout.cy.js"
bunx cypress run --record --tag "local" --spec "cypress/e2e/checkout.cy.js"
Tags are shown on the run and are filterable in Cypress Cloud, so a shared local tag lets anyone skip past them when scanning the run list.
Every recorded run also consumes test results from your plan, whether it came from CI or your laptop. That's an argument for narrow --spec runs, which you want anyway.
What a local run can't doโ
The Results API is a CI tool and doesn't have a local equivalent. getAccessibilityResults() identifies the run to report on from the CI environment variables present when the run was recorded, so calling it from your machine fails with "It appears you are not running in CI." Keep policy enforcement in your pipeline and use Cypress Cloud, Branch Review, or Cloud MCP for local feedback.
See alsoโ
- Compare reports is the full guide to Branch Review for Cypress Accessibility.
- Catch accessibility regressions covers the other ways to catch one, including scheduled runs, CI policies, and analytics.
- Fix accessibility violations is the workflow this page speeds up: pick a rule, fix it, prove it landed.
- How Cypress Accessibility works explains the recording, processing, and reporting stages.
profilesdocuments run-tag-based configuration overrides in full.viewFilterscovers URL pattern matching, including path-only patterns.- Work with AI agents has more Cypress Cloud MCP prompt patterns.
- Block pull requests and set policies is where the Results API belongs, once local feedback is in place.
- Troubleshooting covers reports that are missing or don't match what you expect.
- Cypress Accessibility FAQ answers focused questions about local runs, scoring, and configuration.