---
id: accessibility/guides/local-development
title: Accessibility feedback during local development
description: >-
  Record one spec from your machine to get a full Cypress Accessibility report
  without waiting for CI: confirm a fix, catch the violation it introduced, and
  compare against your base branch before you push.
section: accessibility
source_path: docs/accessibility/guides/local-development.mdx
version: 29f95bf8bb06f320986f3749f5bf09a35a409eab
updated_at: '2026-09-04T10:49:54.630Z'
---
# 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](/llm/markdown/accessibility/troubleshooting.md#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](/llm/markdown/cloud/integrations/cloud-mcp.md) and ask your agent for the run's results. See [Work with AI agents](/llm/markdown/accessibility/work-with-ai-agents.md) 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](/llm/markdown/cloud/features/smart-orchestration/parallelization.md#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](/llm/markdown/cloud/account-management/projects.md#Run-Completion-Delay) or close the run yourself with the [Run Completion API](/llm/markdown/cloud/features/smart-orchestration/parallelization.md#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](/llm/markdown/accessibility/guides/compare-reports.md) 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.

1.  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"
    ```
    
2.  Make your fix, then record the same specs again from your branch.
    
3.  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](/llm/markdown/accessibility/core-concepts/accessibility-score.md) 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`](/llm/markdown/accessibility/configuration/viewfilters.md) 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:

App Quality Config

```
{
  "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](/llm/markdown/accessibility/configuration/profiles.md) for local runs and override just that setting:

App Quality Config

```
{
  "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`](/llm/markdown/accessibility/configuration/profiles.md) 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](/llm/markdown/cloud/account-management/billing-and-usage.md#Cloud-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](/llm/markdown/accessibility/connect-and-extend/results-api.md) 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](/llm/markdown/accessibility/guides/compare-reports.md) is the full guide to Branch Review for Cypress Accessibility.
*   [Catch accessibility regressions](/llm/markdown/accessibility/guides/detect-changes.md) covers the other ways to catch one, including scheduled runs, CI policies, and analytics.
*   [Fix accessibility violations](/llm/markdown/accessibility/guides/improve-accessibility.md) is the workflow this page speeds up: pick a rule, fix it, prove it landed.
*   [How Cypress Accessibility works](/llm/markdown/accessibility/core-concepts/how-it-works.md) explains the recording, processing, and reporting stages.
*   [`profiles`](/llm/markdown/accessibility/configuration/profiles.md) documents run-tag-based configuration overrides in full.
*   [`viewFilters`](/llm/markdown/accessibility/configuration/viewfilters.md) covers URL pattern matching, including path-only patterns.
*   [Work with AI agents](/llm/markdown/accessibility/work-with-ai-agents.md) has more Cypress Cloud MCP prompt patterns.
*   [Block pull requests and set policies](/llm/markdown/accessibility/guides/block-pull-requests.md) is where the Results API belongs, once local feedback is in place.
*   [Troubleshooting](/llm/markdown/accessibility/troubleshooting.md) covers reports that are missing or don't match what you expect.
*   [Cypress Accessibility FAQ](/llm/markdown/accessibility/faq.md) answers focused questions about local runs, scoring, and configuration.
