# Technical Documentation: cypress-io/cypress-documentation

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/cypress-io/cypress-documentation)

### Overview (README.md)

# Cypress Documentation [](https://on.cypress.io/discord) [](https://github.com/cypress-io/cypress-documentation/labels/good-first-issue)



## CI status

[](https://github.com/cypress-io/cypress-documentation/actions/workflows/ci.yml?query=branch%3Amain)
`main` branch

[](https://app.netlify.com/sites/cypress-docs/deploys)

Our docs are built using [Docusaurus](https://docusaurus.io/).

### Installation

```
$ npm i
```

### Local Development

```
$ npm run start
```

This command starts a local development server and opens up a browser window.
Most changes are reflected live without having to restart the server.

### Build

```
$ npm run build
```

This command generates static content into the `dist` directory and can be
served using any static contents hosting service.

### LLM Docs

The build process reprocesses the content into both markdown and chunked JSON to be published under `/llm` - these formats strip out unnecessary styling and formatting which can be difficult and/or token-inefficient for use by LLMs. Three files at the site root index them:

- `/llms.txt` - a link index of every documentation page, in the [llmstxt.org](https://llmstxt.org) format.
- `/llms-full.txt` - the whole corpus concatenated into one markdown file.
- `/docs-manifest.json` - project metadata and the machine-readable list of every format published.

## Contributing

Refer to the [`CONTRIBUTING.md`](/CONTRIBUTING.md) guide for details.

## License

This project is licensed under the terms of the [MIT license](/LICENSE.md).

---

### Partials  Intercept Alias Index (`docs/partials/_intercept-alias-index.mdx`)

```js
cy.intercept('GET', '/users').as('getUsers')

// trigger multiple requests
cy.visit('/users')
cy.visit('/users')

// yields an array of all interceptions for this alias
cy.get('@getUsers.all').then((interceptions) => {
  expect(interceptions).to.have.length(2)
})
```

You can also retrieve a specific intercept by its 1-based numeric index. Without
any suffix, `cy.get('@alias')` returns the most recent intercepted request.

```js
cy.intercept('GET', '/users').as('getUsers')

cy.visit('/users')
cy.visit('/users')

// yields the first intercepted request
cy.get('@getUsers.1').its('response.statusCode').should('eq', 200)

// yields the second intercepted request
cy.get('@getUsers.2').its('response.statusCode').should('eq', 200)
```

:::caution

Index `0` is not valid — indices start at `1`. These suffixes are **not**
supported by [`cy.wait()`](/api/commands/wait). Use `cy.get('@alias.all')`
instead of `cy.wait('@alias.all')`.

:::

---

### Accessibility Configuration Overview (`docs/accessibility/configuration/overview.mdx`)

---
title: Configure Cypress Accessibility
description: 'Configure Cypress Accessibility to get an accessibility score you can trust: group URLs into views, ignore third-party elements, identify violations by your own attributes, and scope reports to the application you own.'
sidebar_label: Overview
sidebar_position: 10
---

<ProductHeading product="accessibility" />

# Configuration overview

Cypress Accessibility works out of the box with no setup, but a few lines of configuration make your reports match your application. Configuration lets you get an [accessibility score](/accessibility/core-concepts/accessibility-score) you can trust and act on by:

- **Reporting on the application you own**: ignore third-party widgets, embedded content, and pages outside your control so violations you can't fix stop counting against your score.
- **Organizing reports around your product**: group related URLs into [views](/accessibility/configuration/views) that map to real pages and flows, so a violation on a shared template is triaged once instead of once per URL.
- **Speaking your team's vocabulary**: identify violation targets by your own attributes, such as a component name or automation ID, so an issue reads as "the ProductImage component" instead of a generated selector.
- **Stabilizing identification across snapshots**: stop dynamic or auto-generated attributes from splitting one element into many, so the same element is recognized as one across the many snapshots in a run.

You don't need any of this to get started, and you can add it incrementally. Reprocess a past run after each change to see the effect immediately, without re-running your tests.

## Setting Configuration

<AppQualityConfigEditing />

<DocsImage
  src="/img/accessibility/configuration/cypress-accessibility-configuration-editor.png"
  alt="The App Quality tab of a project's settings in Cypress Cloud, showing the configuration editor with JSON configuration"
/>

After you save configuration changes, you can reprocess any historical run to apply them. You can start a reprocess from two places:

- The **Properties** tab, using the "regenerate" button next to the configuration values that were used for that run.
- The accessibility report, using the "configuration updated" message that appears when you view a historical run that was processed with an older configuration.

<DocsImage
  src="/img/accessibility/configuration/cypress-cloud-properties-tab-application-quality-config.png"
  alt="The Properties tab of a run in Cypress Cloud, showing the Application Quality configuration that was applied and the regenerate button used to reprocess the run"
/>

Regenerating reports in this way lets you iterate on configuration and see the effects immediately, without running your Cypress tests again.

<AppQualityConfigWhoCanEdit />

## Configuration options

### Which option do I need?

Several options change what appears in reports and how it's organized. Pick the one that matches your goal:

| Your goal                                                      | Use                                                                                     |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| Group related URLs into a single view                          | [`views`](/accessibility/configuration/views)                                           |
| Remove entire pages or URLs from reports                       | [`viewFilters`](/accessibility/configuration/viewfilters)                               |
| Remove elements from reports and the score entirely            | [`elementFilters`](/accessibility/configuration/elementfilters)                         |
| Enable, disable, or scope Axe Core® rules                      | [`axeConfig`](/accessibility/configuration/axe-core-configuration)                      |
| Keep an element but ignore specific rules for it               | [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) |
| Identify violation targets by your own attributes              | [`significantAttributes`](/accessibility/configuration/significantattributes)           |
| Stop dynamic or generated attributes from identifying elements | [`attributeFilters`](/accessibility/configuration/attributefilters)                     |
| Add component context to violation-target selectors            | [`components`](/accessibility/configuration/components)                                 |
| Apply different configuration to runs based on run tags        | [`profiles`](/accessibility/configuration/profiles)                                     |

### Comments

Most configuration rules support an optional `comment` property that you can use to record why a value is set. This makes your configuration easier to understand and maintain, especially when working in a team or revisiting configuration after some time. Any rule defined as an object accepts a `comment`; the options that are plain lists of strings, such as [`significantAttributes`](/accessibility/configuration/significantattributes), do not take a per-entry comment.

A `comment` lives inside the rule and has no effect on behavior. Comments appear only in the configuration itself and are never displayed in reports. Because Cypress Cloud validates every rule and rejects properties it doesn't recognize, `comment` is the supported place to keep notes.

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "#onetrust-banner-sdk, #onetrust-banner-sdk *",
      "include": false,
      "comment": "Third-party cookie consent banner, violations reported upstream to the vendor"
    }
  ]
}
```

### Full configuration reference

The shape of every available option, with the type each value expects. Every property is optional, and you only include the ones you need:

```
/* Detailed source-code truncated for AI context efficiency. */
```

One accessibility-specific control lives outside this JSON: the per-element [`data-a11y-ignore`](/accessibility/configuration/ignoring-rules-per-element) attribute is added to your application's markup.

## How rules are applied

A few behaviors govern the rules you write, and some of them differ from [UI Coverage](/ui-coverage/configuration/overview):

- **`viewFilters`: first match wins.** URLs are compared against your rules top to bottom, and the first rule whose `pattern` matches decides whether that URL is included. List specific rules before broad, catch-all rules. URLs that match no rule are included by default.
- **`elementFilters`: any exclude wins.** In Cypress Accessibility, an element is ignored when any `include: false` rule matches it, regardless of where the rule sits in the list, and an `include: true` rule can't protect an element from an exclusion elsewhere. This is different from UI Coverage, where the first matching rule wins. See [When to use include: true](/accessibility/configuration/elementfilters#When-to-use-include-true).
- **`significantAttributes`: order sets priority.** The attributes you list are checked before the default attributes, in the order you list them, and the first one that uniquely identifies an element becomes its violation-target selector.
- **Unknown properties are rejected.** When you save, Cypress Cloud validates your configuration against a strict schema and rejects anything it doesn't recognize, such as a misspelled property, a value of the wrong type, or a note on a property that doesn't accept one. Correct the flagged property to save, and keep freeform notes in a [`comment`](#Comments).

## Configuration scope

Some properties are shared across App Quality products, and some belong to Cypress Accessibility alone.

- **Shared properties**: `viewFilters`, `elementFilters`, `significantAttributes`, and `attributeFilters` apply to both Cypress Accessibility and UI Coverage when set at the root of your configuration. To apply one to Cypress Accessibility only, nest it under an `accessibility` key. A nested value **completely replaces** the root-level value for that product (the two are not merged), so repeat any shared rules you still want in the nested list.
- **Shared, but not nestable**: `views` applies to both Cypress Accessibility and UI Coverage and can only be set at the root.
- **Accessibility only**: `components` and `axeConfig` belong to Cypress Accessibility alone and are always set under the `accessibility` key. `components` shapes violation-target selectors; [`axeConfig`](/accessibility/configuration/axe-core-configuration) enables, disables, and scopes Axe Core® rules. UI Coverage has its own product-only options (`elements`, `elementGroups`, and interaction commands) set under a `uiCoverage` key. See the [UI Coverage configuration overview](/ui-coverage/configuration/overview) for those.

## Viewing Configuration for a Run

Every run permanently records the exact configuration it was processed with, so the runs themselves are the history of how your configuration has changed over time. You can review a run's configuration in Cypress Cloud, or read it programmatically with the Results API.

### In Cypress Cloud

To review the configuration a specific run used, open its **Properties** tab, shown in the [Setting Configuration](#Setting-Configuration) screenshot above. This displays the configuration as it was applied when the run was processed. When you open a run that was processed with an older configuration than the one currently saved, the report flags it with a "configuration updated" message, and you can [regenerate](#Setting-Configuration) the run to reprocess it with the current configuration.

### From the Results API

The [Accessibility Results API](/accessibility/connect-and-extend/results-api) exposes the applied configuration on the `config` property of its result, so you can read it in a CI workflow:

```js title="read-accessibility-config.js"
const { getAccessibilityResults } = require('@cypress/extract-cloud-results')

getAccessibilityResults().then((results) => {
  if (results.config) {
    // ISO timestamp of when the applied configuration was last saved
    console.log(results.config.updatedAt)

    // The App Quality configuration that was applied to the run
    console.log(results.config.value)
  }
})
```

If no configuration was applied to the run, `config` may be absent, so check for it before reading `value`.

## See also

- [Group & name views](/accessibility/configuration/views)
- [Exclude views](/accessibility/configuration/viewfilters)
- [Exclude elements](/accessibility/configuration/elementfilters)
- [Ignore rules per element](/accessibility/configuration/ignoring-rules-per-element)
- [Configure Axe Core® rules - `axeConfig`](/accessibility/configuration/axe-core-configuration)
- [Prioritize identifying attributes](/accessibility/configuration/significantattributes)
- [Ignore attributes for identification](/accessibility/configuration/attributefilters)
- [Define components](/accessibility/configuration/components)
- [Override config by run tag](/accessibility/configuration/profiles)
- [Cypress Accessibility FAQ](/accessibility/faq)

---

### Accessibility Connect And Extend Overview (`docs/accessibility/connect-and-extend/overview.mdx`)

---
title: 'Connect & extend Cypress Accessibility'
description: 'Ways to get Cypress Accessibility results out of Cypress Cloud and into your own files, pipelines, AI workflows, and reporting systems.'
sidebar_label: Overview
sidebar_position: 10
---

<ProductHeading product="accessibility" />

# Connect & extend

Cypress Accessibility results don't have to stay in Cypress Cloud. This section covers the ways to get a run's results into a file, a CI check, an AI agent, or a reporting system, so you can analyze and act on them wherever you already work.

## Ways to get your data

| Method                                                                | Best for                                                                                           | Interface                                      |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| [Download report](/accessibility/connect-and-extend/download-reports) | A one-off, manual export of a single run's violations for offline analysis, sharing, or AI agents. | `.csv` or `.json` file                         |
| [Webhooks](/accessibility/connect-and-extend/webhooks)                | Push Cypress Accessibility results to your own endpoint when the report finishes processing.       | `run.accessibility.completed`                  |
| [Results API](/accessibility/connect-and-extend/results-api)          | Automated pass/fail checks in CI that assert on results and block pull requests.                   | Node module (`@cypress/extract-cloud-results`) |
| [Cypress Cloud MCP](/cloud/integrations/cloud-mcp)                    | Live, interactive querying by AI agents while you work in your editor.                             | MCP tools                                      |
| [Data Extract API](/cloud/integrations/data-extract-api)              | Bulk analytics and trends across projects and over time, pulled into BI or a data warehouse.       | API and Enterprise Reporting downloads         |

## Which should I use?

- For a single run's results, use the [Download report](/accessibility/connect-and-extend/download-reports) button. The file works offline with any tool or AI agent.
- To enforce a standard in CI, use the [Results API](/accessibility/connect-and-extend/results-api) to assert on a run's results and [block pull requests](/accessibility/guides/block-pull-requests) that don't meet it.
- To work with an AI agent, use a [downloaded report](/accessibility/work-with-ai-agents#Work-with-a-downloaded-report) for the full dataset or [Cypress Cloud MCP](/accessibility/work-with-ai-agents#Cypress-Cloud-MCP) to query results live. See [Work with AI agents](/accessibility/work-with-ai-agents).
- To push results when a report finishes, use [Webhooks](/accessibility/connect-and-extend/webhooks). The `run.accessibility.completed` event can start other workflows in this list.
- To get results into your issue tracker, have an agent read the latest report for a branch, check what is already filed, and open only the missing tickets. See [File issues in your issue tracker](/accessibility/work-with-ai-agents#File-issues-in-your-issue-tracker).
- To track trends across runs and projects, use the [Data Extract API](/cloud/integrations/data-extract-api) and [Enterprise Reporting](/cloud/features/analytics/enterprise-reporting).

---

### Api Node Events Overview (`docs/api/node-events/overview.mdx`)

---
title: 'Overview of Node Events in Cypress'
description: 'Node event hooks enable you to tap into, modify, or extend the internal behavior of Cypress.'
sidebar_label: Overview
sidebar_position: 10
---

<ProductHeading product="app" />

# Node Events Overview

Node event hooks enable you to tap into, modify, or extend the internal behavior of
Cypress.

Normally, as a user, all of your test code, your application, and Cypress
commands are executed in the browser. But Cypress is also a Node process that
can be used to change the behavior of Cypress or to expose [plugins](/app/plugins/plugins-list) for others to consume.

> `setupNodeEvents` enables you to tap into the Node process running outside of the
> browser.

Node event hooks are a "seam" for you to write your own custom code that executes during
particular stages of the Cypress lifecycle.

## setupNodeEvents

The [`setupNodeEvents`](/app/references/configuration#setupNodeEvents)
function receives 2
arguments: [`on`](#on) and [`config`](#config). It can return a synchronous
value or can also return a Promise, which will be awaited until it resolves.
This enables you to perform asynchronous actions such as reading files in from
the filesystem.

If you return or resolve with an object, Cypress will then merge this object
into the `config` which enables you to overwrite configuration or environment
variables.

:::cypress-config-plugin-example

```ts
// configure plugins here
```

:::

### on

`on` is a function that you will use to register listeners on various **events**
that Cypress exposes.

Registering to listen on an event looks like this:

:::cypress-config-plugin-example

```ts
on('<event>', (arg1, arg2) => {
  // plugin stuff here
})
```

:::

#### List of events

Each event documents its own argument signature.

| Event                                                          | Description                                                                     |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [`after:run`](/api/node-events/after-run-api)                  | Occurs after the run is finished.                                               |
| [`after:screenshot`](/api/node-events/after-screenshot-api)    | Occurs after a screenshot is taken.                                             |
| [`after:spec`](/api/node-events/after-spec-api)                | Occurs after a spec is finished running.                                        |
| [`before:browser:launch`](/api/node-events/browser-launch-api) | Occurs immediately before launching a browser.                                  |
| [`before:run`](/api/node-events/before-run-api)                | Occurs before the run starts.                                                   |
| [`before:spec`](/api/node-events/before-spec-api)              | Occurs when a spec is about to be run.                                          |
| [`file:preprocessor`](/api/node-events/preprocessors-api)      | Occurs when a spec or spec-related file needs to be transpiled for the browser. |
| [`task`](/api/commands/task)                                   | Occurs in conjunction with the `cy.task` command.                               |

### config

`config` is the resolved
[Cypress configuration](/app/references/configuration) of the opened project.

This configuration contains all of the values that get passed into the browser
for your project.

Some plugins may use or require these values, so they can take certain
actions based on the configuration. If these values are programmatically
modified, Cypress will use the new values.

:::caution

The `config` object also includes the following extra values that are not part
of the standard configuration. **These values are read only and cannot be
modified from the plugins file.**

- `configFile`: The absolute path to the
  [Cypress configuration file](/app/references/configuration). See the
  [--config-file](/app/references/command-line#cypress-open) and
  [configFile](/app/references/module-api) docs for more information on this
  value.
- `projectRoot`: The absolute path to the root of the project (e.g.
  `/Users/me/dev/my-project`).
- `version`: The version number of Cypress. This can be used to handle breaking
  changes.

:::

[Check out our API docs for modifying configuration here.](/api/node-events/configuration-api)

## Use Cases

### Configuration

Hooking into node events programmatically alters the resolved configuration and
environment variables that come from the
[Cypress configuration file](/app/references/configuration),
[`cypress.env.json`](/app/guides/environment-variables#2-cypressenvjson),
the [command line](/app/references/command-line), or system environment
variables.

This enables you to do things like:

- Use multiple environments with their own configurations
- Swap out environment variables based on an environment
- Read in configuration files using the built in `fs` lib
- Change the list of browsers used for testing
- Write your configuration in `yml`

Check out our [Configuration API docs](/api/node-events/configuration-api) which
describe how to use this event.

### Preprocessors

The event `file:preprocessor` is used to customize how your test code is
transpiled and sent to the browser. By default, Cypress handles ES2015+ and
TypeScript, using webpack to package it for the browser.

You can use the `file:preprocessor` event to do things like:

- Add the latest ES\* support.
- Write your test code in ClojureScript.
- Customize the Babel settings to add your own plugins.
- Customize the options for compiling TypeScript.
- Swap out Webpack for Vite or anything else.

Check out our [File Preprocessor API docs](/api/node-events/preprocessors-api) which
describe how to use this event.

### Run Lifecycle

The events [`before:run`](/api/node-events/before-run-api) and
[`after:run`](/api/node-events/after-run-api) occur before and after a run,
respectively.

You can use [`before:run`](/api/node-events/before-run-api) to do things like:

- Set up reporting on a run
- Start a timer for the run to time how long it takes

You can use [`after:run`](/api/node-events/after-run-api) to do things like:

- Finish up reporting on a run set up in `before:run`
- Stop the timer for the run set up in `before:run`

### Spec Lifecycle

The events [`before:spec`](/api/node-events/before-spec-api) and
[`after:spec`](/api/node-events/after-spec-api) run before and after a single spec
is run, respectively.

You can use [`before:spec`](/api/node-events/before-spec-api) to do things like:

- Set up reporting on a spec running
- Start a timer for the spec to time how long it takes

You can use [`after:spec`](/api/node-events/after-spec-api) to do things like:

- Finish up reporting set up in `before:spec`.
- Stop the timer for the spec set up in `before:spec`.
- Delete the video recorded for the spec. This prevents it from taking time and
  computing resources for compressing and uploading the video. You can do this
  conditionally based on the results of the spec, such as if it passes (so
  videos for failing tests are preserved for debugging purposes).

Check out the [Before Spec API doc](/api/node-events/before-spec-api) and
[After Spec API doc](/api/node-events/after-spec-api) which describe how to use
these events.

### Browser Launching

The event `before:browser:launch` can be used to modify the launch arguments for
each particular browser.

You can use the `before:browser:launch` event to do things like:

- Load a Chrome extension
- Enable or disable experimental chrome features
- Control which Chrome components are loaded

:::caution

<strong>Loading extensions in Chrome 137 and above</strong>

Standard, Chrome-branded browsers (for example, regular Google Chrome) version
137 and above can no longer load extensions through the `before:browser:launch`
event. This is because Chrome removed support for the `--load-extension` command
line flag that Cypress relied on to load extensions.

To continue loading extensions, run your tests in
[Chrome for Testing](/app/references/launching-browsers#Chrome-Browsers) or
Chromium, which still support extension loading.

:::

Check out our [Browser Launch API docs](/api/node-events/browser-launch-api) which
describe how to use this event.

### Screenshot handling

The event `after:screenshot` is called after a screenshot is taken and saved to
disk.

You can use the `after:screenshot` event to do things like:

- Save details about the screenshot
- Rename the screenshot
- Manipulate the screenshot image by resizing or cropping it

Check out our [After Screenshot API docs](/api/node-events/after-screenshot-api)
which describe how to use this event.

### cy.task

The event `task` is used in conjunction with the
[`cy.task()`](/api/commands/task) command. It runs arbitrary code in Node to
accomplish tasks that aren't possible in the browser.

You can use the `task` event to do things like:

- Manipulating a database (seeding, reading, writing, etc.)
- Storing state in Node that you want persisted (since the driver is fully
  refreshed on visits)
- Performing parallel tasks (like making multiple http requests outside of
  Cypress)
- Running an external process (like spinning up a Webdriver instance of another
  browser like Safari or puppeteer)

## Execution context

The [`setupNodeEvents`](/app/references/configuration#setupNodeEvents)
function is invoked
when Cypress opens a project.

Cypress does this by spawning an independent `child_process` which then
`requires` the [Cypress configuration file](/app/references/configuration).
This is similar to the way Visual Studio Code or Atom works.

This code will be executed using the Node version that launched Cypress.

### npm modules

When Cypress executes the
[`setupNodeEvents`](/app/references/configuration#setupNodeEvents) function
it will execute with
`process.cwd()` set to your project's path. Additionally - you will be able to
`require` **any node module** you have installed, including local files inside
your project.

For example, if your `package.json` looked like this:

```json
{
  "name": "My Project",
  "dependencies": {
    "debug": "x.x.x"
  },
  "devDependencies": {
    "lodash": "x.x.x"
  }
}
```

Then you could do any of the following in your `setupNodeEvents` function:

:::cypress-config-plugin-example

```ts
const _ = require('lodash') // yup, dev dependencies
const path = require('path') // yup, core node library
const debug = require('debug') // yup, dependencies
const User = require('./lib/models/user') // yup, relative local modules

console.log(__dirname) // /Users/janelane/Dev/my-project
console.log(process.cwd()) // /Users/janelane/Dev/my-project
```

:::

## Error handling

The [Cypress configuration file](/app/references/configuration) is loaded in
its own child process so it is isolated away from the context that Cypress
itself runs in. That means you cannot accidentally modify or change Cypress's
own execution in any way.

If your [`setupNodeEvents`](/app/references/configuration#setupNodeEvents)
function has an
uncaught exception, an unhandled rejection from a promise, or a syntax error -
Cypress will automatically catch those and display them to you inside of the
console and even in Cypress itself.

Errors in your `setupNodeEvents` function _will not crash_ Cypress.

## File changes

Normally when writing code in Node, you typically have to restart the process
after changing any files.

Cypress automatically watches your
[Cypress configuration file](/app/references/configuration) and any changes
made will take effect immediately. We will read the file in and execute the
exported function again.

This enables you to iterate on plugin code even with Cypress already running.

## <Icon name="graduation-cap" /> Real World Example

The <Icon name="github" inline="true" contentType="rwa" /> uses
[tasks](/api/commands/task) to re-seed its database, and to filter/find test
data for various testing scenarios.

<WarningSetupNodeEvents />

:::cypress-config-plugin-example

```ts
on('task', {
  async 'db:seed'() {
    // seed database with test data
    const { data } = await axios.post(`${testDataApiEndpoint}/seed`)
    return data
  },

  // fetch test data from a database (MySQL, PostgreSQL, etc...)
  'filter:database'(queryPayload) {
    return queryDatabase(queryPayload, (data, attrs) =>
      _.filter(data.results, attrs)
    )
  },
  'find:database'(queryPayload) {
    return queryDatabase(queryPayload, (data, attrs) =>
      _.find(data.results, attrs)
    )
  },
})
```

:::

:::note

_<Icon name="github" /> Source:
[Real World App > cypress.config.ts](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress.config.ts)_

:::

Check out the
[Real World App test suites](https://github.com/cypress-io/cypress-realworld-app/tree/develop/cypress/tests/ui)
to see these tasks in action.

---

### App Ai Overview (`docs/app/ai/overview.mdx`)

---
title: 'AI in Cypress: test generation, agent skills, and agentic debugging'
description: 'A map of every AI capability in Cypress: author tests with Cypress Studio and cy.prompt, give AI coding agents real Cypress context with skills and Cloud MCP, and analyze runs with Cypress AI.'
sidebar_label: AI in Cypress
sidebar_position: 10
slug: /app/ai/overview
---

<ProductHeading product="app" />

# AI in Cypress

AI shows up in Cypress in two distinct ways, and knowing which one you need is
the fastest route to the right page.

**AI that writes tests for you.** You are still the author. Cypress Studio and
[`cy.prompt`](/api/commands/prompt) turn recorded interactions or plain language
into real Cypress commands, so less of your time goes to boilerplate and
selector archaeology.

**Cypress made legible to your agents.** Here your AI coding tool is the
consumer. Skills, `cypress tap`, Cloud MCP, and agent-ready reports give an
agent accurate Cypress context, so it produces tests that follow your
conventions instead of generic ones that break in CI.

Most teams end up using both. The rest of this page is a map of what exists in
each half.

## Write tests with AI

Both options below produce ordinary Cypress code that you can read, edit, and
commit. Neither is a black box: `cy.prompt` exposes the generated commands in
the Command Log, and Studio writes directly into your spec file.

- **[Cypress Studio](/app/guides/cypress-studio)** records real interactions in
  your app and turns them into end-to-end tests. Connected to Cypress Cloud,
  Studio AI also recommends assertions as you record. Reach for it when you want
  to author a test by clicking through your app.
- **[Generate tests with `cy.prompt`](/app/guides/ai-test-generation)** turns
  natural language steps into executable Cypress commands, and can keep them
  working as your UI changes. Reach for it when describing a flow is faster than
  recording one.

## Give agents Cypress context

An AI coding agent that knows nothing about Cypress writes tests that look
plausible and then fail in CI: brittle selectors, arbitrary waits, and
assertions that do not retry. These capabilities give it better information to
work from.

This walkthrough follows an AI coding agent through the full agentic testing
loop with Cypress. Skills teach it to write Cypress tests, `cypress tap` lets it
build and verify them against a live session, the Cloud CLI triages failed CI
runs from the terminal, and Cloud MCP brings full run context, including UI
Coverage and Cypress Accessibility results, into your editor.

<DocsVideo
  src="https://www.youtube.com/embed/TD0u9ayqXXE"
  title="Agentic Testing with Cypress: Turn Your AI Agent Into a Testing Teammate"
/>

- **[Cypress skills for AI agents](/app/tooling/ai-skills)** teach your coding
  agent to write, review, and explain tests the way an experienced Cypress
  engineer would. Install them once per project.
- **[`cypress tap`](/app/tooling/cypress-tap)** attaches your agent to a running
  open mode session from the terminal, so it can run a spec and then read the
  Command Log, the error, and the DOM as the Cypress app shows them. That closes
  the loop: the agent can verify its own fix instead of reporting pass or fail.
  The [`cypress-tap` skill](/app/tooling/ai-skills#cypress-tap) packages this
  workflow so your agent drives it correctly.
- **[Cloud MCP](/cloud/integrations/cloud-mcp)** connects your agent to Cypress
  Cloud so it can read real run results, failures, and
  [Test Replay](/cloud/features/test-replay) data while you work, rather than
  guessing at why something failed.
- **[Cloud CLI](/cloud/integrations/cloud-cli)** is the scriptable counterpart
  to Cloud MCP: the same Cloud run data as JSON in the terminal, for agents that
  work through a shell and for your own automation. The
  [`cypress-cloud-cli` skill](/app/tooling/ai-skills#cypress-cloud-cli) instructs
  your agent on how to work through that recorded run and test data to find a
  failure's root cause.

## Analyze and debug with AI

- **[Cypress AI](/cloud/features/cypress-ai-features)** explains failures and
  summarizes test intent across recorded runs in Cypress Cloud.
- **[Work with AI agents in Cypress Accessibility](/accessibility/work-with-ai-agents)**
  and **[Work with AI agents in UI Coverage](/ui-coverage/work-with-ai-agents)**
  cover tuning those reports so an agent can act on them, then prompting it to
  triage findings and plan the work.

## What each capability needs

**No AI capability in Cypress requires a paid subscription.** Everything below
works on the free
[Starter plan](https://www.cypress.io/pricing?utm_source=docs.cypress.io&utm_medium=ai-overview),
and some of it never touches Cypress Cloud at all. The exceptions are the
agent-ready reports at the bottom of the table, which come with the Cypress
Accessibility and UI Coverage solutions rather than with a Cloud plan.

Paying raises limits rather than unlocking capabilities: a paid plan gets you a
larger `cy.prompt` execution allowance and higher hourly limits on `cy.prompt`
and Studio AI. See
[AI usage limits](/cloud/features/cypress-ai-features#Usage-limits) for the
numbers.

| Capability                              | Where it runs | Cypress Cloud account |              Paid plan              |
| --------------------------------------- | :-----------: | :-------------------: | :---------------------------------: |
| Cypress Studio recording                |  Cypress App  |      Not needed       |                 No                  |
| Studio AI assertion suggestions         |  Cypress App  |    Free plan works    |                 No                  |
| `cy.prompt`                             |  Cypress App  |    Free plan works    |                 No                  |
| Cypress skills for AI agents            |  Your editor  |      Not needed       |                 No                  |
| `cypress tap`                           | Your terminal |      Not needed       |                 No                  |
| Cloud MCP                               |  Your editor  |    Free plan works    |                 No                  |
| Cloud CLI                               | Your terminal |    Free plan works    |                 No                  |
| Cypress AI failure and intent summaries | Cypress Cloud |    Free plan works    |                 No                  |
| Agent-ready accessibility reports       | Cypress Cloud |          Yes          | Included with Cypress Accessibility |
| Agent-ready coverage reports            | Cypress Cloud |          Yes          |      Included with UI Coverage      |

The capabilities that need a Cloud account need one because Cypress Cloud is
what routes their AI requests securely, applies your organization's controls,
and tracks usage. See
[Why do I need a Cloud account?](/cloud/features/cypress-ai-features#Why-do-I-need-a-Cloud-Account)

Organization admins and owners can turn AI capabilities on or off for everyone
in the organization. See
[Disabling AI features](/cloud/features/cypress-ai-features#Disabling-AI-features).

## See also

- [`cy.prompt()`](/api/commands/prompt) - the command reference
- [Cypress Studio](/app/guides/cypress-studio)
- [Cypress skills for AI agents](/app/tooling/ai-skills)
- [`cypress tap`](/app/tooling/cypress-tap)
- [Cloud MCP](/cloud/integrations/cloud-mcp)
- [Cloud CLI](/cloud/integrations/cloud-cli)
- [Cypress AI](/cloud/features/cypress-ai-features) - availability, usage limits,
  and pricing for every AI capability

---

### Ui Coverage Configuration Overview (`docs/ui-coverage/configuration/overview.mdx`)

---
title: Configure UI Coverage in Cypress
description: 'Configure Cypress UI Coverage to get a coverage score you can trust: ignore dynamic attributes, filter out noise, group elements, shape views, and count the interactions that matter.'
sidebar_label: Overview
sidebar_position: 10
---

<ProductHeading product="ui-coverage" />

# Configuration overview

UI Coverage works out of the box with no setup, but a few lines of configuration make your reports match your application. Configuration lets you get a coverage score you can trust and act on by:

- **Reflecting your app, not the framework**: ignore dynamic or auto-generated attributes so the same button is recognized as one element across snapshots instead of many.
- **Removing noise**: filter out third-party widgets, admin-only pages, and elements your team doesn't own so the report focuses on what matters.
- **Organizing reports around your product**: group related elements and shape how URLs roll up into [views](/ui-coverage/core-concepts/views) that map to real pages and flows.
- **Counting the interactions you care about**: recognize custom or plugin commands, require a meaningful interaction on specific elements, and even credit assertions as coverage.

You don't need any of this to get started, and you can add it incrementally. Reprocess a past run after each change to see the effect immediately, without re-running your tests.

<UICovPremiumNote />

## Setting configuration

<AppQualityConfigEditing />

<DocsImage
  src="/img/ui-coverage/configuration/cypress-ui-coverage-configuration-editor.png"
  alt="The Cypress Cloud UI showing the configuration editor"
/>

After you save configuration changes, you can reprocess any historical run to apply them. You can start a reprocess from two places:

- The **Properties** tab, using the "regenerate" button next to the configuration values that were used for that run.
- The UI Coverage report, using the "configuration updated" message that appears when you view a historical run that was processed with an older configuration.

Regenerating reports in this way applies config changes and shows their effects without running your Cypress tests again.

<AppQualityConfigWhoCanEdit />

## Configuration options

:::info

<Icon name="book-open-reader" /> For a quick overview of the practical
application of the most common UI Coverage configuration properties, you can
read [this blog
post](https://www.cypress.io/blog/making-the-most-of-ui-coverage?utm_source=docs.cypress.io&utm_medium=ui-coverage-configuration).

:::

### Which option do I need?

Several options change what appears in reports and how it's organized. Pick the one that matches your goal:

| Your goal                                                           | Use                                                                                                         |
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Control how URLs are grouped into views                             | [`views`](/ui-coverage/configuration/views)                                                                 |
| Remove entire views from reports                                    | [`viewFilters`](/ui-coverage/configuration/viewfilters)                                                     |
| Remove elements from reports and scores entirely                    | [`elementFilters`](/ui-coverage/configuration/elementfilters)                                               |
| Rename or stabilize the identity of a single element                | [`elements`](/ui-coverage/configuration/elements)                                                           |
| Combine repeated or related elements so they count as one           | [`elementGroups`](/ui-coverage/configuration/elementgroups)                                                 |
| Define groups in your application's markup instead of configuration | [`data-cy-ui-group` attribute](/ui-coverage/core-concepts/element-grouping#Grouping-with-markup-attributes) |
| Prioritize your own attributes for identifying and naming elements  | [`significantAttributes`](/ui-coverage/configuration/significantattributes)                                 |
| Stop dynamic or generated attributes from identifying elements      | [`attributeFilters`](/ui-coverage/configuration/attributefilters)                                           |
| Count your custom commands as interactions                          | [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands)                 |
| Limit which interaction commands count for specific elements        | [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands)                       |
| Apply different configuration to runs based on run tags             | [`profiles`](/ui-coverage/configuration/profiles)                                                           |

### Comments

Most configuration rules support an optional `comment` property that you can use to record why a value is set. This makes your configuration easier to understand and maintain, especially when working in a team or revisiting configuration after some time. Any rule defined as an object accepts a `comment`; the options that are plain lists of strings, such as [`significantAttributes`](/ui-coverage/configuration/significantattributes) and [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands), do not take a per-entry comment.

A `comment` lives inside the rule and has no effect on behavior. Comments appear only in the configuration itself and are never displayed in reports. Because Cypress Cloud validates every rule and rejects properties it doesn't recognize, `comment` is the supported place to keep notes.

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": ".intercom-launcher",
      "include": false,
      "comment": "Third-party chat widget, not covered by our tests"
    }
  ]
}
```

### Full configuration reference

The shape of every available option, with the type each value expects:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## How rules are applied

Two behaviors govern the rules you write:

- **Order matters** for [`views`](/ui-coverage/configuration/views), [`viewFilters`](/ui-coverage/configuration/viewfilters), [`elementFilters`](/ui-coverage/configuration/elementfilters), [`elementGroups`](/ui-coverage/configuration/elementgroups), [`attributeFilters`](/ui-coverage/configuration/attributefilters), and [`profiles`](/ui-coverage/configuration/profiles): rules are evaluated top to bottom and the **first** rule that matches an element or URL wins; later rules that also match it are ignored. List specific rules before broad, catch-all rules, and place an `include: true` exception above the `include: false` rule it should override. Two properties differ: for [`elements`](/ui-coverage/configuration/elements) the **last** matching rule wins, and for [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands), order has no effect.
- **Unknown properties are rejected.** When you save, Cypress Cloud validates your configuration against a strict schema and rejects anything it doesn't recognize, such as a misspelled property, a value of the wrong type, or a note on a property that doesn't accept one. Correct the flagged property to save, and keep freeform notes in a [`comment`](#Comments).

## Configuration scope

Some properties are shared across App Quality products, and some belong to UI Coverage alone.

- **Shared properties**: `elementFilters`, `viewFilters`, `attributeFilters`, and `significantAttributes` apply to both UI Coverage and Cypress Accessibility when set at the root of your configuration. To apply one to a single product, nest it under a `uiCoverage` or `accessibility` key. A nested value **completely replaces** the root-level value for that product (the two are not merged), so repeat any shared rules you still want in the nested list. To disable a shared property for one product, nest an empty list (`"elementFilters": []`) rather than `null`, which falls back to the root value.
- **Shared, but not nestable**: `views` applies to both UI Coverage and Cypress Accessibility and can only be set at the root.
- **UI Coverage only**: `elementGroups`, `elements`, `additionalInteractionCommands`, and `allowedInteractionCommands` are specific to UI Coverage and are always set under the `uiCoverage` key.

## Viewing configuration for a run

Every run permanently records the exact configuration it was processed with, so the runs themselves are the history of how your configuration has changed over time. You can review a run's configuration in Cypress Cloud, or read it programmatically with the Results API.

### In Cypress Cloud

To review the configuration a specific run used, open its **Properties** tab, as shown below. This displays the configuration as it was applied when the run was processed. When you open a run that was processed with an older configuration than the one currently saved, the report flags it with a "configuration updated" message, and you can [regenerate](#Setting-configuration) the run to reprocess it with the current configuration.

<DocsImage
  src="/img/accessibility/configuration/cypress-cloud-properties-tab-application-quality-config.png"
  alt="The properties tab for a run, with an Application Quality section at the bottom"
/>

### From the Results API

The [UI Coverage Results API](/ui-coverage/results-api) exposes the applied configuration on the `config` property of its result, so you can read it in a CI workflow:

```js
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults().then((results) => {
  if (results.config) {
    // ISO timestamp of when the applied configuration was last saved
    console.log(results.config.updatedAt)

    // The App Quality configuration that was applied to the run
    console.log(results.config.value)
  }
})
```

If no configuration was applied to the run, `config` may be absent, so check for it before reading `value`.

## See also

- [Views](/ui-coverage/configuration/views)
- [View Filters](/ui-coverage/configuration/viewfilters)
- [Element Filters](/ui-coverage/configuration/elementfilters)
- [Elements](/ui-coverage/configuration/elements)
- [Element Groups](/ui-coverage/configuration/elementgroups)
- [Significant Attributes](/ui-coverage/configuration/significantattributes)
- [Attribute Filters](/ui-coverage/configuration/attributefilters)
- [Additional Interaction Commands](/ui-coverage/configuration/additionalinteractioncommands)
- [Allowed Interaction Commands](/ui-coverage/configuration/allowedinteractioncommands)
- [Profiles](/ui-coverage/configuration/profiles)

---

### App Run Tests Continuous Integration Overview (`docs/app/run-tests/continuous-integration/overview.mdx`)

---
title: 'Continuous Integration with Cypress: Run Tests in CI'
description: 'Set up Cypress in CI: install and run commands, boot your server, record to Cypress Cloud, run in parallel, and use Cypress Docker images on any CI provider.'
sidebar_label: CI overview
sidebar_position: 10
slug: /app/continuous-integration/overview
---

<ProductHeading product="app" />

# Continuous Integration with Cypress

Cypress runs in any continuous integration (CI) provider, including GitHub
Actions, CircleCI, GitLab CI, Jenkins, and AWS CodeBuild. Running your Cypress
tests on every push and pull request catches regressions before they reach
your users, and recorded results show you exactly what happened when a test
fails.

Setting it up takes two commands: install Cypress, then run it. This guide
covers those commands and everything around them: booting your app's server,
choosing a Docker image, caching, parallelization, and setup guides for each
major CI provider.

## What is Continuous Integration?

Continuous integration is the practice of merging code changes into a shared
repository frequently, where each change is verified by an automated build and
test run. When Cypress is part of that pipeline, every commit runs your
end-to-end and component tests against your application, so a change that
breaks a user flow fails the build instead of shipping.

<DocsVideo
  src="https://youtube.com/embed/USX6AntcPyg"
  title="GitHub Actions + Cypress: What is Continuous Integration?"
/>

## Setting up CI

<DocsVideo
  src="https://youtube.com/embed/saYovXS9Llk"
  title="Continuous Integration with Cypress"
/>

### Install and run Cypress

Running Cypress in CI is almost the same as running it locally in your
terminal. You generally only need to do two things:

1. **Install Cypress**

<CypressInstallCommands />

2. **Run Cypress**

<CypressRunCommands />

Where these commands go depends on your CI provider: each defines its own
configuration file format for the steps in a build. Refer to your CI
provider's documentation for where to add the commands to install and run
Cypress, or start from one of our [CI examples](#CI-Examples).

### Boot your server

Typically you will need to boot a local server before running Cypress. A web
server is a **long running process** that never exits, so you need to run it
in the **background** or your CI provider will never move on to the next
command. You also need to wait for the server to be ready before Cypress
starts. A command like this has a race condition:

```shell
npm start & npx cypress run # don't do this
```

There is no guarantee that your server has booted by the time `cypress run`
executes, so your tests may try to visit your local server before it is ready.
Instead of adding an arbitrary wait (like `sleep 20`), use a tool that waits
for the server to respond.

:::tip

If you run your tests with the official
[Cypress GitHub Action](https://github.com/cypress-io/github-action), its
`start` and `wait-on` options boot and wait for your server without any extra
packages. See our
[GitHub Actions guide](/app/continuous-integration/github-actions).

:::

#### `start-server-and-test` module

The [start-server-and-test](https://github.com/bahmutov/start-server-and-test)
module starts your server, waits until a URL responds, runs your test command,
and shuts the server down when the tests finish.

<PackageManagerTabs install="start-server-and-test" dev />

In your `package.json` scripts, pass the command that boots your server, the
URL your server is hosted on, and your Cypress test command.

```json title="package.json"
{
  "scripts": {
    "start": "my-server -p 3030",
    "cy:run": "cypress run",
    "test": "start-server-and-test start http://localhost:3030 cy:run"
  }
}
```

In the example above, the `cy:run` command will only be executed when the URL
`http://localhost:3030` responds with an HTTP status code of 200. The server
also shuts down when the tests complete.

**Gotchas**

When
[working with `webpack-dev-server`](https://github.com/bahmutov/start-server-and-test#note-for-webpack-dev-server-users)
or another server that does not respond to `HEAD` requests, use an explicit
`GET` method to ping the server like this:

```json title="package.json"
{
  "scripts": {
    "test": "start-server-and-test start http-get://localhost:3030 cy:run"
  }
}
```

When working with local `https` in webpack, set a system environment variable
to allow the local certificate:

```json title="package.json"
{
  "scripts": {
    "start": "my-server -p 3030 --https",
    "cy:run": "cypress run",
    "cy:ci": "START_SERVER_AND_TEST_INSECURE=1 start-server-and-test start https-get://localhost:3030 cy:run"
  }
}
```

#### `wait-on` module

If you'd rather manage the server process yourself, the
[wait-on](https://github.com/jeffbski/wait-on) module blocks until a URL
responds. Background the server, wait for it, then run Cypress:

```shell
npm start & npx wait-on http://localhost:8080
```

```shell
npx cypress run
```

:::info

Most CI providers automatically kill background processes, so you don't have
to worry about cleaning up your server process once Cypress finishes.

However, if you're running this script locally you'll have to do a bit more
work to collect the backgrounded PID and then kill it after `cypress run`.

:::

#### `concurrently` module

A general-purpose process runner like
[concurrently](https://github.com/open-cli-tools/concurrently) can compose the
same flow: start the server and a `wait-on`-gated test command together, kill
the server when the tests finish (`-k`), and pass or fail based on the test
command alone (`-s first`).

```shell
npx concurrently -k -s first "npm start" "npx wait-on http://localhost:8080 && npx cypress run"
```

### Record tests

Cypress can record your test runs and make the results available in
[Cypress Cloud](/cloud/get-started/introduction), giving you insight into what
happened when your tests ran in CI.

With recorded tests, you can:

- See the number of failed, pending, and passing tests.
- Debug failures with [Test Replay](/cloud/features/test-replay), which
  captures the state of your application so you can inspect the DOM, network
  requests, and console logs at every step of the failed test.
- Get the entire stack trace of failed tests, or hand that same failure
  context to your AI coding agent through
  [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) so it can debug the
  failing run for you.
- View screenshots taken when tests fail and when using
  [`cy.screenshot()`](/api/commands/screenshot).
- Detect and manage [flaky tests](/cloud/features/flaky-test-management) that
  pass and fail across recorded runs.
- Analyze trends in your test suite with
  [Analytics](/cloud/features/analytics/overview), like run duration,
  most common errors, and slowest tests.
- Generate [UI Coverage](/ui-coverage/get-started/introduction) and
  [Cypress Accessibility](/accessibility/get-started/introduction) reports
  from your recorded runs with no additional test code or configuration
  (premium solutions).
- See which machines ran each test when
  [parallelized](/cloud/features/smart-orchestration/parallelization).

To record tests:

1. [Set up your project to record](/cloud/get-started/setup#Setup) and copy
   your record key.
2. [Pass the `--record` flag to `cypress run`](/app/references/command-line#cypress-run)
   within CI, along with the record key, either inline with the `--key` flag
   or via the
   [`CYPRESS_RECORD_KEY` environment variable](#Environment-variables).

<CypressCommandTabs command="run --record --key=abc123" />

[Read the full guide on Cypress Cloud.](/cloud/get-started/introduction)

### Run tests in parallel

Cypress can run tests in parallel across multiple machines, cutting your total
run time roughly in proportion to the number of machines.

You'll want to refer to your CI provider's documentation on how to set up
multiple machines to run in your CI environment.

Once multiple machines are available within your CI environment, you can pass
the [--parallel](/app/references/command-line#cypress-run-parallel) flag to
have your tests run in parallel. Parallelization requires recording to
[Cypress Cloud](/cloud/get-started/introduction), which load-balances specs
across your machines.

<CypressCommandTabs command="run --record --key=abc123 --parallel" />

[Read the full guide on parallelization.](/cloud/features/smart-orchestration/parallelization)

## Cypress Docker Images

CI providers, such as [GitHub Actions](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container) and
[CircleCI](https://circleci.com/docs/executor-intro/#docker), allow workflows to run using
[Docker container images](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/).

Cypress supports the use of [Docker](https://docs.docker.com/get-started/docker-overview/)
through the provisioning of official [Cypress Docker images](https://github.com/cypress-io/cypress-docker-images).
Images are Linux-based and support the following platforms:

- Linux/amd64
- Linux/arm64

Cypress Docker images provide a consistent environment tailored for use with
Cypress. By choosing an appropriate Cypress Docker image, you determine the
exact environment that your Cypress tests run in. This shields your workflows
from version updates made by your CI provider, for instance if they update
Node.js or browser versions.

Cypress Docker images are available from:

- [Docker Hub](https://hub.docker.com/u/cypress)
- [Amazon ECR (Elastic Container Registry) Public Gallery](https://gallery.ecr.aws/cypress-io)

### Cypress Docker variants

- [cypress/base](https://github.com/cypress-io/cypress-docker-images/tree/master/base) is the entry-level Cypress Docker image. To test in an installed browser such as Chrome or Firefox, use the `cypress/browsers` image described below.
  It contains a complete Linux (Debian) operating system, together with the
  [prerequisite operating system packages](/app/get-started/install-cypress#UbuntuDebian) for Cypress,
  Node.js, npm, and Yarn v1 Classic.
  An image `<tag>` gives you the choice of Node.js version.

- [cypress/browsers](https://github.com/cypress-io/cypress-docker-images/tree/master/browsers) builds on the
  [cypress/base](https://github.com/cypress-io/cypress-docker-images/tree/master/base) image.
  For `Linux/amd64` images it adds **Chrome**, **Firefox**, and **Edge** browsers.
  For `Linux/arm64` images it adds **Firefox** browsers from version `136` and above, and
  **Chrome** browsers from version `151` and above.
  Edge browsers are currently not available for `Linux/arm64`.
  A corresponding image `<tag>` allows selection of the combined Node.js and browser versions.
  The version tag for the unavailable Edge browser on the `Linux/arm64` platform is an empty place-holder only,
  required for multi-platform support compatibility.

- [cypress/included](https://github.com/cypress-io/cypress-docker-images/tree/master/included) builds on the
  [cypress/browsers](https://github.com/cypress-io/cypress-docker-images/tree/master/browsers) image.
  It adds a fixed version of **Cypress**, globally installed by npm.
  A short-form image `<tag>` selects the version of Cypress.
  A corresponding long-form `<tag>` selects the version of Cypress and documents the combined Node.js and browser versions.

- [cypress/factory](https://github.com/cypress-io/cypress-docker-images/tree/master/factory)
  provides the base operating system image and allows individual selection of other components
  by version. It is used to generate customized Docker images.

### CI Docker examples

You can find examples that use Cypress Docker images below:

- [cypress-docker-images examples](https://github.com/cypress-io/cypress-docker-images/blob/master/README.md#examples)
- [cypress-example-kitchensink](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/README.md)
- [Real World App - CircleCI](https://github.com/cypress-io/cypress-realworld-app/blob/develop/.circleci/config.yml)
- [Real World App - GitHub Actions](https://github.com/cypress-io/cypress-realworld-app/blob/develop/.github/workflows/main.yml)
- [cypress-docker-images - GitHub Actions](https://github.com/cypress-io/cypress-docker-images/blob/master/.github/workflows/example-cypress-github-action.yml)

## CI Examples

We maintain in-depth setup guides for the most popular CI providers, and
working example configurations for many others.

### AWS Amplify Console

- [Basic Example (amplify.yml)](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/amplify.yml)

### AWS CodeBuild

Read our extensive guide on how to set up Cypress in [AWS CodeBuild](/app/continuous-integration/aws-codebuild).

### Azure Pipelines

- [Basic Example (azure-ci.yml)](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/basic/azure-ci.yml)
- [Parallelized Example (azure-ci.yml)](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/azure-ci.yml)

### Bitbucket Pipelines

Read our extensive guide on how to set up Cypress in [Bitbucket Pipelines](/app/continuous-integration/bitbucket-pipelines).

### Buildkite

- [Parallel Example](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/.buildkite/pipeline.yml)

### CircleCI

Read our extensive guide on how to set up Cypress in [CircleCI](/app/continuous-integration/circleci).

### GitHub Actions

Read our extensive guide on how to set up Cypress in [GitHub Actions](/app/continuous-integration/github-actions).

### GitLab

Read our extensive guide on how to set up Cypress in [GitLab](/app/continuous-integration/gitlab-ci).

### Jenkins

- [Basic Jenkinsfile](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/basic/Jenkinsfile)
- [Parallel Jenkinsfile](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/Jenkinsfile)

### Netlify

Use our official
[netlify-plugin-cypress](https://github.com/cypress-io/netlify-plugin-cypress)
to execute end-to-end tests before and after deployment to the Netlify
platform.

### Semaphore

- [Basic .semaphore.yml](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/basic/.semaphore.yml)
- [Parallel .semaphore.yml](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/.semaphore/semaphore.yml)

### TravisCI

- [Basic .travis.yml](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/basic/.travis.yml)
- [Parallel .travis.yml](https://github.com/cypress-io/cypress-example-kitchensink/blob/master/.travis.yml)

## Advanced setup

### Machine requirements

Hardware requirements to run Cypress depend on how much memory the browser,
the application under test, and the server (if running it locally) need to run
the tests without crashing. Visit our
[System Requirements](/app/get-started/install-cypress#System-requirements)
guide for minimum hardware recommendations.

**Some signs that your machine may not have enough CPU or memory to run
Cypress:**

- The recorded video artifacts have random pauses or dropped frames.
- [Debug logs of the CPU and memory](/app/references/troubleshooting#Log-memory-and-CPU-usage)
  frequently show CPU percent above 100%.
- The browser crashes.

You can see the total available machine memory and the current free memory by
running the [`cypress info`](/app/references/command-line#cypress-info)
command.

```css
npx cypress info
...
Cypress Version: 15.18.1 (stable)
System Platform: linux (Debian - 12)
System Memory: 73.6 GB free 48.6 GB
```

You can see the CPU parameters on the CI machines by executing the command
below.

```shell
node -p 'os.cpus()'
[
  {
    model: 'Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz',
    speed: 3399,
    times: { user: 760580, nice: 1010, sys: 158130, idle: 1638340, irq: 0 }
  }
  ...
]
```

**Example projects and the machine configurations used to run them on CI:**

- The [Real World App](https://github.com/cypress-io/cypress-realworld-app)
  project runs tests on a CircleCI machine using the
  [Docker executor](https://circleci.com/docs/executor-intro/#docker) with
  [`resource_class: large`](https://circleci.com/docs/configuration-reference/#docker-execution-environment)
  providing 4 vCPUs and 8 GB of RAM. `cypress info` reports
  `System Memory: 73.6 GB free 48.6 GB`.
- The [Real World App](https://github.com/cypress-io/cypress-realworld-app) project also
  executes its tests on
  [GitHub Actions](https://docs.github.com/en/actions) using the
  [Cypress GitHub Action](https://github.com/cypress-io/github-action) with the
  [standard Ubuntu GitHub-hosted runner for Public repositories](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners)
  providing 4 vCPUs and 16 GB of RAM. `cypress info` reports
  `System Memory: 16.8 GB free 15.5 GB` with CPUs reported as
  `AMD EPYC 7763 64-Core Processor`.

**Tip:** if there are problems with longer specs, try splitting them into
shorter ones.

### Dependencies

Cypress runs on many CI providers' virtual machine environments out-of-the-box without needing additional dependencies installed.

#### Linux

If you see a message about a missing dependency when you run Cypress in a Linux CI environment, then refer to the [Linux Prerequisites](/app/get-started/install-cypress#Linux-Prerequisites) lists for guidance.

### Caching

Cypress downloads its binary to the global system cache - on Linux that is
`~/.cache/Cypress`. By ensuring this cache persists across builds you can save
minutes off install time by preventing a large binary download.

We recommend that you:

- Cache the `~/.cache` folder after running `npm install`, `yarn`,
  [`npm ci`](https://docs.npmjs.com/cli/ci) or equivalents as demonstrated in
  the configs below.

- **Do not** cache `node_modules` across builds. Instead, cache the package
  manager's own cache directory (`~/.npm` for npm or `~/.cache/yarn` for yarn).
  These tools maintain package-level caches that track installed versions,
  validate integrity, and only re-download packages that have changed. Caching
  `node_modules` directly bypasses these built-in mechanisms and can cause
  issues such as Cypress not downloading the Cypress binary on `npm install`.

- If you are using `npm install` in your build process, consider
  [switching to `npm ci`](https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable)
  and caching the `~/.npm` directory for a faster and more reliable build.

- If you are using `yarn`, caching `~/.cache` will include both the `yarn` and
  Cypress caches. Consider using `yarn install --frozen-lockfile` as an
  [`npm ci`](https://docs.npmjs.com/cli/ci) equivalent.

- If you need to override the binary location for some reason, use the
  [CYPRESS_CACHE_FOLDER](/app/references/advanced-installation#Binary-cache)
  environment variable.

- Make sure you are not restoring the previous cache using lax keys; then the
  Cypress binaries can "snowball", accumulating every version you have ever
  installed.

**Tip:** you can find lots of CI examples with configured caching in our
[cypress-example-kitchensink](https://github.com/cypress-io/cypress-example-kitchensink#ci-status)
repository.

### Environment variables

You can set various environment variables to modify how Cypress runs.

#### Configuration Values

You can set any [configuration value](/app/references/configuration) as an
environment variable by prefixing it with `CYPRESS_`. This overrides values in
the Cypress configuration.

**_Typical use cases would be modifying things like:_**

- `CYPRESS_BASE_URL` - point tests at a preview or staging deployment
- `CYPRESS_REPORTER` - switch to a CI-friendly reporter like `junit`
- `CYPRESS_DEFAULT_COMMAND_TIMEOUT` - allow more time on slower CI machines
- `CYPRESS_VIEWPORT_WIDTH` and `CYPRESS_VIEWPORT_HEIGHT` - vary the screen
  size per CI job

The install-time variable
[`CYPRESS_INSTALL_BINARY`](/app/references/advanced-installation#Download-URLs)
is also commonly set in CI, to skip or redirect the binary download.

Refer to the
[Environment Variables recipe](/app/references/configuration#Environment-Variables)
for more examples.

**_Record Key_**

If you are [recording your runs](#Record-tests) on a public project, you'll want
to protect your Record Key.
[Learn why.](/cloud/account-management/projects#Project-ID)

Instead of hard coding it into your run command like this:

<CypressCommandTabs command="run --record --key abc-key-123" />

You can set the record key as the environment variable `CYPRESS_RECORD_KEY`
and we'll automatically use that value. You can now omit the `--key` flag when
recording.

<CypressCommandTabs command="run --record" />

Set `CYPRESS_RECORD_KEY` in your CI provider's settings as a secret or masked
environment variable so it doesn't appear in your configuration files or build
logs.

<RecordKeyEnvVar />

#### Git information

Cypress assumes there is a `.git` folder and uses Git commands to get each property,
like `git show -s --pretty=%B` to get the commit message.

Under some environment setups (e.g. `docker`/`docker-compose`) if the `.git`
directory is not available or mounted, you can pass all git related information
under custom system environment variables.

- Branch: `COMMIT_INFO_BRANCH`
- Message: `COMMIT_INFO_MESSAGE`
- Author email: `COMMIT_INFO_EMAIL`
- Author: `COMMIT_INFO_AUTHOR`
- SHA: `COMMIT_INFO_SHA`
- Remote: `COMMIT_INFO_REMOTE`

If the commit information is missing in the Cypress Cloud run then
[GitHub Integration](/cloud/integrations/github) or other
tasks might not work correctly. To see the relevant Cypress debug logs, set the
system environment variable `DEBUG` on your CI machine and inspect the terminal output
to see why the commit information is unavailable.

```shell
DEBUG=cypress:server:record
```

**_Source control credentials_**

The remote origin Cypress records comes from `git config --get remote.origin.url`,
and some CI providers authenticate the checkout by embedding a token in that URL.
Any credential sitting there is readable by every later step in the job and
becomes part of the recorded run.

Use your CI provider's standard checkout authentication rather than supplying
your own long-lived token. Providers issue credentials that expire when the job
ends, such as the GitHub Actions `GITHUB_TOKEN`, the GitLab CI/CD job token, a
CircleCI checkout key, or the Azure Pipelines `System.AccessToken`. Substituting
a personal access token puts a credential that lasts months in the same exposed
position.

If your checkout leaves a credential in the remote URL, set `COMMIT_INFO_REMOTE`
to a clean URL so the recorded remote does not include it. On GitLab CI, for
example, `CI_PROJECT_URL` has no token in it:

```shell
export COMMIT_INFO_REMOTE="$CI_PROJECT_URL.git"
```

#### CI Build Information

In some newer CI providers, Cypress can't map the system environment variables required
to link back to builds or pull requests. In this case we provide users some
environment variables to help pass that information along.

- Pull Request Id: `CYPRESS_PULL_REQUEST_ID`
- Pull Request URL: `CYPRESS_PULL_REQUEST_URL`
- Build URL: `CYPRESS_CI_BUILD_URL`

Setting these will allow links within the Cloud run to take you to the
appropriate place.

#### Custom Environment Variables

You can also set custom values for use in your tests. Which API you use
depends on whether the value is sensitive.

**_Private values: `cy.env()`_**

For secrets like API tokens, set an OS environment variable prefixed with
`CYPRESS_` using your CI provider's secret or masked variable settings:

```shell
export CYPRESS_SERVICE_API_TOKEN=secret-token-123
```

Cypress strips the prefix, and your tests read the value with
[`cy.env()`](/api/commands/env), which retrieves only the values you request
without serializing them into browser state:

```javascript
cy.env(['SERVICE_API_TOKEN']).then(({ SERVICE_API_TOKEN }) => {
  cy.request({
    url: 'https://api.example.com/users',
    headers: { Authorization: `Bearer ${SERVICE_API_TOKEN}` },
  })
})
```

**_Public values: `Cypress.expose()`_**

For non-sensitive configuration that is safe to appear in browser state, like
feature flags or API versions, pass values with the `--expose` CLI flag:

<CypressCommandTabs command="run --expose apiVersion=v2,featureFlag=true" />

and read them synchronously with
[`Cypress.expose()`](/api/cypress-api/expose):

```javascript
const apiVersion = Cypress.expose('apiVersion') // => 'v2'
```

Refer to the dedicated
[Environment Variables & Secrets guide](/app/guides/environment-variables) for more
examples.

### Module API

Oftentimes it can be less complex to programmatically control and boot your
servers with a Node script.

If you're using our [Module API](/app/references/module-api) then you can write a
script that boots and then shuts down the server later. As a bonus, you can work
with the results and do other things.

```js title="scripts/run-cypress-tests.js"
const cypress = require('cypress')
const server = require('./lib/my-server')

;(async () => {
  await server.start()

  // kick off a cypress run
  const results = await cypress.run()

  // stop your server when it's complete
  await server.stop()
})()
```

```shell
node scripts/run-cypress-tests.js
```

## Common problems and solutions

### Missing binary

When npm or yarn install the `cypress` package, a `postinstall` hook is executed
that downloads the platform-specific Cypress binary. If the hook is skipped for
any reason the Cypress binary will be missing (unless it was already cached).

To better diagnose the error, add
[commands to get information about the Cypress cache](/app/references/command-line#cypress-cache-command)
to your CI setup. This will print where the binary is located and what versions
are already present.

<CypressCommandTabs
  command={`cache path
cache list`}
/>

If the required binary version is not found in the cache, you can try the
following:

1. Clean your CI's cache using your CI's settings to force a clean `npm install`
   on the next build.
2. Run the binary install yourself by adding the command `npx cypress install`
   to your CI script. If there is a binary already present, it should finish
   quickly.

### Xvfb

When running on Linux, Cypress needs an X11 server; otherwise it spawns its own
X11 server during the test run. When running several Cypress instances in
parallel, the spawning of multiple X11 servers at once can cause problems for
some of them. In this case, you can separately start a single X11 server and
pass the server's address to each Cypress instance using the `DISPLAY`
variable.

First, spawn the X11 server in the background at some port, for example `:99`.
If you have installed `xvfb` on Linux or if you are using one of our Docker
images from
[cypress-docker-images](https://github.com/cypress-io/cypress-docker-images),
the tools below should be available.

```shell
Xvfb :99 &
```

Second, set the X11 address in a system environment variable

```shell
export DISPLAY=:99
```

Start Cypress as usual

<CypressRunCommands />

After all tests across all Cypress instances finish, kill the Xvfb background
process using `pkill`

```shell
pkill Xvfb
```

:::caution

In certain Linux environments, you may experience connection errors with your
X11 server. In this case, you may need to start Xvfb with the following command:

```shell
Xvfb -screen 0 1024x768x24 :99 &
```

Cypress internally passes these Xvfb arguments, but if you are spawning your own
Xvfb, you would need to pass these arguments. This is necessary to avoid using
8-bit color depth with Xvfb, which will prevent Chrome or Electron from
crashing.

:::

### Colors

If you want colors to be disabled, you can pass the `NO_COLOR` environment
variable to disable colors. You may want to do this if ASCII characters or
colors are not properly formatted in your CI.

```shell
NO_COLOR=1 cypress run
```

## See also

- [Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app)
  runs parallelized CI jobs across multiple operating systems, browsers, and
  viewport sizes
- [cypress-example-kitchensink](https://github.com/cypress-io/cypress-example-kitchensink#ci-status)
  is set up to run on multiple CI providers
- [Command Line](/app/references/command-line) - all `cypress run` flags and
  options
- [Test Replay](/cloud/features/test-replay)
- [Cross Browser Testing Guide](/app/guides/cross-browser-testing)

---

### Cloud Features Analytics Overview (`docs/cloud/features/analytics/overview.mdx`)

---
title: Types of analytics in Cypress Cloud
description: 'Compare the analytics available in Cypress Cloud — run trends, test suite size, flake rates, and enterprise reporting.'
sidebar_label: Overview
sidebar_position: 10
---

<ProductHeading product="cloud" />

# Types of Analytics

Cypress Cloud helps you understand various aspects of your test suite from a number of perspectives.
You can monitor and govern your application quality by looking at test case statistics, common errors,
test run duration, flake rates, and much more.

- [Project Level Analytics](/cloud/features/analytics/project-analytics): Analytics is provided
  for each project in your organization so that you can understand trends and details for an
  individual project.
- [Enterprise Reporting](/cloud/features/analytics/enterprise-reporting): Analytics is provided
  across your organization so that you can spot patterns or anomalies between projects, track test
  usage, and ensure consistency. This level of analytics supports governance of your testing
  program across the entire organization.
- [Data Extract API](/cloud/integrations/data-extract-api): Both aggregate and raw test data can
  be extracted from Cypress Cloud in a variety of formats. Retrieve your test data to use in your
  own analytics systems or automate additional workflows that can be triggered by conditions of your
  choosing.

---

### Cloud Features Smart Orchestration Overview (`docs/cloud/features/smart-orchestration/overview.mdx`)

---
title: Overview of smart orchestration in Cypress Cloud
description: Cypress Cloud provides Smart Orchestration features for use in CI to speed up test runs, accelerate debugging workflows, and reduce costs.
sidebar_label: Overview
sidebar_position: 10
---

<ProductHeading product="cloud" />

# Smart Orchestration Overview

Cypress Cloud provides several Smart Orchestration features for use in CI
to speed up test runs, accelerate debugging workflows, and reduce costs:

- [Parallelization](/cloud/features/smart-orchestration/parallelization): Reduce
  test duration by running multiple test spec files simultaneously across
  available CI machines.
- [Load Balancing](/cloud/features/smart-orchestration/load-balancing): Optimize
  CI resources and minimize test duration by intelligently prioritizing running
  of test spec files during parallelization.
- [Spec Prioritization](/cloud/features/smart-orchestration/spec-prioritization):
  Quickly verify that your latest changes fixed a build by prioritizing the
  specs that failed in the previous Cypress run.
- [Auto Cancellation](/cloud/features/smart-orchestration/run-cancellation):
  Automatically cancel a Cypress run once failures cross a threshold you set, so
  you stop paying for tests you'll never look at and free up CI resources to
  validate the fix.
- [Re-run optimization](/cloud/features/smart-orchestration/rerun-optimization)
  (experimental): When you rerun a failed CI run, re-run only the specs or tests
  that failed and skip the work that already passed, speeding up the path
  to a passing build.

:::success

Curious how much these add up to for your team? The
[Cypress Cloud Savings Calculator](https://www.cypress.io/savings-calculator?utm_source=docs.cypress.io&utm_medium=smart-orchestration&utm_content=Savings+Calculator)
estimates the annual time and CI cost you could save by orchestrating your runs.

:::

---

### App Write Tests Component Testing Angular Overview (`docs/app/write-tests/component-testing/angular/overview.mdx`)

---
title: 'Angular component testing'
description: 'Learn how to set up component tests in Angular and configure Cypress for Angular projects.'
sidebar_label: Angular overview
sidebar_position: 10
slug: /app/component-testing/angular/overview
---

<ProductHeading product="app" />

# Angular Component Testing

Cypress Component Testing supports Angular `^21.0.0` and `^22.0.0`.

:::info

Our testing harness, `cypress/angular`, requires `@angular-devkit/build-angular` to be installed in your project, even if your project is zoneless or is built with `@angular/build`.
As of Cypress `16.0.0`, `cypress/angular` supports zoneless testing with no additional configuration. `zone.js` is no longer required. Zoneless is the default in Angular 21 and 22.
:::

## Tutorial

Visit the
[Getting Started Guide](/app/component-testing/get-started) for a
step-by-step tutorial on adding component testing to any project and how to write your first tests.

## Installation

To get up and running with Cypress Component Testing in Angular, install Cypress
into your project:

<CypressInstallCommands />

Open Cypress:

<CypressOpenCommands />

<DocsImage
  src="/img/app/component-testing/select-test-type.jpg"
  caption="Choose Component Testing"
/>

The Cypress App will guide you through configuring your project.

:::info

For a step-by-step guide on how to create a component test, refer to the
[Getting Started](/app/component-testing/get-started) guide.

For usage and examples, visit the
[Angular Examples](/app/component-testing/angular/examples) guide.

:::

## Framework Configuration

Cypress Component Testing works out of the box with `@angular/cli` projects.
Cypress will automatically detect your project is Angular during setup and
configure it properly.

For a full explanation of how the dev server and bundler work — including
automatic config detection and override options — see
[Component Testing Configuration — Dev Server and Bundler](/app/component-testing/component-framework-configuration#Dev-Server-and-Bundler).

The examples below are for quick reference.

### Angular CLI Configuration

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'angular',
      bundler: 'webpack',
    },
    specPattern: '**/*.cy.ts',
  },
}
```

:::

#### Options API

You can also use the `options` API to provide your own project specific
configuration to your `devServer`. The `devServer` configuration receives an
`options` property:

```ts title=cypress.config.ts
import { defineConfig } from 'cypress'

export default {
  component: {
    devServer: {
      framework: 'angular',
      bundler: 'webpack',
      options: {
        projectConfig: {
          root: '',
          sourceRoot: 'apps/my-app',
          buildOptions: {
            outputPath: 'dist/my-app',
            index: 'apps/my-app/src/index.html',
            main: 'apps/my-app/src/main.ts',
            polyfills: 'apps/my-app/src/polyfills.ts',
            tsConfig: 'apps/my-app/tsconfig.app.json',
            inlineStyleLanguage: 'scss',
            assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
            styles: ['apps/my-app/src/styles.scss'],
            scripts: [],
            buildOptimizer: false,
            optimization: false,
            vendorChunk: true,
            extractLicenses: false,
            sourceMap: true,
            namedChunks: true,
          },
        },
      },
    },
  },
}
```

#### Sample Angular Apps

- [Angular 22](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/angular)

## Styling

Cypress builds your component specs with the Angular build pipeline. When you do
**not** provide an `options.projectConfig`, Cypress reads the build options
(including `assets`, `styles`, and `stylePreprocessorOptions`) from the default
application project in your `angular.json`. When you **do** provide your own
[`projectConfig`](#Options-API), it _replaces_ the configuration Cypress detects
from `angular.json`, so any build options your styles rely on must be repeated
in your `buildOptions`. The two issues below are usually a result of this.

### Sass `@use` / `@import` can't find a stylesheet

If your Sass resolves imports through paths configured in `angular.json` under
`stylePreprocessorOptions.includePaths`, you may see an error during component
testing like:

```
❌ Can't find stylesheet to import.
@use 'mixins'
```

This happens when a custom `projectConfig` omits those include paths. Add the
same `stylePreprocessorOptions` to your `buildOptions` so the Sass compiler can
resolve the imports:

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'angular',
      bundler: 'webpack',
      options: {
        projectConfig: {
          root: '',
          sourceRoot: 'src',
          buildOptions: {
            styles: ['src/styles.scss'],
            stylePreprocessorOptions: {
              includePaths: ['src/styles'],
            },
          },
        },
      },
    },
    specPattern: '**/*.cy.ts',
  },
}
```

:::

### Tailwind CSS v4 utility classes aren't applied

With Tailwind CSS v4, you may find that your own styles load correctly but
Tailwind utility classes such as `bg-red-500` have no effect. The class is
present on the element in the DevTools inspector, but no rule is generated for
it. This is because Tailwind v4 generates utilities through its own build
plugin, which is not part of the Angular build pipeline Cypress uses to compile
your `styles`.

A reliable workaround is to precompile your Tailwind stylesheet into a plain CSS
file with the [Tailwind CLI](https://tailwindcss.com/docs/installation/tailwind-cli)
and load that compiled file through `buildOptions.styles`.

Install the CLI:

<Tabs>
  <TabItem value="npm">

```shell
npm install -D @tailwindcss/cli
```

  </TabItem>

  <TabItem value="yarn">

```shell
yarn add -D @tailwindcss/cli
```

  </TabItem>

  <TabItem value="pnpm">

```shell
pnpm add -D @tailwindcss/cli
```

  </TabItem>

  <TabItem value="bun">

```shell
bun add -d @tailwindcss/cli
```

  </TabItem>
</Tabs>

Compile your stylesheet before opening or running Cypress, then point
`buildOptions.styles` at the compiled output:

```json title=package.json
{
  "scripts": {
    "build:ct-styles": "npx @tailwindcss/cli -i ./src/styles.scss -o ./cypress/support/compiled-styles.css",
    "cypress:open": "npm run build:ct-styles && cypress open --component",
    "cypress:run": "npm run build:ct-styles && cypress run --component"
  }
}
```

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'angular',
      bundler: 'webpack',
      options: {
        projectConfig: {
          buildOptions: {
            styles: ['cypress/support/compiled-styles.css'],
          },
        },
      },
    },
    specPattern: '**/*.cy.ts',
  },
}
```

:::

## See also

- [Component Testing code coverage](/app/tooling/code-coverage#component-testing-code-coverage)

---

### App Write Tests Component Testing React Overview (`docs/app/write-tests/component-testing/react/overview.mdx`)

---
title: 'React component testing'
description: Learn how to set up component tests in React and use Cypress with different React frameworks and bundlers.
sidebar_label: React overview
sidebar_position: 10
slug: /app/component-testing/react/overview
---

<ProductHeading product="app" />

# React Component Testing

Cypress Component Testing currently supports React 18 and 19 with the following
frameworks:

- [React with Vite](#React-with-Vite)
- [React with Webpack](#React-with-Webpack)
- [Next.js](#Nextjs)

## Tutorial

Visit the
[Getting Started Guide](/app/component-testing/get-started) for a
step-by-step tutorial on adding component testing to any project and how to write your first tests.

## Installation

To get up and running with Cypress Component Testing in React, install Cypress
into your project:

<CypressInstallCommands />

Open Cypress:

<CypressOpenCommands />

<DocsImage
  src="/img/app/component-testing/select-test-type.jpg"
  caption="Choose Component Testing"
/>

The Cypress Launchpad will guide you through configuring your project.

:::info

For a step-by-step guide on how to create a component test, refer to the
[Getting Started](/app/component-testing/get-started) guide.

For usage and examples, visit the
[React Examples](/app/component-testing/react/examples) guide.

:::

## Framework Configuration

Cypress Component Testing works out of the box with [Vite](https://vitejs.dev/), [Next.js](https://nextjs.org/), and a custom
[Webpack](https://webpack.js.org/) config. Cypress will automatically detect one
of these frameworks during setup and configure them properly.

For a full explanation of how the dev server and bundler work — including
automatic config detection and override options — see
[Component Testing Configuration — Dev Server and Bundler](/app/component-testing/component-framework-configuration#Dev-Server-and-Bundler).

The examples below are for quick reference.

### React with Vite

Cypress Component Testing works with React apps that use Vite `8.x` as the bundler.

#### Vite Configuration

:::cypress-config-example

```ts
import customViteConfig from './customConfig'
```

```ts
{
  component: {
    devServer: {
      framework: 'react',
      bundler: 'vite',
      // optionally pass in vite config
      viteConfig: customViteConfig,
      // or a function - the result is merged with
      // any `vite.config` file that is detected
      viteConfig: async () => {
        // ... do things ...
        const modifiedConfig = await injectCustomConfig(baseConfig)
        return modifiedConfig
      },
    },
  },
}
```

:::

#### Sample React Vite Apps

- [React Vite with TypeScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/react-vite-ts)

### React with Webpack

Cypress Component Testing works with React apps that use Webpack 5+ as the
bundler.

#### Required Packages

Install these packages in your project to run React component tests with
Webpack:

| Package     | Version  | Purpose                                                                                           |
| ----------- | -------- | ------------------------------------------------------------------------------------------------- |
| `cypress`   | Latest   | The Cypress App. Ships with the React mount adapter and the Webpack dev server                    |
| `react`     | 18 or 19 | The React library your components are built with                                                  |
| `react-dom` | 18 or 19 | Renders your components into the DOM during a test                                                |
| `webpack`   | 5        | Your app's bundler. Cypress compiles your specs with the Webpack config it detects in the project |

:::info

You do not need to install `@cypress/react`, `@cypress/webpack-dev-server`, or
`webpack-dev-server` separately. All three ship inside the `cypress` package, so
`import { mount } from 'cypress/react'` and `bundler: 'webpack'` work as soon as
Cypress is installed.

:::

#### Webpack Configuration

:::cypress-config-example

```ts
import webpackConfig from './webpack.config'
```

```ts
{
  component: {
    devServer: {
      framework: 'react',
      bundler: 'webpack',
      // optionally pass in webpack config
      webpackConfig,
      // or a function - the result is merged with any
      // webpack.config that is found
      webpackConfig: async () => {
        // ... do things ...
        const modifiedConfig = await injectCustomConfig(baseConfig)
        return modifiedConfig
      },
    },
  },
}
```

:::

If you don't provide a webpack config, Cypress will try to infer it. If Cypress
cannot do so, or you want to make modifications to your config, you can specify
it via the `webpackConfig` option.

#### Sample React Webpack Apps

- [React Webpack 5 with JavaScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/react-webpack5-js)

### Next.js

Cypress Component Testing works with Next.js 15 and 16.

#### Next.js Configuration

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'next',
      bundler: 'webpack',
    },
  },
}
```

:::

#### Next.js Caveats

There are some specific caveats to consider when testing Next.js
[Pages](https://nextjs.org/docs/basic-features/pages) in component testing.

A page component could have additional logic in its `getServerSideProps` or
`getStaticProps` methods. These methods only run on the server, so they are not
available to run inside a component test. Trying to test a page in a component
test would result in the props being passed into the page to be undefined.

While you could pass in props directly to the page component in a component
test, that would leave these server-side methods untested. However, an
end-to-end test would execute and test a page entirely.

Because of this, we recommend using E2E Testing over Component Testing for
Next.js pages and Component Testing for individual components in a Next.js app.

#### Sample Next.js Apps

- [Next.js 15 with TypeScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/react-next15-ts)
- [Next.js 16 with TypeScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/react-next16-ts)

## Community Resources

- [Cypress Component Test Driven Design](https://muratkerem.gitbook.io/cctdd/)
- [Cypress React Component Test Examples](https://github.com/muratkeremozcan/cypress-react-component-test-examples)

## See also

- [Component Testing code coverage](/app/tooling/code-coverage#component-testing-code-coverage)

---

### App Write Tests Component Testing Svelte Overview (`docs/app/write-tests/component-testing/svelte/overview.mdx`)

---
title: 'Svelte component testing'
description: Learn how to set up component tests in Svelte, configure Cypress for Svelte projects, and test Svelte components with Vite and a custom Webpack config.
sidebar_label: Svelte overview
sidebar_position: 10
slug: /app/component-testing/svelte/overview
---

<ProductHeading product="app" />

# Svelte Component Testing

Cypress Component Testing supports Svelte 5 in a variety of different
frameworks:

- [Svelte with Vite](#Svelte-with-Vite)
- [Svelte with Webpack](#Svelte-with-Webpack)

:::caution

Svelte is currently in alpha support for component testing.

:::

## Tutorial

Visit the
[Getting Started Guide](/app/component-testing/get-started) for a
step-by-step tutorial on adding component testing to any project and how to write your first tests.

## Installation

To get up and running with Cypress Component Testing in Svelte, install Cypress
into your project:

<CypressInstallCommands />

Open Cypress:

<CypressOpenCommands />

<DocsImage
  src="/img/app/component-testing/select-test-type.jpg"
  caption="Choose Component Testing"
/>

The Cypress Launchpad will guide you through configuring your project.

:::info

For a step-by-step guide on how to create a component test, refer to the
[Getting Started](/app/component-testing/get-started) guide.

For usage and examples, visit the
[Svelte Examples](/app/component-testing/svelte/examples) guide.

:::

## Framework Configuration

Cypress Component Testing works out of the box with [Vite](https://vitejs.dev/),
and a custom [Webpack](https://webpack.js.org/) config. Cypress will
automatically detect one of these frameworks during setup and configure them
properly.

For a full explanation of how the dev server and bundler work — including
automatic config detection and override options — see
[Component Testing Configuration — Dev Server and Bundler](/app/component-testing/component-framework-configuration#Dev-Server-and-Bundler).

The examples below are for quick reference.

### Svelte with Vite

Cypress Component Testing works with Svelte apps that use Vite `8.x` as the
bundler.

#### Vite Configuration

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'svelte',
      bundler: 'vite',
    },
  },
}
```

:::

#### Svelte Vite Sample Apps

- [Svelte 5 with Vite and TypeScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/svelte-vite-ts)

### Svelte with Webpack

Cypress Component Testing works with Svelte apps that use Webpack 5+ as the
bundler.

#### Webpack Configuration

:::cypress-config-example

```ts
import webpackConfig from './webpack.config'
```

```ts
{
  component: {
    devServer: {
      framework: 'svelte',
      bundler: 'webpack',
      // optionally pass in webpack config
      webpackConfig,
    },
  },
}
```

:::

If you don't provide one, Cypress will try to infer your webpack config. If
Cypress cannot or you want to make modifications to your config, you can pass it
in manually via the `webpackConfig` option.

#### Svelte Webpack Sample Apps

- [Svelte 5 Webpack 5 with Typescript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/svelte-webpack-ts)

## See also

- [Component Testing code coverage](/app/tooling/code-coverage#component-testing-code-coverage)

---

### App Write Tests Component Testing Vue Overview (`docs/app/write-tests/component-testing/vue/overview.mdx`)

---
title: 'Vue component testing'
description: Learn how to set up component tests in Vue and configure Cypress for Vue projects.
sidebar_label: Vue overview
sidebar_position: 10
slug: /app/component-testing/vue/overview
---

<ProductHeading product="app" />

# Vue Component Testing

Cypress Component Testing supports Vue 3+ with the following frameworks:

- [Vue with Vite](#Vue-with-Vite)
- [Vue with Webpack](#Vue-with-Webpack)

## Tutorial

Visit the
[Getting Started Guide](/app/component-testing/get-started) for a
step-by-step tutorial on adding component testing to any project and how to write your first tests.

## Installation

To get up and running with Cypress Component Testing in Vue, install Cypress
into your project:

<CypressInstallCommands />

Open Cypress:

<CypressOpenCommands />

<DocsImage
  src="/img/app/component-testing/select-test-type.jpg"
  caption="Choose Component Testing"
/>

The Cypress Launchpad will guide you through configuring your project.

:::info

For a step-by-step guide on how to create a component test, refer to the
[Getting Started](/app/component-testing/get-started) guide.

For usage and examples, visit the
[Vue Examples](/app/component-testing/vue/examples) guide.

:::

## Framework Configuration

Cypress Component Testing works out of the box with
[Vite](https://vitejs.dev/), and a custom [Webpack](https://webpack.js.org/)
config. Cypress will automatically detect one of these frameworks during setup
and configure them properly.

For a full explanation of how the dev server and bundler work — including
automatic config detection and override options — see
[Component Testing Configuration — Dev Server and Bundler](/app/component-testing/component-framework-configuration#Dev-Server-and-Bundler).

The examples below are for quick reference.

### Vue with Vite

Cypress Component Testing works with Vue apps that use Vite `8.x` as the bundler.

#### Vite Configuration

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'vue',
      bundler: 'vite',
    },
  },
}
```

:::

#### Vue Vite Sample Apps

- [Vue 3 Vite with TypeScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/vue3-vite-ts)

### Vue with Webpack

Cypress Component Testing works with Vue apps that use Webpack 5+ as the
bundler.

#### Webpack Configuration

:::cypress-config-example

```ts
import webpackConfig from './webpack.config'
```

```ts
{
  component: {
    devServer: {
      framework: 'vue',
      bundler: 'webpack',
      // optionally pass in webpack config
      webpackConfig,
      webpackConfig: async () => {
        // ... do things ...
        const modifiedConfig = await injectCustomConfig(baseConfig)
        return modifiedConfig
      },
    },
  },
}
```

:::

If you don't provide one, Cypress will try to infer your webpack config. If
Cypress cannot or you want to make modifications to your config, you can pass it
in manually via the `webpackConfig` option.

#### Vue Webpack Sample Apps

- [Vue 3 Webpack 5 with TypeScript](https://github.com/cypress-io/cypress-component-testing-apps/tree/main/vue3-webpack-ts)

## Using Cypress with Nuxt

Cypress does not ship a dedicated [Nuxt](https://nuxt.com/) framework definition,
and it does not read `nuxt.config`. Instead, you component test a Nuxt 3+ app the
same way you test any Vue 3 + Vite project, by setting the `vue` framework and the
`vite` bundler:

:::cypress-config-example

```ts
{
  component: {
    devServer: {
      framework: 'vue',
      bundler: 'vite',
    },
  },
}
```

:::

Because Cypress does not execute `nuxt.config`, the bundler behavior Nuxt
normally provides is not applied for you. Account for the following in the config
you pass to Cypress:

- **Path aliases** — Nuxt's `~` and `@` aliases are not visible to Cypress.
  Declare the ones your components use via `viteConfig`. See
  [Meta-frameworks that own the bundler config](/app/component-testing/component-framework-configuration#Meta-frameworks-that-own-the-bundler-config).
- **Auto-imports** — Nuxt auto-imports components and composables (such as `ref`,
  `useRoute`, and `useRuntimeConfig`). These are not available when a component is
  mounted in isolation, so either import what your component relies on explicitly
  or add the equivalent Vite plugin to your `viteConfig`.

## See also

- [Component Testing code coverage](/app/tooling/code-coverage#component-testing-code-coverage)

---

### Accessibility Changelog (`docs/accessibility/changelog.mdx`)

---
title: 'Cypress Accessibility Release Notes'
description: 'Stay up to date with the latest features, improvements, and bug fixes for Cypress Accessibility.'
sidebar_label: Changelog
sidebar_position: 200
---

<ProductHeading product="accessibility" />

# Changelog

## Week of Oct 5, 2026

- **Configure Axe Core® rules yourself with `axeConfig`:** Set `accessibility.axeConfig` in the App Quality editor to enable or disable individual Axe-Core® rules, or scope a report with `runOnly` tags such as WCAG 2.1 A and AA. See [`axeConfig`](/accessibility/configuration/axe-core-configuration).

## Week of Aug 24, 2026

- **Download an Accessibility report:** A new **Download report** button on a run's Accessibility report exports the run's violations as a `.csv` or `.json` file, including deep links back into Cypress Cloud. Use it for offline analysis, spreadsheets and charts, sharing, or handing the results to an AI agent. See [Download reports](/accessibility/connect-and-extend/download-reports) and [working with AI agents](/accessibility/work-with-ai-agents#Work-with-a-downloaded-report).

## Week of Apr 13, 2026

- The `accessibility.components` configuration object adds `componentAttributes` and `componentAttributeFilters`. See the [components](/accessibility/configuration/components) guide.
- Cypress Accessibility analytics have been expanded in [Enterprise Reporting](/cloud/features/analytics/enterprise-reporting), surfacing trends in rule failure counts, severity level of issues, and more. Get all the details in our guide, [Catch accessibility regressions](/accessibility/guides/detect-changes#track-trends-over-time).

## Week of Mar 30, 2026

- **Cypress Accessibility in Cypress Cloud MCP:** AI agents can now query and act on Cypress Accessibility data for a run through the [Cypress Cloud MCP server](/cloud/integrations/cloud-mcp), using three new tools:
  - `cypress_get_accessibility_report`: Returns a run's violation counts by severity, the failing rules with their element counts, and the top views sorted by failure count.
  - `cypress_get_accessibility_rule_failures`: Drills into the failing DOM elements for a specific rule, optionally scoped to a single view.
  - `cypress_get_accessibility_views`: Browses all of the views in a run, sorted by number of failing rules.

  See [working with AI agents](/accessibility/work-with-ai-agents) for example prompts and setup.

## Week of Feb 06, 2026

- We now support fetching Accessibility results from Buildkite CI with the [Results API](/accessibility/connect-and-extend/results-api).

## Week of Jan 16, 2026

- We've upgraded our axe-core version to [4.11.0](https://docs.deque.com/axe-release-impact/4.11.0/en/release-notes).
- We now support fetching Accessibility results from Bitbucket CI with the [Results API](/accessibility/connect-and-extend/results-api).

## Week of Dec 19, 2025

- The `elementFilters` configuration property now supports an optional `documentScope` field that scopes selectors to specific document hosts (iframes or shadow DOM hosts). This enables you to filter elements within nested document contexts without requiring DOM changes. For example, you can filter all elements within a specific shadow DOM component or iframe by combining a selector with `documentScope`. See the [Element Filters](/accessibility/configuration/elementfilters) documentation for more details and examples.

## Week of Dec 12, 2025

- You can now create Jira issues directly from accessibility violations in the detail view. This brings accessibility issues into your existing Jira workflow for tracking and prioritization. The created Jira issue will include a link back to the accessibility violation in Cypress Cloud. [Learn more about creating Jira issues](/accessibility/reports/element-detail-view#Create-Jira-issue).

## Week of Dec 01, 2025

- The `profiles` configuration property applies different configuration settings to different runs based on [run tags](/app/references/command-line#cypress-run-tag-lt-tag-gt). This enables you to customize accessibility testing behavior for different environments, branches, or test scenarios. See the [Profiles](/accessibility/configuration/profiles) guide for more details.
- All configuration objects now support an optional `comment` property that you can use to provide context and explanations for why certain values are set. This helps make your configuration easier to understand and maintain, especially when working in teams or revisiting configuration after some time.

## Week of Oct 13, 2025

- Individual rules, or set of rules, can now be ignored for specific elements using [a `data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element).

## Week of Oct 06, 2025

- False positives in ["Interactive elements should be semantically correct"](/accessibility/core-concepts/cypress-rules#Interactive-elements-should-be-semantically-correct) related to elements using the `contenteditable` attribute have been addressed.

## Week of Jul 07, 2025

- A new custom accessibility rule, ["Interactive elements should be semantically correct"](/accessibility/core-concepts/cypress-rules#Interactive-elements-should-be-semantically-correct), is now available. This rule is based on the interactions that take place during your test execution, and helps detect accessibility issues that are not a part of typical DOM-based accessibility scans.

## Week of Jun 02, 2025

- We now support fetching Accessibility results from Drone CI with the [Results API](/accessibility/connect-and-extend/results-api).

## Week of May 26, 2025

- A new [element identification](/accessibility/core-concepts/element-identification) algorithm is now available for Cypress Accessibility. This produces improved element deduplication across different snapshots and runs, and incorporates testing-specific attributes like Test IDs into the element recognition and deduplication process. This replaces the default Axe-Core® element identification behavior.
- Two new configuration options are available in Cypress Accessibility - [`significantAttributes`](/accessibility/configuration/significantattributes) and [`attributeFilters`](/accessibility/configuration/attributefilters). These fine-tune Cypress's element identification behavior to ensure stable and relevant locators are used.
- Branch Review for Cypress Accessibility is now generally available, with an updated interface for displaying new and resolved violations, based on feedback during the Beta period. Thank you all for hitting the feedback button! [Learn more about comparing reports](/accessibility/guides/compare-reports).

## Week of May 12, 2025

- We now support fetching Accessibility results from AWS CodeBuild with the [Results API](/accessibility/connect-and-extend/results-api).

## Week of Mar 24, 2025

- Cypress Accessibility results are now included in the [Data Extract API](/cloud/integrations/data-extract-api) so that you can retrieve data over time.

## Week of Mar 10, 2025

- The [Cypress Accessibility Results API](/accessibility/connect-and-extend/results-api) has been updated with additional details about accessibility scores and failed element counts at the run level. Also, view-level reporting has been added, breaking out accessibility report data by the pages and components covered in the report. These improvements support more advanced workflows based on the accessibility data in the API, such as alerting a specific team about violations in a part of the app they own, or implementing different standards for different parts of the application.

## Week of Mar 03, 2025

- We've upgraded our axe-core version to [4.10.2](https://docs.deque.com/axe-release-impact/4.10.2/en/release-notes).
- The axe-core version used to generate a report can now be viewed in the Run Properties tab.

## Week of Feb 24, 2025

- [Cypress Accessibility Branch Review](/accessibility/guides/compare-reports) has entered beta. Read the docs to learn how to compare runs and automatically spot newly introduced issues.

## Week of Jan 13, 2025

- Cypress Accessibility results are now included in the Enterprise Reporting area of Cypress Cloud. Filter by project and branch and see trends over time.

## Week of Nov 11, 2024

- A "Share Issue" button has been added to the element details section for each reported rule violation. This allows for easily copying the key details and related links for a particular issue into your clipboard to add to a message or to a ticket in your issue tracking system.

## Week of Oct 28, 2024

- Our [Axe Core® versioning policy](/accessibility/core-concepts/how-it-works#Axe-Core-updates) has been published, providing a 30-day buffer between any Axe Core® releases and the adoption of those releases in Cypress Cloud.

## Week of Sep 30, 2024

- Cypress Accessibility results are now included in Slack messages alongside test results. [Learn more about our Slack integration here](/cloud/integrations/slack).

## Week of Sep 20, 2024

- A minor bugfix was released for score calculations, to fix a scenario where some snapshots could be counted more than once if they appeared in multiple tests. This may result in a small difference in the total score for runs before and after the change.
- Documentation updates to reflect recently released features and capabilities.

## Week of Sep 09, 2024

- We have introduced the new "Rules" tab for all users. It gathers the outcome of every rule that was tested for, across the entire run, and highlights which rules have the most failing elements. This also helps you understand the exact effect of any underlying configuration on rule outcomes.
- We have introduced new element statuses, beyond just failures. This allows Cypress Accessibility to surface any inconclusive or "manual review" items from Axe Core, as well as track and display elements whose results were explicitly ignored. Learn more in the [run-level reports](/accessibility/reports/run-level-reports) [Elements section](/accessibility/reports/run-level-reports#Elements).
- Elements ignored by configuration will have results captured, but these results will not affect your score. This ensures you can use filters to peek behind the curtain and understand exactly what is being excluded from a given run's results.
- The Detail View that displays failing elements will now also display inconclusive and (optionally) ignored elements for each rule. Inconclusive and ignored elements have distinct orange and gray icons and highlights respectively.

## Week of Aug 19, 2024

- iFrames are now supported for accessibility checks. iFrame processing is _opt-in_ for existing customers, but new customers will begin with iFrames enabled and can choose to opt out instead. This is to avoid disrupting existing pipelines, especially because iFrame content is not _always_ something you want to include in your reports.
- Cypress Accessibility results will now appear in [GitHub](/cloud/integrations/github), [GitLab](/cloud/integrations/gitlab), and [Bitbucket](/cloud/integrations/bitbucket) pull request and merge request comments alongside test results. Integrations can be installed and comments can be enabled in Project Settings.

## Week of Aug 05, 2024

- We now support fetching Accessibility results from CircleCI workflows with the [Results API](/accessibility/connect-and-extend/results-api).

## Week of Jul 29, 2024

- Fetching results in Azure and Jenkins is now supported in the new [Results API](/accessibility/connect-and-extend/results-api), which enables you to programmatically fetch your run's Accessibility results in a CI environment.

## Week of Jul 15, 2024

- The new [Results API](/accessibility/connect-and-extend/results-api), which enables you to programmatically fetch your run's Accessibility results in a CI environment, now supports fetching results in GitLab CI workflows.

## Week of Jun 24, 2024

- We have added the new [Results API](/accessibility/connect-and-extend/results-api) which enables you to programmatically fetch your run's Accessibility results in a CI environment. This brings the results into CI, where you review them and determine if they are acceptable or need to be addressed before code changes can merge.
- View [configuration information for each run](/accessibility/configuration/overview#Viewing-Configuration-for-a-Run) in the properties tab. There, you'll find the configuration set for the project at the start of the run. This will help you understand what factors might be driving a score change. This helps distinguish config criteria changes from other factors such as changes to your application, tests, Cypress versions, and more.

## Week of May 20, 2024

- Shadow DOM elements are now visible and highlighted in A11y report snapshots. By highlighting shadow DOM elements in snapshots, developers can identify and address all accessibility violations, including those within encapsulated components, thus enhancing the overall accessibility of the web application.
- You can now click directly into the accessibility report from any respective run from the "Latest Runs" page in Cypress Cloud. This improvement streamlines access and navigation to accessibility reports, saving you time and reducing the number of steps needed to view the details.
- We've added the ability to configure and customize your Accessibility report in Project Settings. You can set configuration through our editor equipped with linting and IntelliSense code completion. Control what should be tested or ignored in your score calculations to ensure your team is capturing what's relevant to your organization's goals.

## Week of Apr 15, 2024

- We've added full depth axe-core® details for each element flagged with an accessibility violation, providing comprehensive context to help developers accurately identify and resolve issues.

## Week of Mar 25, 2024

- The new Violation Severity Breakdown displays a small bar graph indicating the severity level of accessibility violations across the entire run, or on the level of individual pages or components. This gives users more information at a glance about what pages have the most severe problems, and the overall makeup of their accessibility report. Pages with more severe problems will now be more obvious when scanning the report, helping users decide what pages need more investigation or which pages have the fewest problems.

## Week of Mar 18, 2024

- You can now refine your Views list by severity or specific rule sets. For instance, isolate pages featuring "Critical" violations only, or focus solely on WCAG 2.1 A violations. If your project has varying levels of accessibility, filtering pages or components with specific types of violations can serve as an initial step to comprehend and prioritize areas with the most severe issues.
- Cypress will now conduct accessibility checks within the Shadow DOM on all runs, expanding the accessibility testing scope.

## Week of Feb 25, 2024

- We've introduced text filtering so that users can filter the "Views" list by name, making it effortless to search and locate specific items.
- To improve clarity and context, we've also implemented a tooltip-style feature that displays the position of the highlighted elements. This means that when an accessibility violation is reported and is associated with a specific element on the screen, it's a lot easier to locate.

## Week of Jan 15, 2024

- We've introduced a new feature that streamlines accessibility management - the aggregation of all violations into a single comprehensive report. Look for the "View all" link next to the violations count at the top of the accessibility tab. This will show you all violations detected across an entire run, regardless of what page or component they are detected on.

## Week of Dec 31, 2023

- Users can now discover and address accessibility violations swiftly by using the newly integrated "Print Elements to Console" button within your browser's developer tools.

## Week of Dec 17, 2023

- Users can now view a detailed breakdown of the total number of Views (pages and/or components) and Violations detected during a specific run.

---

### Accessibility Faq (`docs/accessibility/faq.mdx`)

---
title: 'Cypress Accessibility FAQ'
description: 'Common Cypress Accessibility questions: which WCAG rules run, what the score means, inspecting and sharing a violation, fixing and ignoring violations, and configuring views and profiles.'
sidebar_label: FAQ
sidebar_position: 160
---

<ProductHeading product="accessibility" />

# Cypress Accessibility FAQ

## Fixing violations

### <Icon name="angle-right" /> Where do I start when Cypress Accessibility reports hundreds of violations?

Start by narrowing the report to the code you own with [`viewFilters`](/accessibility/configuration/viewfilters) and [`elementFilters`](/accessibility/configuration/elementfilters), so third-party pages and vendor widgets stop competing for attention. Then open the **Rules** list for a run and pick a single rule with a small number of failing elements and a fix that fits in one component, such as `button-name`. Finishing one rule across the application is usually faster than finishing one page, because the fix has the same shape every time. See [Fix accessibility violations](/accessibility/guides/improve-accessibility) for the full process.

### <Icon name="angle-right" /> Should I fix a violation in Cypress Accessibility or ignore it?

Ignore findings you don't own or have decided not to fix, such as a third-party consent banner or an OAuth provider's sign-in page, so your report reflects work you actually intend to do. Fix findings in your own application: filtering one removes the evidence from the report, but the barrier is still there for the people using your product. When you're unsure, leave the finding reported and use the [Results API](/accessibility/connect-and-extend/results-api) to decide whether it blocks a build, which keeps full visibility into the issue.

### <Icon name="angle-right" /> Why didn't my Cypress Accessibility score change after I fixed some violations?

The [accessibility score](/accessibility/core-concepts/accessibility-score) weighs each failed rule per snapshot, not each failing element. If a rule fails on 10 elements in a snapshot and you fix nine of them, that snapshot's score is unchanged until the last one is fixed and the rule flips to passing. The run score also averages every snapshot in the run, so a rule failing on one page in a large suite barely moves the top-line number. Track failed element counts for the rule you're working on, and the **Resolved elements** section of Branch Review, rather than watching the score during remediation.

### <Icon name="angle-right" /> How do I confirm an accessibility fix worked in Cypress Accessibility?

Compare your branch against a base run in Branch Review. The **Resolved elements** section should list the rule you worked on across every view where it was failing, which confirms the fix reached more than the one element you tested by hand. Check the **New failed elements** section in the same review: accessibility fixes commonly introduce new findings, such as an added `aria-label` that duplicates visible text. See [Compare reports](/accessibility/guides/compare-reports) for how the comparison works.

### <Icon name="angle-right" /> Do I need to add assertions or commands to my tests for Cypress Accessibility?

No. Cypress Accessibility reports are generated in Cypress Cloud from the artifacts your recorded run already uploads, so there is nothing to add to your specs and no impact on how long your tests take. Every page and component your tests visit is checked automatically once the product is enabled for your project. Because the report is produced after the run, nothing in your Cypress pipeline fails from an accessibility violation unless you opt in with the [Results API](/accessibility/connect-and-extend/results-api).

### <Icon name="angle-right" /> How do I fix Cypress Accessibility violations with an AI agent?

Configure [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) so your agent can read results directly from Cypress Cloud with three tools: `cypress_get_accessibility_report` for a run's failing rules and worst views, `cypress_get_accessibility_views` to page through every view, and `cypress_get_accessibility_rule_failures` for the failing elements of a specific rule. Scope each prompt to one rule and ask for a plan before any code changes. Narrowing your report first keeps the agent from triaging findings you were never going to fix, and adding [`components`](/accessibility/configuration/components) attributes to violation selectors helps it locate the source file without crawling your markup.

### <Icon name="angle-right" /> How do I stop a Cypress Accessibility rule I already fixed from regressing?

Keep a list of remediated rules in your CI verification script and fail the build when any of them appear in a run's results, using the [Results API](/accessibility/connect-and-extend/results-api). This inverts the more common pattern of allowlisting known failures: instead of tracking what's still broken, you lock in each rule the day it reaches zero violations. Add a rule to the list as soon as it passes, and the list becomes a record of the barriers your application no longer has.

## Inspecting a violation

### <Icon name="angle-right" /> How do I see which element failed an accessibility rule in Cypress?

Open the rule in a run's [accessibility report](/accessibility/reports/run-level-reports) and it expands into the [violation detail view](/accessibility/reports/element-detail-view), which lists every element the rule matched by its violation target selector. Selecting an element pins it, highlights it in a DOM snapshot of the page state it was captured in, and expands a **Solutions** list of the specific checks that failed on it. Clicking a rule row on the **Rules** tab opens **All Views** scoped to that rule, which collects its failing elements across the entire run.

### <Icon name="angle-right" /> Can I inspect a Cypress Accessibility violation without running my application locally?

Yes, and this is the main reason the detail view exists. Every finding is stored with a rehydrated DOM and CSS snapshot of the page state it was found in, so the markup and styles render in your browser exactly as they did during the run. You can inspect the element, read computed styles, and open your browser's accessibility pane against the captured page without starting a server or reproducing the steps. See [inspect violation details](/accessibility/reports/element-detail-view#Work-with-the-DOM-snapshot).

### <Icon name="angle-right" /> Why does a Cypress Accessibility snapshot highlight only one element?

By design. The snapshot outlines the element you have pinned, or the one you are hovering in the rules list, and nothing else, so a page with hundreds of failing elements stays readable. Select a different element to move the highlight, or turn the outline off entirely with the **Show DOM highlights** toggle in the snapshot options menu when it covers something you need to see.

### <Icon name="angle-right" /> Why does Cypress Accessibility say an element is not in this snapshot?

The element failed the rule somewhere in the view, but not in the page state currently displayed. A run captures many snapshots per view as your tests interact with the application, and an element such as a modal's close button only exists in the snapshots where the modal was open. Selecting the element moves the snapshot to a page state that contains it. With an element pinned, the snapshot counter also narrows to only the snapshots that element appears in.

### <Icon name="angle-right" /> What does "One of these must be fixed" mean in a Cypress Accessibility violation?

It means the listed checks are alternatives, and satisfying any one of them clears the violation. A button failing `button-name`, for example, can be fixed with inner text, an `aria-label`, an `aria-labelledby` reference, or a `title` attribute. **All of these must be fixed** means every listed check has to pass, **This must be fixed** means there is a single check, and **This element is failing for multiple reasons** introduces more than one group, each with its own rule. See [inspect violation details](/accessibility/reports/element-detail-view#Pin-an-element-to-inspect-it).

### <Icon name="angle-right" /> How do I share a specific accessibility violation with my team?

Three ways, from fastest to most durable. Copy the URL, which encodes the view, rule, pinned element, snapshot, and filters, so a teammate opens on exactly what you're looking at. Use **Share issue** to copy a Markdown or plain text snippet containing the rule, severity, view, element selector, a link to the rule's documentation, and a deep link back into Cypress Cloud. Or use **Create Jira issue** to open a ticket with those details prefilled. See [hand off a violation](/accessibility/reports/element-detail-view#Hand-off-a-violation).

### <Icon name="angle-right" /> How do I create a Jira issue from a Cypress Accessibility violation?

Select the failing element to expand its detail, choose **Create Jira issue**, and pick a Jira project. **Summary** is prefilled with the rule name and **Description** with the Markdown issue snippet, including a link back to the violation in Cypress Cloud. Both are editable before you submit, so it's the right moment to add context a triager will want. Choose an issue type, complete any fields your Jira project requires, and submit. This requires the [Cypress Cloud Jira integration](/cloud/integrations/jira) to be installed for your organization; without it, the button doesn't appear.

### <Icon name="angle-right" /> Can I file issues for a whole accessibility report at once?

Yes, with an AI agent connected to both [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) and your issue tracker. The agent reads the report for the latest run on a branch, checks Jira or another tracker for the issues that already exist, and creates only the ones that are missing, so a weekly refresh doesn't produce duplicates. [File issues in your issue tracker](/accessibility/work-with-ai-agents#File-issues-in-your-issue-tracker) walks through the prompts, how to group violations into tickets, and the guardrails to keep on an agent that can write.

### <Icon name="angle-right" /> Why does my Cypress Accessibility report show generated class names instead of meaningful selectors?

Because nothing more meaningful was available on the element. Cypress Accessibility builds each violation target selector from a prioritized list of attributes, so an element with no test attribute and no useful `id` falls back to whatever identifies it, which in a component library often means a class like `.MuiIconButton-colorPrimary`. Add the attribute your application already renders to [`significantAttributes`](/accessibility/configuration/significantattributes) to make it the identifier, or use [`components`](/accessibility/configuration/components) to append component and team context to the existing one. Regenerate a past run afterward to see the new selectors without rerunning your tests.

### <Icon name="angle-right" /> Why does a Cypress Accessibility rule show only 20 failing elements?

Elements load 20 at a time to keep the rules list responsive on rules with hundreds of findings. A **Load more elements** row at the bottom of the list fetches the next batch. The count beside the rule name is always the full number of matching elements, not the number currently loaded.

### <Icon name="angle-right" /> Why don't ignored elements show up in the violation detail view?

The **Element status** filter defaults to failed and inconclusive elements, with ignored turned off, so findings you have already excluded stay out of your triage list. Turn **Ignored** on in the filter menu to review them. Ignored elements keep their full detail, including the **Solutions** list, which makes this the fastest audit of what your [`elementFilters`](/accessibility/configuration/elementfilters) and [`data-a11y-ignore`](/accessibility/configuration/ignoring-rules-per-element) rules are hiding.

### <Icon name="angle-right" /> How do I get from an accessibility violation to the test that found it?

Use the **Test Replay** button above the snapshot. It shows how many tests reached that page state and opens [Test Replay](/cloud/features/test-replay) for any of them, so you can see which spec ran, which commands led there, and what the application was doing just before the element was captured.

## Local development

### <Icon name="angle-right" /> Can I get Cypress Accessibility results without waiting for CI?

Yes. Record the specs you're working on from your own machine with `cypress run --record --spec "cypress/e2e/checkout.cy.js"`. Cypress Accessibility is generated in Cypress Cloud from the run's [Test Replay](/cloud/features/test-replay) data, so a run recorded from your laptop is processed exactly like a CI run: same App Quality Config, same Axe Core® version, same element identification. Limiting the run with `--spec` keeps the report to the code you changed and shortens the feedback loop to a couple of minutes. See [Local development](/accessibility/guides/local-development).

### <Icon name="angle-right" /> Does cypress open produce a Cypress Accessibility report?

No. Interactive mode never records a run to Cypress Cloud, and reports are only generated for recorded runs. Use `cypress run --record` to get accessibility results from your machine.

### <Icon name="angle-right" /> Which browser should I use to record a local run for Cypress Accessibility?

Chrome, Edge, Chromium, or Electron. Reports are built from [Test Replay](/cloud/features/test-replay) data, which is only captured in Chromium-based browsers, so a run recorded with `--browser firefox` or `--browser webkit` produces no accessibility report. `cypress run` defaults to Electron, which is supported, so you get a report without passing `--browser` at all. See [No accessibility report was generated for a run](/accessibility/troubleshooting#No-accessibility-report-was-generated-for-a-run) for the other requirements.

### <Icon name="angle-right" /> How do I check an accessibility fix before I push my branch?

Record the same specs twice and compare the two Cypress Accessibility reports in [Branch Review](/accessibility/guides/compare-reports): once from your base branch before you start (or with your changes stashed), then again from your branch after the fix. Set your branch's run as the Changed run and the base branch's run as the Base run. **Resolved elements** confirms the rule you fixed cleared everywhere it was failing, and **New failed elements** catches the violation the fix introduced. Recording the same specs in both runs is what makes the comparison meaningful. See [Local development](/accessibility/guides/local-development).

### <Icon name="angle-right" /> Can I use the Cypress Accessibility Results API on my local machine?

No. `getAccessibilityResults()` identifies which run to report on from the CI environment variables present when the run was recorded, so running it outside CI fails with "It appears you are not running in CI." The Results API is for enforcing a policy in your pipeline. For local feedback, read the report in Cypress Cloud, compare runs in Branch Review, or query results through [Cypress Cloud MCP](/cloud/integrations/cloud-mcp).

### <Icon name="angle-right" /> Is my Cypress Accessibility score from a local run comparable to my CI score?

No, and it isn't meant to be. A run's [accessibility score](/accessibility/core-concepts/accessibility-score) averages every snapshot in that run, so a two-spec local run and a full CI suite have different denominators. Compare rules and failed element counts between two local runs of the same specs, and track the score on your full suite.

### <Icon name="angle-right" /> Why does my local Cypress Accessibility report include pages my CI report excludes?

Your [`viewFilters`](/accessibility/configuration/viewfilters) patterns most likely name a deployed hostname, and hostnames must match exactly, so a rule for `https://app.example.com/*` never matches `http://localhost:3000`. Write path-only patterns like `/auth/*`, which match any protocol, hostname, and port, or add a [`profiles`](/accessibility/configuration/profiles) entry for local runs and tag them with `--tag`. See [Make your configuration match localhost](/accessibility/guides/local-development#Make-your-configuration-match-localhost).

### <Icon name="angle-right" /> Why is my Cypress Accessibility report not ready as soon as the run finishes?

Each spec's data starts processing as it uploads, but the run-level report is assembled only after Cypress Cloud marks the run complete. For grouped and parallelized runs, completion waits out the project's [Run Completion Delay](/cloud/features/smart-orchestration/parallelization#Run-Completion-Delay), a grace period of 60 seconds by default that lets late machines join, and report finalization waits with it. A single run recorded without `--group` or `--parallel` skips that delay and completes as soon as its specs are done, which is why local runs turn around quickly. To speed up a grouped run, shorten the delay in [project settings](/cloud/account-management/projects#Run-Completion-Delay) or close the run with the [Run Completion API](/cloud/features/smart-orchestration/parallelization#Run-Completion-API).

### <Icon name="angle-right" /> How do I keep local runs from cluttering my Cypress Cloud project?

Tag them with `cypress run --record --tag "local"`. Tags appear on the run and are filterable in Cypress Cloud, so everyone can skip past them in the run list. A separate Cypress Cloud project for local runs is possible but costs you the comparison workflow, since Branch Review compares runs within one project and App Quality Config is per project. Every recorded run consumes [test results](/cloud/account-management/billing-and-usage#Cloud-test-results) from your plan regardless of where it ran, which is another reason to keep local runs scoped with `--spec`.

## Detecting changes

### <Icon name="angle-right" /> How do I find which pull request introduced a Cypress Accessibility violation?

Open [Branch Review](/accessibility/guides/compare-reports) in Cypress Cloud with the pull request's run as the Changed run and the base branch's run as the Base run. The **New failed elements** section lists only the violations that appear in the Changed run and not in the Base run, grouped by rule and view, with a page snapshot for each. If the violation predates the pull request, keep the Changed run fixed and move the Base run backwards through earlier runs until the violation stops showing as new. See [Catch accessibility regressions](/accessibility/guides/detect-changes).

### <Icon name="angle-right" /> Does Cypress Accessibility fail my build when a new violation appears?

No. Reports are generated in Cypress Cloud after your tests upload, so a Cypress run never fails because of an accessibility violation, and there is no performance cost to your tests. Blocking a build is an opt-in step you add with the [Results API](/accessibility/connect-and-extend/results-api), which fetches the run's results in CI so you can decide what should fail. See [Block pull requests and set policies](/accessibility/guides/block-pull-requests).

### <Icon name="angle-right" /> Should I block builds on failing rules or on the Cypress Accessibility score?

Rules are the stricter and more reliable signal in a Cypress Accessibility report: a rule going from zero failures to any failures is a real change in the application, traceable to the build that introduced it. Element counts and the score move on their own as tests reach different states and existing broken components get reused, which makes them better suited to monitoring runs and score thresholds than to gating individual pull requests. Many teams use both, with a rule policy on pull requests and a score threshold on scheduled runs. See [Enforce a standard in CI](/accessibility/guides/detect-changes#enforce-a-standard-in-ci).

### <Icon name="angle-right" /> Can I compare accessibility reports from two different Cypress projects?

No. Branch Review compares two runs within a single project, and App Quality Config is set per project, so cross-project comparisons are not available. If two teams need separate reports for the same application, use [profiles](/accessibility/configuration/profiles) to give each team's runs its own configuration inside one project, which keeps comparisons working.

### <Icon name="angle-right" /> Why does Cypress Accessibility show new failed elements in Branch Review when I didn't change that code?

The most common cause is unstable element identification. Cypress Accessibility matches elements between runs by the identifier described in [element identification](/accessibility/core-concepts/element-identification), so a hashed CSS-in-JS class or a framework-generated ID that changes per build makes one element look like a resolved failure plus a new failure. Exclude those values with [`attributeFilters`](/accessibility/configuration/attributefilters). Views can drift the same way when URLs contain IDs or slugs, which [`views`](/accessibility/configuration/views) rules resolve. See [Make the comparison trustworthy](/accessibility/guides/detect-changes#Make-the-comparison-trustworthy).

### <Icon name="angle-right" /> Why does my Cypress Accessibility comparison show a long list of resolved elements after a small change?

The two runs most likely did not cover the same ground. Cypress Accessibility compares what each run actually saw, so if the Base run recorded the full suite and the Changed run recorded a few specs, everything on the pages that were not visited is reported as resolved. Record the same specs on both sides of the comparison. See [Accessibility feedback during local development](/accessibility/guides/local-development).

### <Icon name="angle-right" /> What are existing failed elements in a Cypress Accessibility comparison?

They are the violations present in both runs, which is everything the change neither introduced nor fixed. Cypress Accessibility keeps them out of the Branch Review diff and links to the full report for the Changed run instead, so new and pre-existing findings are never mixed together in the same list. See [Compare reports](/accessibility/guides/compare-reports).

### <Icon name="angle-right" /> Why does Branch Review say my Cypress Accessibility changes are not ready yet?

At least one of the two runs has not finished processing its report. Reports are assembled after Cypress Cloud marks a run complete, and grouped or parallelized runs also wait out the project's [Run Completion Delay](/cloud/features/smart-orchestration/parallelization#Run-Completion-Delay). Reload once both runs are complete. If a run was cancelled, timed out, or re-ran only its failed specs or tests under [Re-run optimization](/cloud/features/smart-orchestration/rerun-optimization), its Cypress Accessibility report is marked partial and Branch Review says so, because a diff built on partial data can be misleading.

### <Icon name="angle-right" /> Why did my Cypress Accessibility score change when no application code changed?

Four things move a score without a code change: someone edited the App Quality Config, which is worth checking first because a new filter or view rule changes what is counted; the tests reached different pages or states than usual; content changed in the environment under test, such as a published image without alternative text; or the Axe Core® version was updated. The Results API exposes both `config` and `axeVersion` so you can rule the last two in or out. See [Notice when the report itself changes](/accessibility/guides/detect-changes#Notice-when-the-report-itself-changes).

### <Icon name="angle-right" /> How do I detect accessibility regressions with Cypress on a site that isn't tied to pull requests?

Record the Cypress project on a schedule against staging or production and compare consecutive runs in Branch Review, which works even when every run is on the same branch. This catches the changes no pull request would show, such as published content, a new version of an embedded third-party widget, or a feature flag enabling untested UI. See [Production monitoring](/accessibility/guides/production-monitoring).

### <Icon name="angle-right" /> Can Cypress notify my team when accessibility results are ready?

Yes. The [Slack](/cloud/integrations/slack) and [Microsoft Teams](/cloud/integrations/microsoft-teams) integrations include the accessibility score, failed rules by severity, and failed element count in run notifications, and can be filtered by run tag or run group. For conditional alerts, act on the [Results API](/accessibility/connect-and-extend/results-api) response in CI, which includes deep links per rule and per view so a notification can point at the exact failure. To push the report to your own endpoint when it finishes, use [Accessibility webhooks](/accessibility/connect-and-extend/webhooks) and subscribe to `run.accessibility.completed`.

### <Icon name="angle-right" /> How do I track Cypress Accessibility trends across projects over time?

Use the [Cypress Accessibility](/cloud/features/analytics/enterprise-reporting#Cypress-Accessibility) tab of [Enterprise Reporting](/cloud/features/analytics/enterprise-reporting) for scores, severity breakdowns, and weekly violation trends, filtered by date range, team, project, and branch. The same data is available through the [Data Extract API](/cloud/integrations/data-extract-api) with the `accessibility-per-project-summary`, `accessibility-per-project-over-time`, and `accessibility-details` reports. See [Track trends over time](/accessibility/guides/detect-changes#track-trends-over-time).

## Ignoring elements

### <Icon name="angle-right" /> How do I exclude elements from Cypress Accessibility?

Add an [`elementFilters`](/accessibility/configuration/elementfilters) rule with `include: false` for a CSS selector that matches the elements. Their failed and incomplete checks move to the **Ignored** status and stop counting against your views and your [accessibility score](/accessibility/core-concepts/accessibility-score). This is the standard way to handle third-party widgets whose violations you can't fix. To ignore only specific rules for an element, use the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) instead, and to ignore entire pages, use [`viewFilters`](/accessibility/configuration/viewfilters).

### <Icon name="angle-right" /> Do ignored elements affect my Cypress Accessibility score?

No. An element ignored by [`elementFilters`](/accessibility/configuration/elementfilters) doesn't count as a failed or incomplete element, and its results don't affect the score. It stays visible in the report under the **Ignored** status so you can always audit what your configuration ignores.

### <Icon name="angle-right" /> Why didn't my Cypress Accessibility score improve after ignoring an element?

The [accessibility score](/accessibility/core-concepts/accessibility-score) weighs each failed rule per snapshot, not each failing element. If a rule has several failing elements in a snapshot and you ignore only some of them, the rule still counts against that snapshot and the score doesn't change. The rule stops affecting the snapshot's score once all of its failing elements there are ignored.

### <Icon name="angle-right" /> Why is an element still failing in Cypress Accessibility after I added an elementFilters rule?

The most common causes are:

- The selector matches a container instead of the element itself. Rules use standard CSS matching against the element with the result, so `footer` matches only the `<footer>` element. Match the container and its descendants, like `footer, footer *`, to ignore a whole region.
- The rule has a `documentScope` that doesn't match the element's iframe or shadow DOM hosts.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> Why do ignored elements still appear in my Cypress Accessibility report?

This is by design. Ignored elements appear under the **Ignored** [element status](/accessibility/reports/run-level-reports#Elements) rather than being removed, so the report always shows what your configuration is hiding. They don't count as failed or incomplete elements, and they don't affect your score.

### <Icon name="angle-right" /> Can I ignore elements in Cypress Accessibility without affecting UI Coverage?

Yes. An `elementFilters` list at the root of your configuration applies to both products, but nesting it under an `accessibility` or `uiCoverage` key applies it to that product only. A nested list completely replaces a root-level one for that product, and the two are not merged. See [Exclude elements](/accessibility/configuration/elementfilters#Scope).

### <Icon name="angle-right" /> Does include: true do anything in Cypress Accessibility?

Not on its own. Every element is included unless an exclude rule matches it, and an include rule can't protect an element from exclusion. The value matters in root-level `elementFilters` lists shared with UI Coverage, where include rules do protect their elements. See [When to use include: true](/accessibility/configuration/elementfilters#When-to-use-include-true).

## Grouping and naming views

### <Icon name="angle-right" /> Why do similar URLs show up as separate views in my Cypress Accessibility report?

Automatic grouping only replaces path segments that are numbers or IDs (UUIDs and UUID-like values) with a wildcard. Segments like usernames or slugs aren't recognized as dynamic, so `/users/alice` and `/users/bob` stay separate views, and a violation on that shared template is reported once per URL. Add a [`views`](/accessibility/configuration/views) pattern to group them into one view and triage the issue once.

### <Icon name="angle-right" /> Do query parameters create separate views in Cypress Accessibility?

No. Query strings are ignored when grouping, so `/dashboard?tab=overview` and `/dashboard?tab=settings` become a single `/dashboard` view. If a query parameter meaningfully changes the page, use a [`views`](/accessibility/configuration/views) pattern with `groupBy` on that parameter to report on each value separately.

### <Icon name="angle-right" /> How do I create a separate Cypress Accessibility view for each value of a URL parameter?

Write a [`views`](/accessibility/configuration/views) pattern that names the parameter, then list that name in `groupBy`. For a pattern like `/analytics/:type/:id`, `groupBy: ["type"]` creates a distinct view for each `type` value (such as `/analytics/performance/:id` and `/analytics/usage/:id`) while still collapsing the dynamic `:id`. `groupBy` accepts a single string or an array of strings, and each name can come from the path, query string, or hash. See [Using groupBy](/accessibility/configuration/views#Using-groupBy).

### <Icon name="angle-right" /> Does grouping URLs into a view change my Cypress Accessibility score?

Not your run-level score. The [run score](/accessibility/core-concepts/accessibility-score) averages every snapshot in the run regardless of how snapshots are grouped, so grouping URLs into a view reorganizes the report without moving the top-line number. What changes is the per-view score: the snapshots you group roll up into one view's score instead of several, which makes each page's accessibility easier to read and track over time.

### <Icon name="angle-right" /> What's the difference between views and viewFilters in Cypress Accessibility?

They do opposite things. [`views`](/accessibility/configuration/views) _keeps_ URLs but changes how they're grouped and named, so related pages collapse into a single view or a dynamic route splits into several. [`viewFilters`](/accessibility/configuration/viewfilters) _removes_ URLs, so matching snapshots are never scanned and don't appear in your report or score. Use `views` to organize the pages you scan, and `viewFilters` for pages you don't own or intend to remediate.

### <Icon name="angle-right" /> Can I configure views for Cypress Accessibility without affecting UI Coverage?

No. Unlike [`viewFilters`](/accessibility/configuration/viewfilters) and [`elementFilters`](/accessibility/configuration/elementfilters), `views` is defined only at the root of your configuration and can't be nested under an `accessibility` or `uiCoverage` key. A single set of view patterns groups URLs the same way for both products. To exclude a URL from one product only, use a nested `viewFilters` list instead. See [Scope](/accessibility/configuration/views#Scope).

## Ignoring views and URLs

### <Icon name="angle-right" /> How do I exclude URLs from Cypress Accessibility?

Add a [`viewFilters`](/accessibility/configuration/viewfilters) rule with `include: false` for a URL pattern. Snapshots from matching URLs are not scanned for accessibility violations and don't appear in your report. This is the standard way to keep third-party pages your tests pass through, such as an OAuth provider's login page, out of your results.

### <Icon name="angle-right" /> Can I exclude URLs from Cypress Accessibility without affecting UI Coverage?

Yes. A `viewFilters` list at the root of your configuration applies to both products, but nesting it under an `accessibility` or `uiCoverage` key applies it to that product only. A nested list completely replaces a root-level one for that product, and the two are not merged. See [Exclude views](/accessibility/configuration/viewfilters#Scope).

### <Icon name="angle-right" /> Why is a URL still in my Cypress Accessibility report after I excluded it with viewFilters?

The most common causes are:

- An earlier rule matches the URL first. Rules apply in order and the first match wins, so a broad `include: true` rule listed before your exclusion prevents it from ever applying.
- The pattern doesn't match the full URL. Hostnames must match exactly (`https://my-app.com/*` doesn't match `www.my-app.com`), or you can use a path-only pattern like `/admin/*` to match any hostname.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

See [troubleshooting view filters](/accessibility/configuration/viewfilters#A-URL-you-excluded-still-appears-in-the-report) for details.

## Element identification

### <Icon name="angle-right" /> Which attributes does Cypress Accessibility use to identify elements?

Cypress Accessibility checks a prioritized list of attributes on each element: `data-cy`, `data-test`, `data-testid`, `data-test-id`, `data-qa`, and `row-id`, in that order, falling back to `id`, `name`, `class`, and other DOM signals when none of those uniquely identify the element. See [Element identification](/accessibility/core-concepts/element-identification) for how identification works across snapshots.

### <Icon name="angle-right" /> How do I make Cypress Accessibility use my own attribute in violation selectors?

Add the attribute name to [`significantAttributes`](/accessibility/configuration/significantattributes). Attributes you list are checked before the default list, in the order you list them, so an attribute your application already renders, such as `data-component`, can identify elements and appear as the violation target selector in your reports.

### <Icon name="angle-right" /> Does significantAttributes replace the default attribute list in Cypress Accessibility?

No. Your attributes are checked first, and the defaults still apply after them, so an element without any of your attributes is identified exactly as it would be without configuration. Listing a default attribute like `data-qa` promotes it above the other defaults. To stop an attribute from being used at all, use [`attributeFilters`](/accessibility/configuration/attributefilters) instead.

### <Icon name="angle-right" /> Can I use aria-label as a significant attribute to review my labels?

Yes. Any valid HTML attribute qualifies, not only `data-*` attributes. Listing [`aria-label`](/accessibility/configuration/significantattributes) identifies elements by their label text, so the elements you triage are shown by their labels. This adds a manual check on top of the automated one: Cypress Accessibility confirms that a control has an accessible name, but not that the name is understandable, so `aria-label="button"` passes the same name-presence rules as `aria-label="Close dialog"`. Seeing the label as the identifier makes an unclear one easy to catch.

### <Icon name="angle-right" /> How do I add component or team context to my Cypress Accessibility violation selectors?

Use [`components`](/accessibility/configuration/components), a Cypress Accessibility-only option that adds attributes like `data-component` or `data-team` to the violation target selector when they're present on the element or one of its ancestors. Instead of a bare `[data-cy="signup"]`, the target reads as `[data-cy="signup"][data-component="IconButton"]`, so whoever picks up the issue, whether a developer, a Jira ticket, or an AI agent triaging through [Cypress Cloud MCP](/accessibility/work-with-ai-agents), can see which component or team it belongs to without opening the page HTML. This differs from [`significantAttributes`](/accessibility/configuration/significantattributes), which chooses the single attribute that _identifies_ the element, whereas `components` adds context on top of that identifier.

### <Icon name="angle-right" /> What's the difference between significantAttributes and components in Cypress Accessibility?

Both put your attributes into violation target selectors, but they play different roles. [`significantAttributes`](/accessibility/configuration/significantattributes) chooses the single attribute that _identifies_ an element, so `["data-component"]` makes the selector `[data-component="SearchInput"]` instead of a test id or generated selector. [`components`](/accessibility/configuration/components) _adds_ attributes on top of whatever already identifies the element, so a selector stays `[data-cy="signup"]` but gains `[data-component="IconButton"]`. Use `significantAttributes` when your attribute is the best identifier, and `components` when you want to keep the identifier but append component, team, or page context around it.

### <Icon name="angle-right" /> Why isn't my components attribute showing up in my Cypress Accessibility selectors?

The most common causes are:

- The attribute isn't on the element or any of its ancestors. `components` keeps a listed attribute wherever it appears on the element or an ancestor, but it can't add one that isn't in the DOM.
- `includeInSelector` is `false`, which keeps the entry for documentation but doesn't change selectors.
- A [`componentAttributeFilters`](/accessibility/configuration/components#componentAttributeFilters) rule with `include: false` matches the value, so it's skipped.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> Can I keep certain component attribute values out of my Cypress Accessibility selectors?

Yes. Add a [`componentAttributeFilters`](/accessibility/configuration/components#componentAttributeFilters) rule with `include: false` for the values you don't want appended, matched by regex. This is useful when an attribute is meaningful on some elements but generic on others, such as a `data-component` that's a specific component in most places but a layout primitive like `Box` elsewhere. The default attribute filters that drop dynamic values from _identifying_ selectors don't apply to component attributes, so `componentAttributeFilters` are the only way to filter them.

## Configuration

### <Icon name="angle-right" /> Where do I set Cypress Accessibility configuration?

In the **App Quality** tab of your project settings in Cypress Cloud. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration).

### <Icon name="angle-right" /> Do I need to rerun my tests after changing configuration?

No. You can regenerate any historical run from its **Properties** tab, and the report is reprocessed with the current configuration. This lets you iterate on configuration and see the effects immediately without running your Cypress tests again.

### <Icon name="angle-right" /> How do I apply a setting to Cypress Accessibility without changing UI Coverage?

Nest the property under an `accessibility` key. `viewFilters`, `elementFilters`, `significantAttributes`, and `attributeFilters` apply to both products when set at the root, but a copy nested under `accessibility` applies to Cypress Accessibility alone. A nested value completely replaces the root value for that product rather than merging, so repeat any rules you still want. `views` is the exception: it's shared and can only be set at the root. See [Configuration scope](/accessibility/configuration/overview#Configuration-scope).

### <Icon name="angle-right" /> Can I read the configuration a Cypress Accessibility run was processed with?

Yes, two ways. In Cypress Cloud, open the run's **Properties** tab to see the exact configuration that was applied. In CI, the [Accessibility Results API](/accessibility/connect-and-extend/results-api) exposes it on the `config` property of `getAccessibilityResults()`, where `config.value` is the applied App Quality configuration and `config.updatedAt` is when it was last saved. See [Viewing configuration for a run](/accessibility/configuration/overview#Viewing-Configuration-for-a-Run).

### <Icon name="angle-right" /> How do I add a note explaining a Cypress Accessibility configuration rule?

Add a `comment` property to the rule. Any rule defined as an object accepts one, and it's the supported place for notes because Cypress Cloud rejects properties it doesn't recognize. Comments live in your Cypress Accessibility configuration only and never appear in reports. See [Comments](/accessibility/configuration/overview#Comments).

## Accessibility standards

### <Icon name="angle-right" /> Does Cypress Accessibility make my application WCAG conformant or ADA compliant?

No automated tool can determine that, and Cypress Accessibility doesn't claim to. What it reports is factual and narrow: which Axe-Core® rules passed, failed, or couldn't be evaluated on the pages and components your tests visited, on a specific run, with a recorded rule configuration and Axe-Core® version.

Determining conformance with the Web Content Accessibility Guidelines (WCAG), published by the W3C, requires human assessment of criteria no scanner can evaluate. Laws and procurement rules in different regions, including the Americans with Disabilities Act (ADA) in the United States, Section 508 for US federal agencies and their suppliers, and the European Accessibility Act (EAA), commonly point to WCAG as the technical reference. How any of those obligations apply to your organization is a legal question for you and your advisors, not an output of a testing tool. See [accessibility automation principles](/accessibility/guides/accessibility-automation) for where automated checks stop.

### <Icon name="angle-right" /> Which WCAG version and level do the Cypress Accessibility rules cover?

By default, a run evaluates Axe-Core®'s default ruleset: rules tagged for WCAG 2.0 and WCAG 2.1 Level A and AA, plus Deque's Best Practices rules. Three WCAG-tagged rules are turned off by default in Cypress Accessibility, and Axe-Core®'s WCAG 2.2, Level AAA, experimental, and deprecated rule groups are off unless you enable them with [`axeConfig`](/accessibility/configuration/axe-core-configuration). This means the default report is broader than any single WCAG level in one sense, because Best Practices findings are Deque recommendations rather than WCAG success criteria, and narrower in another, because it doesn't run every WCAG-tagged rule. See [What the default ruleset covers](/accessibility/configuration/axe-core-configuration#what-the-default-ruleset-covers).

### <Icon name="angle-right" /> Can Cypress Accessibility run WCAG 2.2 or Level AAA rules?

Yes. Axe-Core® ships those rules but keeps them off by default. Enable them for your project with [`axeConfig`](/accessibility/configuration/axe-core-configuration) in the App Quality editor, using `runOnly` with the relevant tags or per-rule `rules` overrides. After you save, regenerate a historical run to preview the effect before adopting it on new runs.

### <Icon name="angle-right" /> Can I use Cypress Accessibility results in a VPAT or accessibility conformance report?

You can reference them as one source of evidence, but they don't produce the document. A VPAT or accessibility conformance report is written by people evaluating a product against each criterion, and automated results speak only to the subset of criteria a scanner can check, on the pages and components your tests happened to visit.

What Cypress Accessibility contributes is a durable, dated record: every run permanently stores the rule configuration and Axe-Core® version it was processed with, viewable in the run's **Properties** tab, and the [Results API](/accessibility/connect-and-extend/results-api) exposes per-rule and per-view results you can archive alongside your own assessment notes.

### <Icon name="angle-right" /> Does a 100% Cypress Accessibility score mean my application is accessible?

No. A 100% score means Axe-Core® detected no violations in the scope your tests covered, with the rules that were enabled for that run. It says nothing about criteria automated checks can't evaluate, such as whether a label is understandable, whether focus order matches the visual layout, or whether the experience works for someone using a screen reader end to end. Automated checks detect around [57% of the issues a manual audit surfaces](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/). Treat a clean report as a solid foundation and a signal that your team is actively managing accessibility, not as a finished state. See [What a 100% score means](/accessibility/core-concepts/accessibility-score#What-a-100-score-means).

## Axe Core® rules

### <Icon name="angle-right" /> Which accessibility rules does Cypress Accessibility run?

Cypress Accessibility runs [Axe-Core®](https://github.com/dequelabs/axe-core)'s default ruleset against every captured snapshot, plus a few [custom Cypress rules](/accessibility/core-concepts/cypress-rules). That covers WCAG 2.0 and 2.1 Level A and AA, along with Deque's Best Practices rules, which are recommendations rather than WCAG success criteria. Rule groups that Axe-Core® keeps off by default, including WCAG 2.2, Level AAA, experimental, and deprecated rules, don't run unless you enable them with [`axeConfig`](/accessibility/configuration/axe-core-configuration). Three further rules are [off by default](/accessibility/configuration/axe-core-configuration#rules-that-are-off-by-default) in Cypress Accessibility: `color-contrast`, `no-autoplay-audio`, and `meta-refresh`. You don't add any assertions or `cy.` commands to your tests to run these checks; they run automatically when Cypress Accessibility is enabled. See [What the default ruleset covers](/accessibility/configuration/axe-core-configuration#what-the-default-ruleset-covers).

### <Icon name="angle-right" /> Can I change which Axe-Core® rules Cypress Accessibility runs?

Yes. Set [`axeConfig`](/accessibility/configuration/axe-core-configuration) under the `accessibility` key in the App Quality editor to enable a rule that's off by default, turn off a rule that's a known false positive, or scope the report to a WCAG conformance target with `runOnly`. To ignore a rule for individual elements, use the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) in your application code.

### <Icon name="angle-right" /> Why isn't color contrast reported in my Cypress Accessibility results?

Color contrast checking is off by default in Cypress Accessibility because it's the slowest Axe-Core® rule and the most likely to produce false positives or incomplete results. It works well in many projects; enable it with [`axeConfig`](/accessibility/configuration/axe-core-configuration):

```json title="App Quality Config"
{
  "accessibility": {
    "axeConfig": {
      "rules": {
        "color-contrast": { "enabled": true }
      }
    }
  }
}
```

See [Rules that are off by default](/accessibility/configuration/axe-core-configuration#rules-that-are-off-by-default).

### <Icon name="angle-right" /> How do I stop Cypress Accessibility from reporting a rule I can't fix?

You have three options in Cypress Accessibility, from broadest to narrowest. Disable the rule project-wide with [`axeConfig`](/accessibility/configuration/axe-core-configuration); ignore the rule for specific elements yourself with the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element); or leave the rule on and control whether it blocks your build in CI with the [Results API](/accessibility/connect-and-extend/results-api). Keeping a rule reported but non-blocking is often the best choice, since you retain visibility into the issue.

### <Icon name="angle-right" /> Does Cypress Accessibility work with component tests?

Yes. Cypress Accessibility runs against component tests as well as end-to-end tests. Because a component is usually a page fragment, "page-level" rules that check page structure and document-wide attributes don't run for component tests, while the rest of the ruleset does. See [Component testing](/accessibility/configuration/axe-core-configuration#component-testing).

### <Icon name="angle-right" /> Why does Cypress Accessibility skip some rules for my component tests?

Cypress Accessibility skips page-level rules such as `region`, `landmark-one-main`, and `document-title` for [component tests](/accessibility/configuration/axe-core-configuration#component-testing). A component is usually a fragment of a page, so rules that assert on overall page structure would report failures that don't apply to a component in isolation. Rules that evaluate the component itself, such as `button-name` and `image-alt`, still run.

### <Icon name="angle-right" /> Which version of Axe-Core® does Cypress Accessibility use?

Cypress Accessibility pins a specific, tested version of Axe-Core® and waits at least 30 days before adopting a new release, so new or changed rules don't alter your results without warning. The exact version used for a run is shown in that run's **Properties** tab in Cypress Cloud and in the [Results API](/accessibility/connect-and-extend/results-api) response. See [Axe-Core® library version and updates](/accessibility/configuration/axe-core-configuration#axe-core-library-version-and-updates).

## Profiles

### <Icon name="angle-right" /> How do I apply different Cypress Accessibility settings to different runs?

In your project's App Quality configuration in Cypress Cloud, add a [`profiles`](/accessibility/configuration/profiles) array, give each profile a `name`, and record the run with a matching [`--tag`](/app/references/command-line#cypress-run-tag-lt-tag-gt). When a run's tag matches a profile's `name`, that profile's `config` overrides your base Cypress Accessibility configuration for that run, so a smoke run and a full regression run can each use their own settings without changing your test code. If no tag matches, the base configuration is used unchanged.

### <Icon name="angle-right" /> Does a Cypress Accessibility profile override my base configuration or merge with it?

Cypress Cloud overrides one property at a time with a shallow merge, not a deep merge. Any property the profile lists replaces the root value for that property entirely (arrays are replaced, not concatenated), so if a profile defines [`elementFilters`](/accessibility/configuration/elementfilters), repeat any root rules you still want to keep. Properties the profile doesn't mention are inherited from the root. The `accessibility` and `uiCoverage` objects merge one level deep, so a profile can override `accessibility.viewFilters` while still inheriting `accessibility.attributeFilters`. See [How a profile changes your configuration](/accessibility/configuration/profiles#How-a-profile-changes-your-configuration).

### <Icon name="angle-right" /> If a run has multiple tags that match profiles, which Cypress Accessibility profile is used?

Cypress Cloud uses the first profile in the [`profiles`](/accessibility/configuration/profiles) array whose `name` matches one of the run's tags. The tie is broken by the order of the profiles array, not the order of the tags on the run, so reordering tags on the command line never changes which profile applies.

### <Icon name="angle-right" /> Why isn't my Cypress Accessibility profile applied even though I tagged the run?

The most common causes are:

- The run tag doesn't exactly match the profile `name`. Matching is case-sensitive and exact, so `aq-config-regression` matches only the tag `aq-config-regression`, not `AQ-Config-Regression` or `aq-config-regression-nightly`.
- The tag never reached Cypress Cloud. Profiles are selected from the tags passed to `cypress run --record --tag`, so a run recorded without `--record`, or without that specific `--tag`, falls back to the base configuration.
- An earlier profile in the array also matches one of the tags and is used instead, because the first match wins.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> Can a profile turn off Cypress Accessibility or skip a run entirely?

There's no dedicated "skip this run" switch in a profile. To suppress a report for certain runs, point a profile at a deliberately narrow configuration (for example, [`viewFilters`](/accessibility/configuration/viewfilters) that exclude every view) so Cypress Cloud produces an empty or tightly scoped accessibility report for the run instead. See [Why use profiles?](/accessibility/configuration/profiles#Why-use-profiles).

### <Icon name="angle-right" /> How do I make Cypress Accessibility checks on pull requests faster and more focused than regression runs?

Add a profile (for example, `aq-config-pr`) whose `config` narrows the report to your most critical flows with [`viewFilters`](/accessibility/configuration/viewfilters), then tag pull request runs with `cypress run --record --tag "aq-config-pr"`. The pull request report covers only those flows, so it's small and unambiguous for a developer to act on before merging, while regression runs record without the tag and keep the full base configuration. Combine the profile with the [Results API](/accessibility/connect-and-extend/results-api) to fail the build when a critical flow regresses. See [Block pull requests](/accessibility/guides/block-pull-requests#Using-Profiles-for-PR-specific-configuration).

### <Icon name="angle-right" /> Can a Cypress Accessibility profile change which Axe Core® rules run for a specific run?

Yes. Set [`axeConfig`](/accessibility/configuration/axe-core-configuration) under `accessibility` in a profile's `config` to enable, disable, or scope rules for tagged runs. A common pattern is a broader base ruleset for regression runs and a WCAG-scoped `runOnly` selection on a pull request profile. To ignore a rule only for certain elements, use the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) in your application code.

### <Icon name="angle-right" /> Can a Cypress Accessibility profile change how violation targets are identified, such as components or significantAttributes, for certain runs?

Yes. Anything you can set under an `accessibility` key can go in a profile's `config`, including [`components`](/accessibility/configuration/components) and [`significantAttributes`](/accessibility/configuration/significantattributes). Because the `accessibility` object merges one level deep, a profile can override just one of them, for example identifying elements by `aria-label` during a labels audit, while inheriting the rest. See [How a profile changes your configuration](/accessibility/configuration/profiles#How-a-profile-changes-your-configuration).

---

### Accessibility Troubleshooting (`docs/accessibility/troubleshooting.mdx`)

---
title: 'Troubleshooting: Cypress Accessibility'
description: 'Fix common Cypress Accessibility report problems: ignored elements that still appear, scores that do not improve, rules you cannot resolve yet, noise from third-party UI, unstable violation selectors, and configuration that has no effect.'
sidebar_label: Troubleshooting
sidebar_position: 150
---

<ProductHeading product="accessibility" />

# Troubleshooting Cypress Accessibility

Cypress Accessibility produces a report for every recorded run with no setup, running Axe Core® checks against the states your Cypress tests exercise. For most applications the defaults are accurate on their own. When a report doesn't match what you expect, the cause is usually one of a small, predictable set: configuration that hasn't been applied to the run yet, a filter that isn't matching, an unstable attribute in a violation's selector, or noise from parts of the page your team doesn't own.

This page maps each symptom to its cause and the configuration that resolves it. Because you can [regenerate](/accessibility/configuration/overview#Setting-Configuration) any past run with your current configuration, you can confirm every fix in minutes without re-running your Cypress tests, so the fastest path to a report you trust is to make one change, regenerate a recent run, and check the result.

:::tip Start here: regenerate the run after changing configuration

Every run is processed with the configuration that was saved **at that moment**, so edits you make afterward don't change an existing report until you reprocess it. This timing is the single most common reason a rule "doesn't work."

After saving configuration in the **App Quality** tab of your project settings, open a run's **Properties** tab and use its "regenerate" button. The configuration that was used for that run is displayed there, so you can confirm what was applied. Every configuration fix on this page assumes you regenerate the run afterward. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration).

:::

## No accessibility report was generated for a run

The run recorded to Cypress Cloud, but its **Accessibility** tab is empty or absent.

**Cause.** Reports are built in Cypress Cloud from the run's [Test Replay](/cloud/features/test-replay) data. When that data wasn't captured or wasn't uploaded, there is nothing to scan, so no report is produced. This is a different problem from a report that looks wrong, and none of the configuration fixes on this page apply to it.

**Fixes.** A recorded run produces an accessibility report when all of the following are true:

- **Cypress Accessibility is enabled for the project.** It's a paid premium solution, so a project on a plan without it records normally and produces no accessibility report.
- **The run was recorded** with `cypress run --record` and a valid record key, against a project with a `projectId`. Interactive mode (`cypress open`) never records a run, so it never generates results.
- **Cypress v13 or later** was used. Test Replay was introduced in Cypress 13.
- **Test Replay is enabled** in the project's settings in Cypress Cloud. A run recorded while it's turned off uploads no data to process.
- **The browser was Chromium-based or Electron.** Chrome, Edge, Chromium, and Electron capture Test Replay data. Firefox and WebKit do not, so `--browser firefox` and `--browser webkit` runs produce no accessibility report. `cypress run` defaults to Electron, which is supported.

When a report exists but is missing specific specs, check the terminal output from the run. Cypress prints the Test Replay upload status for every spec, and a spec that reports "Nothing to upload" or a capture failure contributes nothing to the accessibility report.

## An element you excluded still appears in the report

You added an [`elementFilters`](/accessibility/configuration/elementfilters) rule to remove an element, but it's still shown with violations in the report.

**Cause.** The rule was saved after the run was processed, the selector doesn't match the element, or an earlier rule already decided the element's fate. `elementFilters` selectors must match the element that Axe Core® reports, not a wrapper around it, and the **first** matching rule wins.

**Fixes.**

- **Regenerate the run** so the new rule is applied. This is by far the most common cause.
- **Check the selector** against the exact node in the violation's HTML snapshot. A rule like `footer` matches only the `<footer>` element itself, while `footer *` matches the controls inside it.
- **Order rules from specific to broad**, and place any `include: true` exception before the `include: false` rule it should override, because the first matching rule wins.

  ```json title="App Quality Config"
  {
    "elementFilters": [
      {
        "selector": ".intercom-launcher",
        "include": false,
        "comment": "Third-party chat widget, not part of our tested UI"
      }
    ]
  }
  ```

See [How are elementFilters rules applied?](/accessibility/configuration/elementfilters) for the full precedence rules.

## Your score didn't improve after excluding an element

You removed a failing element with [`elementFilters`](/accessibility/configuration/elementfilters), but the [accessibility score](/accessibility/core-concepts/accessibility-score) is unchanged or barely moved.

**Cause.** The score is based on the elements checked and the severity of the rules they fail, not on a simple count of nodes. Excluding one element removes only that element's contribution, and if the same rule still fails on other elements, or higher-severity issues remain elsewhere, the score stays roughly the same. Excluding elements is meant to remove genuinely irrelevant UI, not to raise a score.

**Fixes.**

- **Confirm the element was actually removed** using the section above, then look at whether the same rule still fails elsewhere.
- **Address the underlying violations** rather than filtering, when the elements are part of your application. See [Fix accessibility violations](/accessibility/guides/improve-accessibility) and [How the accessibility score is calculated](/accessibility/core-concepts/accessibility-score).

## A rule keeps failing and you can't resolve it yet

A known issue, a false positive, or a third-party defect is failing a rule, and you need to stop it from blocking work without hiding it everywhere.

**Cause.** Cypress Accessibility keeps results broad on purpose so you retain full visibility of every issue in Cypress Cloud. Deciding what should _block_ is a separate, opt-in step, so the right tool depends on whether you want to suppress a single element, change how a rule runs, or enforce a policy in CI.

**Fixes.**

- **Ignore a rule on one specific element** with the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) in your application markup, which is the most surgical option and keeps the rule active everywhere else.
- **Turn a rule off or adjust how Axe Core® runs** across the report with [`axeConfig`](/accessibility/configuration/axe-core-configuration), when a rule doesn't apply to your application at all.
- **Keep the rule visible but non-blocking** by handling it in your CI policy instead of in Cypress Cloud. The [Results API](/accessibility/connect-and-extend/results-api) gives you full control over which rules fail a build, so you can allow a known violation while still failing on anything new. See [Block pull requests and set policies](/accessibility/guides/block-pull-requests).

## Third-party or out-of-scope UI is adding noise

Chat launchers, cookie banners, analytics overlays, or entire pages you don't own are contributing violations that aren't yours to fix.

**Cause.** Cypress Accessibility checks whatever renders in the states your tests reach, including third-party widgets and any URL your tests visit. Each is reported until you exclude it.

**Fixes.**

- **Remove third-party elements** with [`elementFilters`](/accessibility/configuration/elementfilters), which drops them from the report and the score.
- **Exclude whole URLs you don't intend to cover** with [`viewFilters`](/accessibility/configuration/viewfilters). To keep only your own application's URLs, list `include: true` rules for them followed by a catch-all `{ "pattern": "*", "include": false }`; because the first matching rule wins, the catch-all must come last.

  ```json title="App Quality Config"
  {
    "viewFilters": [
      {
        "pattern": "https://status.my-app.com/*",
        "include": false,
        "comment": "External status page, linked from the footer but out of scope"
      }
    ]
  }
  ```

## Violation selectors use unstable or unhelpful identifiers

The selectors shown for a violation point at framework-generated `id`s or hashed classes, or the same real element appears under different selectors across snapshots, making issues hard to find and deduplicate.

**Cause.** Cypress Accessibility builds an element's identity from its attributes and position in the DOM (see [Element identification](/accessibility/core-concepts/element-identification)). When an identifying attribute changes on every render, the same element can be reported inconsistently. Cypress already ignores the most common unstable values, so add configuration only when your application produces unstable identifiers the built-in filters don't cover.

**Fixes.**

- **Prefer your own stable attribute** in violation selectors with [`significantAttributes`](/accessibility/configuration/significantattributes). Attributes you list are checked before the defaults, so a stable `data-cy` or `data-test` produces clearer, more consistent selectors. Listing `aria-label` also turns the report into an inventory of your label text.

  ```json title="App Quality Config"
  {
    "significantAttributes": ["data-cy"]
  }
  ```

- **Ignore the dynamic attribute** with [`attributeFilters`](/accessibility/configuration/attributefilters) so identification falls back to a stable attribute. When you filter a dynamic `id`, also filter the attributes that reference it, such as `for`, `aria-labelledby`, and `aria-describedby`. Patterns match the whole value (they're anchored as `^(...)$`), and JSON requires backslashes to be doubled, so a token like `\d` must be written `\\d`.

## A configuration rule has no effect

You saved a rule, but the report looks the same.

Work through these causes in order:

- **The run predates the change.** Reports use the configuration saved when they were processed. [Regenerate](/accessibility/configuration/overview#Setting-Configuration) the run to apply your current configuration. This is by far the most common cause.
- **An earlier rule matched first.** For [`elementFilters`](/accessibility/configuration/elementfilters) and [`viewFilters`](/accessibility/configuration/viewfilters), the **first** matching rule wins, so a broad rule above your specific one prevents it from applying. List specific rules first, and place `include: true` exceptions before the `include: false` rule they should override.
- **A nested list replaced a root one.** Nesting a shared property such as `elementFilters` or `attributeFilters` under an `accessibility` or `uiCoverage` key **completely replaces** the root-level list for that product; the two are never merged. Repeat any root rules you still want in the nested list.
- **The pattern or selector doesn't match.** `attributeFilters` patterns are anchored to the whole value, so `value: "user"` matches only the exact string `user`; use `value: "user-.*"` for a prefix. Selectors must match the element Axe Core® reports, not a wrapper around it.
- **The configuration didn't save.** Cypress Cloud validates against a strict schema and rejects any property it doesn't recognize, including a misspelled name, a value of the wrong type, or a freeform note on a field that doesn't accept one. Keep notes in a [`comment`](/accessibility/configuration/overview#Comments), and correct the flagged property so the configuration can save.

## A profile isn't being applied

You tagged a run to pick up a [profile](/accessibility/configuration/profiles), but the run used your base configuration instead.

**Cause.** Profiles are selected by matching a run's tags, and a profile applies only when the run carries a tag its rules match. A profile also **overrides** the base configuration for the matched run rather than merging with it, so a partial profile can look like "nothing changed" if you expected your base rules to still apply.

**Fixes.**

- **Confirm the run was tagged** with a value the profile matches, for example `cypress run --record --tag "aq-config-pr"`.
- **Include every rule the run needs in the profile**, since the profile replaces the base configuration for matched runs rather than merging.
- **Check tag precedence** when a run carries multiple matching tags. See [Profiles](/accessibility/configuration/profiles) and the profile questions in the [FAQ](/accessibility/faq).

## Still stuck?

- The [Cypress Accessibility FAQ](/accessibility/faq) answers focused questions about ignoring elements and URLs, element identification, configuration, and profiles.
- The [Configuration overview](/accessibility/configuration/overview) covers where configuration lives, how it's scoped, and how to regenerate reports.
- [How Cypress Accessibility works](/accessibility/core-concepts/how-it-works) and [How the accessibility score is calculated](/accessibility/core-concepts/accessibility-score) explain what the report measures.
- If a report still looks wrong after working through this page, reach out to your Cypress point of contact with a link to the run.

---

### Accessibility Work With Ai Agents (`docs/accessibility/work-with-ai-agents.mdx`)

---
title: Work with AI agents in Cypress Accessibility
description: 'Use AI assistants alongside Cypress Accessibility: query Cloud results with Cypress Cloud MCP, file violations into Jira or another issue tracker without duplicates, align reports with component identification settings, and explore local browser LLM workflows.'
sidebar_label: Work with AI agents
sidebar_position: 110
---

<ProductHeading product="accessibility" />

# Work with AI agents

AI coding assistants can speed up accessibility work when they have the right context. This guide outlines patterns that teams are adopting today.

## Cypress Cloud MCP {#Cypress-Cloud-MCP}

[Cypress Cloud MCP](/cloud/integrations/cloud-mcp) lets compatible agents pull run metadata, test results, and accessibility summaries from Cypress Cloud using structured tools instead of copy-pasting from the UI.

You can ask your LLM about what issues are present, what patterns exist, and how to break the reports into work units or manage other handoffs like reporting issues to your third-party vendors or content authors.

For example, an open-ended question like "Check the newest Cypress Accessibility results for this project and help me make an action plan to resolve them" should help your agent produce a useful summary of the current state and help quickly bucket things according to expected remediation paths and ownership.

### Example prompts

#### Basic

Here are some example prompts to try out:

> "Pull the Cypress Cloud Accessibility report for the latest run on this branch. List any critical or serious violations grouped by rule, and tell me which views are most impacted."

> "Using Cypress Cloud, get the "color-contrast" failures from run #142 scoped to the "/checkout" view. For each failing element, look at the local CSS and suggest a fix."

#### Advanced

**Deep dive on solving a specific issue:**

> You are a front-end expert focused on delivering an accessible product.
>
> The `<element_id>` selector was flagged as inaccessible by the Cypress Accessibility report. It `<element_status>` the `<rule_severity>` rule `<rule_name>` described as `<rule_label>`. The proposed solution is `<proposed_solution>`.
>
> First, verify the issue is actually a problem given how the code is constructed.
>
> If it is a valid issue, explain by briefly summarizing the fix in markdown so I can include it in my code review, then generate a plan to fix this issue (I must approve this plan before you make changes).
>
> If it is not an issue, note it and stop. If there are not enough details to reasonably solve this, explain what other information you need before making changes. If the information is within the Cypress Cloud, submit feedback to the Cypress team.

**Determine owners for issues based on specific roles at your company, and who needs to be involved or aware:**

> Using Cypress Cloud MCP, find the most recent run in this project with failed accessibility results and create an action plan that groups similar problems together and recommends suitable owners.
>
> Our team includes these roles developers, QA engineers, designers, product managers, marketers, and accessibility specialists. For each role, determine if they need to be Responsible, Accountable, Consulted, Informed, or not involved.

## Work with a downloaded report {#Work-with-a-downloaded-report}

The [**Download report** button](/accessibility/connect-and-extend/download-reports) on a run's Accessibility report exports the run's violations as a `.csv` or `.json` file. This gives an AI agent a complete, self-contained view of a run's accessibility results that it can read directly from disk—no Cloud connection or MCP setup required.

This pairs well with the [Cypress Cloud MCP](#Cypress-Cloud-MCP) approach rather than replacing it:

- **Cloud MCP** is best for live, interactive querying while you work—asking follow-up questions and drilling into specific rules or views on demand.
- **A downloaded report** is best when you want the agent to work over the full dataset at once—generating a chart, producing a written summary, or diffing two runs—and when you want a fixed artifact you can re-run the same analysis against later.

Each row in the file is one failed element for one rule on one view, and includes deep links back into the Cloud report. See [what's in the file](/accessibility/connect-and-extend/download-reports#Whats-in-the-file) for the full column list.

### Map violations to your components {#Map-violations-to-your-components}

The **Element** column is where a downloaded report becomes especially efficient for an agent. When you set up your [components configuration](/accessibility/configuration/components), each element's selector reflects a true hierarchy of your components instead of a raw DOM path. An agent can read that structure straight from the file to:

- **Spot patterns and trends** across rules and views—for example, that most `color-contrast` failures live inside a single design-system component, or that one component is responsible for a disproportionate share of a run's violations.
- **Trace an issue to its origin** in your component tree and source code, without re-parsing full-page HTML or crawling the codebase to locate the element.

Mapping raw DOM selectors back to the component and source file that produced them is normally the expensive part of agent-assisted accessibility work, in both effort and tokens. Carrying that hierarchy in the export up front means the agent spends its budget on analysis and fixes rather than on rediscovering where each element came from.

### Interpret the report

Drop the downloaded file into your project (or attach it to your chat) and ask the agent to summarize it. Because every row carries the rule, impact, element, and view, the agent can bucket and prioritize without any extra context.

> Read this accessibility report file and give me a summary: total violations, a breakdown by impact (critical, serious, moderate, minor), and the five rules with the most failing elements. Then list the three views with the most issues and suggest where I should start.

> Group the failures in this report by likely owner—developers, designers, and content authors—based on the rule and element. For each group, write a short, plain-language description of the work involved.

### Create charts and graphs

Since the export is structured data, an agent with code execution can turn it into visualizations without you writing any plotting code.

> Using this accessibility report, generate a bar chart of failing elements by rule severity, and a second chart of the top 10 rules by number of failing elements. Save them as images.

> Build a small HTML dashboard from this report file: a summary of totals by impact at the top, a table of views sorted by violation count, and a chart of the most common rules. Make it a single self-contained file I can open in a browser.

### Compare different reports

Download a report for each run you want to compare—for example, a `main` branch run and a feature-branch run—and ask the agent to diff them. This is a lightweight, offline complement to the [Branch Review](/accessibility/guides/compare-reports) comparison in Cypress Cloud, useful when you want the difference in writing or as data.

> Here are two accessibility reports, `report-main.json` and `report-branch.json`. Compare them and tell me which violations are new in the branch report, which were resolved, and which are unchanged. Group new issues by rule and view, and include the Element URL for each new issue so I can open it in Cypress Cloud.

> I've downloaded accessibility reports from our last four weekly runs. Chart the total number of failing elements over time, and call out any rule where failures increased week over week.

:::tip

Ask the agent to keep the **Element URL** and **View URL** values in its output. Every row links back to the live snapshot in Cypress Cloud, so a summary, chart annotation, or ticket can point straight to the issue in context.

:::

## File issues in your issue tracker

Triage usually ends in tickets, and typing them out one at a time is the slowest part of the job. An agent connected to both Cypress Cloud and your issue tracker can read the accessibility report for the latest run, check what has already been filed, and open only the tickets that are missing. Nothing new has to run in your pipeline, because the data comes from runs Cypress Cloud has already recorded.

Cypress supplies the read side of this workflow. Cloud MCP is read-only, so the write side comes from your tracker's own MCP server or CLI, which Jira, GitHub, and Linear all publish. Connect both to the same agent before you start.

:::note

For a single violation you are already looking at, the [Create Jira issue](/accessibility/reports/element-detail-view#Create-Jira-issue) button in Cypress Cloud is faster than any prompt. Reach for an agent when you have a report's worth of findings to file at once.

:::

### Decide what a ticket represents

Agree on this before the agent creates anything. It decides both the size of your backlog and whether next week's refresh can tell an existing ticket from a new one.

**Group by rule and view.** One ticket per rule per view is a good default: "Form elements must have labels on /checkout" is a unit of work someone can pick up and finish. A ticket per failing element buries the team in near-duplicates, and a ticket per rule across the whole application is usually too large to schedule.

**Give every ticket the same shape.** Ask the agent to follow a fixed convention: a label such as `cypress-accessibility` on everything it opens, a summary pattern such as `[Accessibility] <rule ID> on <view name>`, and a description holding the rule, the severity, the failing selectors, and the link back to the report in Cypress Cloud. The convention is what makes the next refresh cheap, because deduplication becomes a search for a label and a rule ID rather than a judgment call about whether two sentences describe the same problem.

**Group by component where it helps.** If your selectors carry [component names](#Map-violations-to-your-components), an agent can spot that one design-system component is behind failures on 15 views. That is one ticket for the component team rather than 15 for the page owners, so tell the agent which grouping you want.

### Plan first, then create

Run this in two passes. The first proposes tickets and checks them against your tracker without writing anything, so you see the batch before it exists. Replace the placeholders in both prompts:

- `<branch>` is the branch you track, such as `main`.
- `<projectId>` is your Cypress project ID, the `projectId` in your Cypress configuration file.
- `<tracker project key>` identifies the project in your issue tracker that the tickets are filed into, such as the Jira project key `WEB` or the repository `acme/storefront` in GitHub.

<CopyPrompt
  title="Plan tickets from the latest report"
  subtext="See which failures are already tracked, which regressed, and which need a new ticket."
  defaultCollapsed
  prompt={`Refresh our accessibility backlog using Cypress Cloud MCP, without creating anything yet.

1. Find the latest completed run on <branch> for project <projectId> and pull its accessibility report.
2. Group the failures into one proposed ticket per rule per view, sorted by severity. Include the failing element count and the Cypress Cloud link for each.
3. For each proposed ticket, search <tracker project key> in my issue tracker for a matching issue, open or closed in the last 90 days, matching on rule ID and view name.
4. Report three groups: already tracked and open, previously closed but failing again, and not tracked at all.`}
   >

### Plan tickets from the latest report

</CopyPrompt>

<CopyPrompt
  title="Create the missing issues"
  subtext="Open tickets for the untracked failures only, in a format you can find again next week."
  defaultCollapsed
  prompt={`Create issues in <tracker project key> for the untracked failures only. For each one: use the summary pattern [Accessibility] <rule ID> on <view name>, add the label cypress-accessibility, set priority from the rule severity, and put the rule description, the failing selectors, and the Cypress Cloud report link in the description.

Then list the issues you created with their keys, and tell me anything you skipped and why.`}

>

### Create the missing issues

</CopyPrompt>

Once you trust the sequence, save both prompts as a custom instruction or skill in your AI client so the whole team refreshes the backlog the same way. Keep the approval step between them: creating issues is a write, and reading the plan first is what keeps a batch you did not intend out of your tracker.

For a first sweep through a large backlog, work from a [downloaded report](#Work-with-a-downloaded-report) instead of live queries. Cloud MCP returns rule failures up to 25 at a time within a limit of 100 tool requests per hour, and a run with hundreds of failing elements can spend that budget on pagination alone. The file also carries an **Element URL** for every row, which is the link you want in the ticket body.

Refresh on a cadence that matches how fast the report changes, such as weekly against the latest `main` run. This workflow is for the backlog on your main branch: catching a violation a pull request is about to introduce is a different job, and a faster one, because nobody has to file anything. See [Catch accessibility regressions](/accessibility/guides/detect-changes) and [Block pull requests and set policies](/accessibility/guides/block-pull-requests).

## Optimizing Cypress Accessibility for MCP use cases

In general, it's a good idea to look carefully at the pages and elements included in your accessibility reports, to make sure the contents are things you are currently interested in having your agent triage.

You can learn how exclude pages or elements, mute known issues for certain elements, and reduce duplication in the [Cypress Accessibility configuration overview](/accessibility/configuration/overview).

There is also configuration for how elements are identified when failures are presented, which can flow directly into the MCP tools in a predictable way to speed up element identification in your codebase.

### Component identification techniques

Clear component boundaries make both human triage and agent-assisted fixes easier: violations are grouped predictably, and prompts can refer to the same names you see in Cypress Accessibility.

For LLM use-cases, a few lightweight signals from the page where an element locator can turn into a huge efficiency boost, avoiding the context and tokens needed to parse a full page of HTML or crawl large amounts of code. Instead, you can quickly and accurately identify where in your pages component tree a given element is, and what code rendered it.

If you don't have attributes like this already, you can ask your agent to add some to your builds with a prompt like this:

> Add meaningful `data-cy-component` attributes to the container elements of significant areas of the dom. These will be used for later identification of an element's position in a component tree when reporting accessibility issues, so it should be possible to identify just enough structure to easily find the element in the future, but not be overly verbose.

## Your browser's LLM tooling

If you use Google Chrome, you might have noticed the Gemini AI debugging assistant. Since Cypress Cloud provides fully rendered DOM snapshots for accessibility issues, you are only a few clicks from a debugging session with Chrome Developer Tools.

Here are the steps to follow for this process:

### 1. Click the Print-to-Console shortcut

This logs the exact element reference to your developer console, avoiding any need to inspect or move around the DOM manually, or use search tools to locate your element.

<DocsImage
  src="/img/accessibility/guides/working-with-ai-agents-print-to-console.png"
  width="75%"
  alt="Cypress Cloud accessibility issue view for the rule that all page content should be contained by landmarks, showing the failing CSS selector, action icons beside it, the Print to Console control with its tooltip visible, a Solutions summary stating that some content is not inside landmarks, and a narrow app preview with the affected region outlined."
/>

### 2. Move to the Elements panel

Right-click the element in the console and choose "Open in Elements panel". This will take you to the full DOM view with the element highlighted. You need to be here for the AI chat to correctly start with the element reference.

<DocsImage
  src="/img/accessibility/guides/working-with-ai-agents-open-in-elements-panel.png"
  width="75%"
  alt="Browser developer tools console showing a logged element. A context menu is open over the console output with 'Open in Elements panel' highlighted."
/>

### 3. Start a chat about this element

Right-click the highlighted element and choose "Debug with AI" and then "Start a chat". This will open the chat with this specific element.

<DocsImage
  src="/img/accessibility/guides/working-with-ai-agents-debug-with-ai-start-chat.png"
  width="75%"
  alt="Chrome DevTools Elements panel with a Material UI grid item div selected in the tree. A context menu on the element shows Debug with AI expanded to a submenu listing Start a chat, Assess visibility, and Center element. The Accessibility tab and an AI assistance tab appear in the surrounding tool UI."
/>

### 4. Ask about the issue

Use the "Share button" or copy the rule that is failing into the chat, and Gemini can explore the DOM, explain the rule in more detail, and offer solution options.

<DocsImage
  src="/img/accessibility/guides/working-with-ai-agents-test-runner-ai-assistance.png"
  width="75%"
  alt="Cypress Test Runner in a three-pane layout: on the left, New Cypress Accessibility Failures lists a moderate landmarks rule and a CSS selector for the failing element; the center shows the Real World App with a highlight on the navigation drawer; on the right, the AI assistance tab lists completed diagnostic steps such as reading styles and listing landmarks, then explains that drawer content sits outside landmark regions and suggests wrapping it in a nav element or role navigation."
/>

---

### Api AGENTS (`docs/api/AGENTS.md`)

# Agent rules: API reference pages

The root [`AGENTS.md`](../../AGENTS.md) still applies; this file adds the rules
specific to `docs/api/` (commands, `Cypress.*` APIs, node events, utilities).
Reasoning and examples live in
[`AGENTS_REFERENCE.md`](../../AGENTS_REFERENCE.md).

## Source of truth

These pages describe behavior implemented in `cypress-io/cypress`. Read that
source before writing or changing a behavior claim: `npm run api:source -- blur`
resolves a command to the files that define it. What each section is answerable
from, and why a conflict gets flagged rather than written away, is in
[`AGENTS_REFERENCE.md`](../../AGENTS_REFERENCE.md#api-source-of-truth).

## Frontmatter

Reference frontmatter is terse. Mirror the sibling file you're adding next to.

```yaml
---
title: 'cy.click()'
description: Click a DOM element in Cypress.
sidebar_label: click
slug: /api/commands/click
---
```

- `title`: the symbol as a reader writes it in code (`'cy.click()'`,
  `'Cypress.Promise()'`, `'before:spec event'`). Never append a suffix. Every
  page under `/api` gets ` | Cypress API Documentation` at build time from
  `src/sectionTitles.js`, asserted by `cypress/e2e/page_titles.cy.ts`.
- `description`: one sentence saying what the command does.
- `sidebar_label`: the bare name, no `cy.` prefix, no parentheses.
- `slug`: only where the siblings carry one. It repeats the file's own route, so
  `docs/api/cypress-api/` omits it entirely.
- The H1 is the bare name (`# click`), not the title.

## Page skeleton

`<ProductHeading product="app" />` goes above the H1. Then these sections, in
this order, using only the ones the page needs:

| Section          | Contents                                                                                                      |
| ---------------- | ------------------------------------------------------------------------------------------------------------- |
| `## Syntax`      | signatures in a `javascript` block, then `### Usage` (correct/incorrect), `### Arguments`, `<HeaderYields />` |
| `## Examples`    | grouped under `###` headings, usually by argument shape; option or workflow groups are fine where they help   |
| `## Notes`       | behavior worth calling out                                                                                    |
| `## Rules`       | `<HeaderRequirements />`, `<HeaderAssertions />`, `<HeaderTimeouts />`, each followed by bullets              |
| `## Command Log` | a snippet, the rendered log as `<DocsImage>`, then the console output                                         |
| `## History`     | version table, newest first                                                                                   |
| `## See also`    | 2 to 5 sibling commands                                                                                       |

Never hand-write the `Yields`, `Requirements`, `Assertions`, or `Timeouts`
headings. The four `Header*` partials render them,
`src/theme/MDXComponents.js` registers them globally so they take no import, and
each carries the anchor other pages link to (`{#Yields}`, `{#Requirements}`,
`{#Assertions}`, `{#Timeouts}`). Hand-writing one drops its anchor and breaks
every inbound link to it.

## History tables

Newest version first, each version linking its changelog anchor:

```markdown
| Version                                  | Changes                       |
| ---------------------------------------- | ----------------------------- |
| [6.1.0](/app/references/changelog#6-1-0) | Added option `scrollBehavior` |
```

Add a row whenever a release changes documented behavior, and add the matching
changelog entry in the same PR (see `docs/app/releases/AGENTS.md`).

---

### Api Table Of Contents (`docs/api/table-of-contents.mdx`)

---
title: 'Cypress API: Table of Contents'
description: 'Cypress commands, assertions, actions, and other commands to help write tests.'
sidebar_label: 'Table of Contents'
sidebar_position: 10
---

<ProductHeading product="app" />

# Table of Contents

## Commands

Cypress commands don't do anything at the moment they are invoked, but rather
enqueue themselves to be run later. Commands can be chained together
because Cypress manages a Promise chain on your behalf, with each command
yielding a 'subject' to the next command, until the chain ends or an error is
encountered.

Learn more about how commands chain together in the
[Introduction to Chains of Commands](/app/core-concepts/introduction-to-cypress#Chains-of-Commands).

Cypress commands can be classified one of the following

- `query` - commands that read the state of your application
- `assertion` - command which assert on a given state
- `action` - interact with your application as a user would
- `other` - any other command that is useful for writing tests

The differences between queries and other commands are outline in the
[Retry-ability Guide](/app/core-concepts/retry-ability).

### Queries

Queries are Cypress commands that read the state of your application. They
return a subject for further commands to act or assert on, and retry as needed
to make sure the DOM element or other data they yield is always up to date.

| Command                                                         | Usage                                                                                                      |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| [`.as()`](/api/commands/as)                                     | Assign an alias for later use. Reference the alias later within a `cy.get()` query or `cy.wait()` command. |
| [`.children()`](/api/commands/children)                         | Get the children of each element within a set of DOM elements.                                             |
| [`.closest()`](/api/commands/closest)                           | Get the element itself or its closest ancestor that matches a selector.                                    |
| [`.contains()`](/api/commands/contains)                         | Select a DOM element by text content.                                                                      |
| [`.document()`](/api/commands/document)                         | Get the `window.document` of the active page.                                                              |
| [`.eq()`](/api/commands/eq)                                     | Select a DOM element by index from a collection.                                                           |
| [`.filter()`](/api/commands/filter)                             | Filter elements with a selector.                                                                           |
| [`.find()`](/api/commands/find)                                 | Find descendent elements with a selector.                                                                  |
| [`.first()`](/api/commands/first)                               | Select the first item in a collection.                                                                     |
| [`.focused()`](/api/commands/focused)                           | Get the DOM element that is currently focused.                                                             |
| [`.get()`](/api/commands/get)                                   | Find DOM elements by selector, or read an alias previously created with the `.as()` command.               |
| [`.getAllCookies()`](/api/commands/getallcookies)               | Get all browser cookies.                                                                                   |
| [`.getAllLocalStorage()`](/api/commands/getalllocalstorage)     | Get `localStorage` data for all origins with which the test has interacted.                                |
| [`.getAllSessionStorage()`](/api/commands/getallsessionstorage) | Get `sessionStorage` data for all origins with which the test has interacted.                              |
| [`.getCookie()`](/api/commands/getcookie)                       | Get a browser cookie by its name.                                                                          |
| [`.getCookies()`](/api/commands/getcookies)                     | Get browser cookies for the current domain or a specified domain.                                          |
| [`.hash()`](/api/commands/hash)                                 | Get the URL hash of the active page.                                                                       |
| [`.invoke()`](/api/commands/invoke)                             | Invoke a function on the previously yielded subject.                                                       |
| [`.its()`](/api/commands/its)                                   | Get a property's value on the previously yielded subject.                                                  |
| [`.last()`](/api/commands/last)                                 | Select the last item in a collection.                                                                      |
| [`.location()`](/api/commands/location)                         | Get the `window.location` object of the active page.                                                       |
| [`.next()`](/api/commands/next)                                 | Get the next sibling element.                                                                              |
| [`.nextAll()`](/api/commands/nextall)                           | Get all following sibling elements.                                                                        |
| [`.nextUntil()`](/api/commands/nextuntil)                       | Get all following sibling elements until reaching a selector.                                              |
| [`.not()`](/api/commands/not)                                   | Filter selected elements with a selector.                                                                  |
| [`.parent()`](/api/commands/parent)                             | Get the parent of a DOM element.                                                                           |
| [`.parents()`](/api/commands/parents)                           | Get all parent elements of a DOM element.                                                                  |
| [`.parentsUntil()`](/api/commands/parentsuntil)                 | Get all parent elements up to a selector.                                                                  |
| [`.prev()`](/api/commands/prev)                                 | Get the previous sibling element.                                                                          |
| [`.prevAll()`](/api/commands/prevall)                           | Get all previous sibling elements.                                                                         |
| [`.prevUntil()`](/api/commands/prevuntil)                       | Get all following previous sibling elements until reaching a selector.                                     |
| [`.root()`](/api/commands/root)                                 | Get the root DOM element.                                                                                  |
| [`.shadow()`](/api/commands/shadow)                             | Traverse into the shadow DOM of an element.                                                                |
| [`.siblings()`](/api/commands/siblings)                         | Get all sibling elements.                                                                                  |
| [`.title()`](/api/commands/title)                               | Get the `document.title` property of the active page.                                                      |
| [`.url()`](/api/commands/url)                                   | Get the URL of the active page.                                                                            |
| [`.window()`](/api/commands/window)                             | Get the `window` object of the active page.                                                                |

### Assertions

Assertions are Cypress commands that assert on the state of your application.
They pause your test until the given condition is met, or until they time out.
Learn more about Cypress assertions in the
[Introduction to Assertions](/app/core-concepts/introduction-to-cypress#Assertions)
and the [Assertions Reference](/app/references/assertions).

| Command                             | Usage                                                                                                      |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| [`.and()`](/api/commands/and)       | Alias for `.should(). Assert on the state of your application`.                                            |
| [`.should()`](/api/commands/should) | Assert on the state of your application. Assertions are automatically retried until they pass or time out. |

### Actions

Actions are Cypress commands that interact with your application as a user
would. They wait for elements to be actionable before interacting with the page.

Learn more about action commands in our
[Actionability Guide](/app/core-concepts/interacting-with-elements).

| Command                                             | Usage                                                                                    |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| [`.check()`](/api/commands/check)                   | Check checkbox or radio elements.                                                        |
| [`.clear()`](/api/commands/clear)                   | Clear the value of an input or textarea.                                                 |
| [`.click()`](/api/commands/click)                   | Click a DOM element.                                                                     |
| [`.dblclick()`](/api/commands/dblclick)             | Double-click a DOM element.                                                              |
| [`.rightclick()`](/api/commands/rightclick)         | Right click a DOM element.                                                               |
| [`.scrollIntoView()`](/api/commands/scrollintoview) | Scroll an element into view.                                                             |
| [`.scrollTo()`](/api/commands/scrollto)             | Scroll to a specific position.                                                           |
| [`.select()`](/api/commands/select)                 | Select an `<option>` within a `<select>`.                                                |
| [`.selectFile()`](/api/commands/selectfile)         | Selects a file in an HTML5 input element, or simulates dragging a file into the browser. |
| [`.trigger()`](/api/commands/trigger)               | Trigger an event on a DOM element.                                                       |
| [`.type()`](/api/commands/type)                     | Type into a DOM element.                                                                 |
| [`.uncheck()`](/api/commands/uncheck)               | Uncheck checkbox(es).                                                                    |

### Other Commands

Cypress has a variety of additional commands to help write tests.

| Command                                                             | Usage                                                                                                                                                                           |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`.blur()`](/api/commands/blur)                                     | Blur a focused element. Blur is not an action command, because users cannot directly unfocus an element, only focus a new one, but `.blur()` can be used as a testing shortcut. |
| [`.clearAllCookies()`](/api/commands/clearallcookies)               | Clear all browser cookies.                                                                                                                                                      |
| [`.clearAllLocalStorage()`](/api/commands/clearalllocalstorage)     | Clear `localStorage` data for all origins with which the test has interacted.                                                                                                   |
| [`.clearAllSessionStorage()`](/api/commands/clearallsessionstorage) | Clear `sessionStorage` data for all origins with which the test has interacted.                                                                                                 |
| [`.clearCookie()`](/api/commands/clearcookie)                       | Clear a specific browser cookie.                                                                                                                                                |
| [`.clearCookies()`](/api/commands/clearcookies)                     | Clear browser cookies for a domain.                                                                                                                                             |
| [`.clearLocalStorage()`](/api/commands/clearlocalstorage)           | Clear data in `localStorage` for current domain and subdomain.                                                                                                                  |
| [`.clock()`](/api/commands/clock)                                   | Override the browser's built-in time objects (`Date`, `setTimeout` and similar), allowing them to be controlled via `cy.tick()`.                                                |
| [`.debug()`](/api/commands/debug)                                   | Set a `debugger` statement and log what the previous command yields.                                                                                                            |
| [`.each()`](/api/commands/each)                                     | Invoke a callback on each item in an array.                                                                                                                                     |
| [`.env()`](/api/commands/env)                                       | Access secret environment variables in your tests.                                                                                                                              |
| [`.fixture()`](/api/commands/fixture)                               | Load a fixed set of data from disk.                                                                                                                                             |
| [`.focus()`](/api/commands/focus)                                   | Focus on a DOM element. Focus is not an action command, because users cannot directly focus an element, but `.focus()` can be used as a testing shortcut.                       |
| [`.go()`](/api/commands/go)                                         | Navigate back or forward using the browser's history.                                                                                                                           |
| [`.hover()`](/api/commands/hover)                                   | Cypress does not have a cy.hover() command. See [Issue #10](https://github.com/cypress-io/cypress/issues/10).                                                                   |
| [`.intercept()`](/api/commands/intercept)                           | Spy and stub network requests and responses.                                                                                                                                    |
| [`.log()`](/api/commands/log)                                       | Print a message to the Cypress Command Log.                                                                                                                                     |
| [`.mount()`](/api/commands/mount)                                   | Mount a component for Cypress Component Testing.                                                                                                                                |
| [`.origin()`](/api/commands/origin)                                 | Visit multiple domains of different origin in a single test.                                                                                                                    |
| [`.pause()`](/api/commands/pause)                                   | Pause test execution, allowing interaction with the application under test before resuming.                                                                                     |
| [`.press()`](/api/commands/press)                                   | Trigger native key events in your application to simulate real user keyboard interactions.                                                                                      |
| [`.prompt()`](/api/commands/prompt)                                 | Use natural language to generate Cypress tests with AI.                                                                                                                         |
| [`.readFile()`](/api/commands/readfile)                             | Read a file from disk.                                                                                                                                                          |
| [`.reload()`](/api/commands/reload)                                 | Reload the page.                                                                                                                                                                |
| [`.request()`](/api/commands/request)                               | Make an HTTP request.                                                                                                                                                           |
| [`.screenshot()`](/api/commands/screenshot)                         | Take a screenshot of the application under test.                                                                                                                                |
| [`.session()`](/api/commands/session)                               | Cache and restore cookies, localStorage, and sessionStorage (i.e. session data) to recreate a consistent browser context between tests.                                         |
| [`.setCookie()`](/api/commands/setcookie)                           | Set a browser cookie.                                                                                                                                                           |
| [`.spread()`](/api/commands/spread)                                 | Invoke a callback function with multiple arguments. Similar to `.then()`.                                                                                                       |
| [`.spy()`](/api/commands/spy)                                       | Wrap a method in a spy to record calls to the function.                                                                                                                         |
| [`.stub()`](/api/commands/stub)                                     | Replace a method, record its usage, and control its behavior.                                                                                                                   |
| [`.submit()`](/api/commands/submit)                                 | Submit a form.                                                                                                                                                                  |
| [`.task()`](/api/commands/task)                                     | Execute code in Node via the `task` plugin event.                                                                                                                               |
| [`.then()`](/api/commands/then)                                     | Invoke a callback function with the current subject to run code at specific points during a Cypress test.                                                                       |
| [`.tick()`](/api/commands/tick)                                     | Move time after overriding a native time functions with `cy.clock()`.                                                                                                           |
| [`.viewport()`](/api/commands/viewport)                             | Control the size and orientation of the screen for your application.                                                                                                            |
| [`.visit()`](/api/commands/visit)                                   | Visit a remote URL. Many tests begin with this command.                                                                                                                         |
| [`.wait()`](/api/commands/wait)                                     | Wait a number of milliseconds, or wait for an aliased resource to resolve.                                                                                                      |
| [`.within()`](/api/commands/within)                                 | Scopes all subsequent cy commands to within this element. Useful when working within a particular group of elements such as a `<form>`.                                         |
| [`.wrap()`](/api/commands/wrap)                                     | Yield the object passed into `.wrap()`. If the object is a promise, yield its resolved value.                                                                                   |
| [`.writeFile()`](/api/commands/writefile)                           | Write to a file with the specified contents.                                                                                                                                    |

## Cypress API

### Events

Cypress emits a series of events as it runs in your browser. These events are
useful not only to control your application's behavior, but also for debugging
purposes. Learn more about them in the
[Catalog of Events](/api/cypress-api/catalog-of-events).

### Custom Commands and Queries

Cypress exposes interfaces to write
[Custom Commands](/api/cypress-api/custom-commands) and
[Custom Queries](/api/cypress-api/custom-queries). See those pages for more
details.

The Cypress community has created a large number of

<a href="/app/plugins/plugins-list#custom-commands">Command Plugins</a> which
you can install or download.

### APIs

Cypress exposes a number of properties and methods on the global `Cypress`
object.

The _key_ difference between Cypress APIs and Cypress commands is that Cypress
APIs execute the moment they are invoked and are **not** enqueued to run at a
later time.

| Property                                                           | Usage                                                                                                                          |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| [`Cypress.arch`](/api/cypress-api/arch)                            | CPU architecture name of the underlying OS, as returned from Node's `os.arch()`.                                               |
| [`Cypress.browser`](/api/cypress-api/browser)                      | Information about the current browser, such as browser family and version.                                                     |
| [`Cypress.Commands`](/api/cypress-api/custom-commands)             | Create new custom commands and extend or override existing ones.                                                               |
| [`Cypress.config()`](/api/cypress-api/config)                      | Get and set Cypress configuration from inside your tests.                                                                      |
| [`Cypress.Cookies.debug()`](/api/cypress-api/cookies)              | Generate console logs whenever a cookie is modified.                                                                           |
| [`Cypress.currentRetry`](/api/cypress-api/currentretry)            | A number representing the current test retry count.                                                                            |
| [`Cypress.currentTest`](/api/cypress-api/currenttest)              | An object with information about the currently executing test.                                                                 |
| [`Cypress.log`](/api/cypress-api/cypress-log)                      | This is the internal API for controlling what gets printed to the Command Log. Useful when writing your own custom commands.   |
| [`Cypress.dom`](/api/cypress-api/dom)                              | A collection of DOM related helper methods.                                                                                    |
| [`Cypress.ElementSelector`](/api/cypress-api/element-selector-api) | Configure selector priority used by [Cypress Studio](/app/guides/cypress-studio) and [cy.prompt()](/api/commands/prompt).      |
| [`Cypress.expose`](/api/cypress-api/expose)                        | Expose configuration values to the browser context.                                                                            |
| [`Cypress.isBrowser()`](/api/cypress-api/isbrowser)                | Checks if the current browser matches the given name or filter.                                                                |
| [`Cypress.isCy()`](/api/cypress-api/iscy)                          | checks if a variable is a valid instance of cy or a cy chainable.                                                              |
| [`Cypress.Keyboard.defaults()`](/api/cypress-api/keyboard-api)     | Set default values for how the `.type()` command is executed.                                                                  |
| [`Cypress.platform`](/api/cypress-api/platform)                    | The underlaying OS name, as returned by Node's `os.platform()`.                                                                |
| [`Cypress.require`](/api/cypress-api/require)                      | Use dependencies within the [cy.origin()](/api/commands/origin) callback function.                                             |
| [`Cypress.Screenshot.defaults()`](/api/cypress-api/screenshot-api) | Set defaults for screenshots captured by the `.screenshot()` command and the automatic screenshots taken during test failures. |
| [`Cypress.session`](/api/cypress-api/session)                      | A collection of helper methods related to the `.session()` command.                                                            |
| [`Cypress.spec`](/api/cypress-api/spec)                            | An object with information about the currently executing spec file.                                                            |
| [`Cypress.testingType`](/api/cypress-api/testing-type)             | The current testing type, eg. `"e2e"` or `"component"`.                                                                        |
| [`Cypress.version`](/api/cypress-api/version)                      | The current Cypress version.                                                                                                   |

## Utilities

Cypress makes several common libraries available directly on the global
`Cypress` object.

| Utility                                         | Usage                                                                                                                                    |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| [`Cypress.$`](/api/utilities/$)                 | Cypress automatically includes [jQuery](http://jquery.com/) and exposes it as `Cypress.$`.                                               |
| [`Cypress.Blob`](/api/utilities/blob)           | Cypress automatically includes a [Blob](https://github.com/nolanlawson/blob-util) library and exposes it as `Cypress.Blob`.              |
| [`Cypress.Buffer`](/api/utilities/buffer)       | Cypress automatically includes a [Buffer polyfill](https://github.com/feross/buffer) for the browser and exposes it as `Cypress.Buffer`. |
| [`Cypress._`](/api/utilities/_)                 | Cypress automatically includes [lodash](https://lodash.com/) and exposes it as `Cypress._`.                                              |
| [`Cypress.minimatch`](/api/utilities/minimatch) | Cypress automatically includes [minimatch](https://github.com/isaacs/minimatch) and exposes it as `Cypress.minimatch`.                   |
| [`Cypress.Promise`](/api/utilities/promise)     | Cypress automatically includes `Bluebird` and exposes it as `Cypress.Promise`.                                                           |
| [`Cypress.sinon`](/api/utilities/sinon)         | Cypress automatically includes [Sinon.JS](http://sinonjs.org/) and exposes it as `Cypress.sinon`.                                        |

## Node Events

The Node Events hook into and extend Cypress behavior. For more
details, see the [How to use a Plugin](/app/plugins/plugins-guide) and
[Node Events Overview](/api/node-events/overview).

| API                                                             | Usage                                                                                                                                                                                                                                                                    |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [After Run Event](/api/node-events/after-run-api)               | The `after:run` event fires after a run is finished. When running cypress via cypress open, the event will fire when closing a project.                                                                                                                                  |
| [After Screenshot Event](/api/node-events/after-screenshot-api) | After a screenshot is taken, you can get details about it via the `after:screenshot` plugin event.                                                                                                                                                                       |
| [After Spec Event](/api/node-events/after-spec-api)             | The `after:spec` event fires after a spec file is run. When running cypress via cypress open, the event will fire when the browser closes.                                                                                                                               |
| [Before Run Event](/api/node-events/before-run-api)             | The `before:run` event fires before a run starts. When running cypress via cypress open, the event will fire when opening a project.                                                                                                                                     |
| [Before Spec Event](/api/node-events/before-spec-api)           | The `before:spec` event fires before a spec file is run. When running cypress via cypress open, the event will fire when the browser launches.                                                                                                                           |
| [Browser Launch API](/api/node-events/browser-launch-api)       | Before Cypress launches a browser, it gives you the opportunity to modify the browser preferences, install extensions, add and remove command-line arguments, and modify other options from the [`setupNodeEvents`](/app/plugins/plugins-guide#Using-a-plugin) function. |
| [Configuration API](/api/node-events/configuration-api)         | Cypress enables you to dynamically modify configuration values and environment variables from your Cypress configuration.                                                                                                                                                |
| [Preprocessors API](/api/node-events/preprocessors-api)         | A preprocessor is the plugin responsible for preparing a support file or a test file for the browser. A preprocessor also typically watches the source files for changes, processes them again, and then notifies Cypress to re-run the tests.                           |

---

### Cloud Faq (`docs/cloud/faq.mdx`)

---
title: 'Frequently asked questions (FAQ) in Cypress Cloud'
description: 'Get answers to common questions about Cypress Cloud.'
sidebar_label: FAQ
sidebar_position: 220
---

<ProductHeading product="cloud" />

# Cypress Cloud FAQ

## General

### <Icon name="angle-right" /> What is Cypress Cloud?

<DocsImage
  src="/img/cloud/runs/run-details-page.png"
  alt="Cloud Screenshot"
  width="80%"
/>

[Cypress Cloud](https://on.cypress.io/cloud) gives you access to tests you've
recorded - typically when running Cypress tests from your
[CI provider](/app/continuous-integration/overview) - and provides you
insight into what happened during your tests run.

You can read more in the
[introduction to Cypress Cloud](/cloud/get-started/introduction).

### <Icon name="angle-right" /> What does Cypress record?

Cypress captures the following:

When you run Cypress via `cypress run` passing the `--record` flag the following
data is sent to the Cloud for every run:

- Standard output in the terminal
- Test results
- Test definitions
- Cypress configuration (minus Cypress environment variables)
- Screenshots
- Videos
- OS environment variables related to CI and git information

You have the option to
[delete videos or screenshots](/app/guides/screenshots-and-videos#Control-which-videos-to-keep-and-upload-to-Cypress-Cloud)
before being sent to the Cloud so those are not captured.

When [Test Replay](#Test-Replay) capturing is enabled, the additional data outlined
below will be sent to the Cloud. You can
[disable capturing](/cloud/features/test-replay#Opt-out-of-Test-Replay) this data.

- The rendered DOM and CSS styles for the application under test
- Cypress commands and events represented in the Command Log
- Network traffic within your application under test
- Browser console logs

Cypress Cloud does not capture anything related to the code of your application
under test or the code within any associated repositories that are associated with your project.

### <Icon name="angle-right" /> How is this different than CI?

Cypress Cloud is **complementary** to your
[CI provider](/app/continuous-integration/overview), and plays a
completely different role.

It doesn't replace or change anything related to CI. You will still run Cypress
tests in your CI provider.

The difference between [Cypress Cloud](/cloud/get-started/introduction) and your CI
provider is that your CI provider has no idea what is going on inside of the
Cypress process. It's programmed to know whether or not a process failed - based
on whether it had an exit code greater than `0`.

[Cypress Cloud](/cloud/get-started/introduction) provides you with the low level
details of _what_ happened during your run. Using both your CI provider +
Cypress together gives the insight required to debug your test runs.

When a run happens and a test fails - instead of going and inspecting your CI
provider's `stdout` output, you can log into
[Cypress Cloud](https://on.cypress.io/cloud), see the `stdout` as well as
screenshots and video of the tests running. It should be instantly clear what
the problem was.

### <Icon name="angle-right" /> What counts as a test result?

Which [pricing tier](https://www.cypress.io/pricing?utm_source=docs.cypress.io&utm_medium=cloud-faq) is best for you depends on
the number of tests you record each month in your organization.

Tests are recorded when [cypress run](/app/references/command-line#cypress-run)
is called with the `--record` flag while supplying the record `--key`. This
means your [test run data](/cloud/features/recorded-runs#Latest-Runs) is being
"recorded" to Cypress Cloud.

We consider each time the `it()` function is called to be a single test. So you
will generally have several tests recorded within each spec file and likely
several spec files within a single run. Only the
[passed and failed tests](/app/core-concepts/writing-and-organizing-tests#Understanding-test-results)
are counted. The pending and skipped tests are NOT counted.

You can always see how many tests you've recorded from your organization's
[Billing & Usage](/cloud/account-management/billing-and-usage) page
within Cypress Cloud.

### <Icon name="angle-right" /> What counts as a user?

A [user](/cloud/account-management/users) is anyone with a login to
Cypress Cloud who has been invited to see and review the test results of your
organization.

Each plan includes a set number of users. To compare the user seats each plan
allows, see the
[pricing page](https://www.cypress.io/pricing?utm_source=docs.cypress.io&utm_medium=cloud-faq).
To see how many of your seats are in use, check the
[Billing & Usage](/cloud/account-management/billing-and-usage) page in Cypress
Cloud.

### <Icon name="angle-right" /> How much does it cost?

See our [Pricing Page](https://www.cypress.io/pricing?utm_source=docs.cypress.io&utm_medium=cloud-faq) for more details.

### <Icon name="angle-right" /> What is the difference between public and private projects?

**A public project** means that anyone can see the recorded runs for it. It's
similar to how public projects on GitHub, Travis, or CircleCI are handled.
Anyone who knows your `projectId` will be able to see the recorded runs,
screenshots, and videos for public projects.

**A private project** means that only
[users](/cloud/account-management/users) you explicitly invite to your
[organization](/cloud/account-management/organizations) can see its
recorded runs. Even if someone knows your `projectId`, they will not have access
to your runs unless you have invited them.

### <Icon name="angle-right" /> What happens once I reach the test results limit?

Tests running with the `--record` flag will run as normal when the limit is
reached, but parallelization will be disabled and new test results will be
hidden from the dashboard until your plan is upgraded or a new usage cycle
begins. The usage cycle resets at the start of each billing period, which is
monthly on most plans, though some annual plans use an annual test results
allowance.

To avoid any interruption in service, we recommend that you review your
usage and select a plan that satisfies your usage requirements. You can do this
by:

1. Logging into [Cypress Cloud](https://cloud.cypress.io)
2. Select your organization
3. Navigate to the **Billing and Usage** tab
4. Review your organization's usage
5. Scroll down and select **Upgrade** under your plan of choice

### <Icon name="angle-right" /> What happens if I downgrade my account?

Downgrading your account will **not** result in loss of access to Cypress Cloud.

However, it will make your Cypress Cloud account subject to the limitations of
your new plan. For example, downgrading to the _Starter_ plan will limit data
retention to 30 days, test results to 500 per billing period, and your
organization to 10 [users](#What-counts-as-a-user).

### <Icon name="angle-right" /> When does my billing period reset?

Your usage cycle resets at the start of each billing period, at which point
your recorded [test result](#What-counts-as-a-test-result) and AI usage counters
return to zero for the new period. Org-level
[`cy.prompt`](/api/commands/prompt) execution counts reset on the same schedule.
See [cy.prompt](/cloud/faq#cyprompt) for details. Most plans bill monthly,
though some annual plans use an annual test results allowance. You can confirm
the dates of your current period on your organization's
[Billing & Usage](/cloud/account-management/billing-and-usage) page.

### <Icon name="angle-right" /> How do I reduce my Cypress Cloud usage or lower my bill?

Because Cypress Cloud meters
[test results](#What-counts-as-a-test-result) (each passed or failed test
recorded with `--record`), the most effective way to reduce usage is to record
fewer, more meaningful tests. A few common approaches:

- Record only the runs you need insight into, rather than every local run.
- Remove redundant or obsolete tests, and avoid recording the same suite
  multiple times against the same commit.
- [Choose the right test level](/app/guides/test-performance#Choose-the-right-test-level)
  so behavior is covered where it is cheapest to test, instead of duplicating it
  across many end-to-end tests.
- [Find and eliminate over-tested UI with UI Coverage](/app/guides/test-performance#Find-and-eliminate-over-tested-UI-with-UI-Coverage)
  to cut redundant tests that cover the same flows.
- [Run the right tests at the right time](/app/guides/test-performance#Run-the-right-tests-at-the-right-time),
  for example a smaller smoke suite on every PR and the full suite less often.
- Use the **By project** tab on the
  [Billing & Usage](/cloud/account-management/billing-and-usage) page to find
  which projects consume the most of your plan, then focus there.

For more ways to trim and streamline your suite, see the
[Optimizing test performance](/app/guides/test-performance) guide.

If your usage consistently exceeds your plan, compare options on the
[pricing page](https://www.cypress.io/pricing?utm_source=docs.cypress.io&utm_medium=cloud-faq); moving to a larger plan is
often more cost-effective than purchasing additional test results. You can also
**schedule a demo** from the pricing page to talk through the plan that best
fits your usage.

### <Icon name="angle-right" /> Can I choose not to use Cypress Cloud?

Of course. Cypress Cloud is a separate service from the Cypress app and will
always remain optional. We hope you'll find a tremendous amount of value in it,
but it is not coupled with being able to run your tests.

You can always run your tests in CI using
[cypress run](/app/references/command-line#cypress-run) without the `--record`
flag which does not communicate with our external servers and will not record
any test results.

## Using Cypress Cloud

### <Icon name="angle-right" /> What is the projectId for?

The `projectId` is a 6-character string that helps identify your project once
you've [set up your tests to record](/cloud/features/recorded-runs#Latest-Runs).
It's generated by Cypress and typically is found in your
[Cypress configuration](/app/references/configuration).

:::cypress-config-example

```ts
{
  projectId: 'a7bq2k'
}
```

:::

For further detail see the
[Identification](/cloud/account-management/projects#Project-ID)
section of the [Cypress Cloud](/cloud/get-started/introduction) docs.

### <Icon name="angle-right" /> What is a Record Key?

A _Record Key_ is a GUID that's generated automatically by Cypress once you've
[set up your tests to record](/cloud/features/recorded-runs#Latest-Runs). It helps
identify your project and authenticate that your project is even _allowed_ to
record tests.

You can find your project's record key inside of the _Settings_ tab.

<DocsImage
  src="/img/cloud/projects/record-key-desktop-gui.jpg"
  alt="Record Key in Configuration Tab"
  width="80%"
/>

For further details see the
[Identification](/cloud/account-management/projects#Project-ID)
section of the [Cypress Cloud](/cloud/get-started/introduction) docs.

### <Icon name="angle-right" /> How do I record my tests?

1. First [set up the project to record](/cloud/get-started/setup#Setup).
2. Then [record your runs](/cloud/features/recorded-runs#Latest-Runs).

After recording your tests, you will see them in
[Cypress Cloud](https://on.cypress.io/cloud) and in the Cypress App [Runs](/app/core-concepts/open-mode#Runs) tab.

### <Icon name="angle-right" /> Can I delete a run from Cypress Cloud?

You can [archive a run](/cloud/features/recorded-runs#Archive-run) so that it does
not display in the runs list or in analytics.

**Note:** Archiving the recorded runs has no effect on the amount of tests
recorded and counted as your usage billed for the month.

### <Icon name="angle-right" /> Can I host Cypress Cloud data myself?

No. A self-hosted version of Cypress Cloud is not available at this time.

### <Icon name="angle-right" /> Why is test parallelization based on spec files and not on the individual functions?

Cypress
[test parallelization](/cloud/features/smart-orchestration/parallelization) is
indeed based on specs. For each spec, Cypress scaffolds the new running context,
in a sense isolating each spec file from any previous spec files, and ensuring a
clean slate for the next spec. Doing this for each _individual_ test would be
very very expensive and would slow down the test runs significantly.

Spec file durations are also more meaningful and consistent than timings of
individual tests, we can order specs by the moving average of the previously
recorded durations. This would be much less useful when load balancing quickly
finishes individual tests.

Thus, to better load balance the specs, you would want more spec files with
approximately the same running duration. Otherwise, a single very long running
test might limit how fast all your tests finish, and how fast the run completes.
Due to starting a new test execution context before each spec file and encoding
and uploading video after, making spec files run shorter than approximately 10
seconds would also be fruitless - because Cypress overhead would eat any time
savings.

### <Icon name="angle-right" /> My CI setup is based on Docker, but is very custom. How can I load balance my test runs?

Even if your CI setup is very different from the
[CI examples we have](/app/continuous-integration/overview#CI-Examples) and
[run with our sample projects](https://github.com/cypress-io/cypress-example-kitchensink#ci-status),
you can still take advantage of the test load balancing using Cypress Cloud.
Find a variable across your containers that is the same for all of them, but is
different from run to run. For example, it could be an environment variable
called `CI_RUN_ID` that you set when creating the containers to run Cypress. You
can pass this variable via CLI argument
[`--ci-build-id`](/app/references/command-line#cypress-run-ci-build-id-lt-id-gt)
when starting Cypress in each container:

```shell
cypress run --record --parallel --ci-build-id $CI_RUN_ID
```

For reference, here are
[the variables](https://github.com/cypress-io/cypress/blob/develop/packages/server/lib/util/ci_provider.js)
we extract from the popular CI providers, and for most of them, there is some
variable that is set to the same value across multiple containers running in
parallel. If there is NO common variable, try using the commit SHA string.
Assuming you do not run the same tests more than once against the same commit,
it might be good enough for the job.

### <Icon name="angle-right" /> I'm working with a restrictive VPN. Which subdomains do I have to allow on my VPN for Cypress Cloud to work properly?

<UrlAllowList />

## Re-run optimization

### <Icon name="angle-right" /> Can I rerun only failed tests?

Yes, depending on where you are running tests:

- **In CI**, [Re-run optimization](/cloud/features/smart-orchestration/rerun-optimization)
  re-runs only the specs or tests that failed when you trigger a rerun of a
  recorded build. Choose **Run only failed specs** to re-execute each spec that
  contained a failure, or **Run only failed tests** (Cypress 15.21.0 or later) to
  re-execute only the tests that did not pass.
- **In the Cypress app**, the [Debug page](/app/core-concepts/open-mode#Debug) lets
  you rerun only the failed tests from a recorded CI run on your current branch.
- **During a single run**, [test retries](/app/guides/test-retries) automatically
  re-attempt failed individual tests before the run finishes.

### <Icon name="angle-right" /> How is Re-run optimization different from test retries?

They solve different problems. [Test retries](/app/guides/test-retries)
automatically retries a failed _individual test_ within a single run, in real time,
to absorb flake before the run finishes. **Re-run optimization** changes what
happens when you re-run an _entire CI build_ after it has completed, re-executing
only the specs or tests that failed. You can use both together: test
retries reduce flake within a run, and Re-run optimization speeds up the reruns you still need.

### <Icon name="angle-right" /> Does Re-run optimization carry forward my passing test results?

No, not currently. A rerun-optimized run shows only the specs and tests that were re-executed. Work that
passed in the anchor run is skipped and does not appear in the rerun's results.

### <Icon name="angle-right" /> Why does my CI report show fewer tests after a rerun?

Reporter output (JUnit/XML and custom reporters) reflects only the re-executed
specs and tests, so a rerun-optimized run reports fewer specs and tests than a full run.
Adjust any CI guardrails that assert on fixed test counts.

### <Icon name="angle-right" /> Does Re-run optimization require recording to Cypress Cloud?

Yes. Runs must be recorded to Cypress Cloud with the `--record` flag, and the
feature is available on Business or Enterprise plans, or during a free trial.

### <Icon name="angle-right" /> What happens if the rerun has no failed specs or tests?

If the anchor run contained no failing specs (or, for **Run only failed tests**,
no tests that still need to run), there is nothing to re-execute and
the optimized rerun completes without running any specs.

### <Icon name="angle-right" /> How do I know Re-run optimization was applied?

The Cypress App prints a notice in the CLI output naming the run it is retrying
from. **Run only failed specs** mentions failed specs; **Run only failed tests**
mentions tests that did not pass. The run is labeled with a **Re-run** tag in Cypress Cloud.

## Spec Prioritization

### <Icon name="angle-right" /> What is Spec Prioritization?

[Spec Prioritization](/cloud/features/smart-orchestration/spec-prioritization) is
a [Smart Orchestration](/cloud/features/smart-orchestration/overview) feature
that automatically runs the specs that failed in your previous Cypress run
first. Instead of waiting for the same failures to resurface late in a run,
Cypress Cloud surfaces them right away so you learn whether your latest change
worked in minutes rather than at the end of the run.

### <Icon name="angle-right" /> Does Spec Prioritization make my tests run faster?

On its own, Spec Prioritization changes the _order_ specs run in, not the total
duration, so it surfaces failures earlier without shortening the run. To turn
that earlier feedback into shorter runs and lower CI costs, pair it with
[Auto Cancellation](/cloud/features/smart-orchestration/run-cancellation): when
the prioritized failures reappear at the start of a run, the run is cancelled
right away, avoiding wasted compute on specs you already know will need another
pass.

### <Icon name="angle-right" /> What plan do I need to use Spec Prioritization?

Spec Prioritization is available on the
[Business and Enterprise tiers](https://cypress.io/pricing). Not sure if
upgrading is worth it? The
[recommendations](/cloud/features/recorded-runs#Recommendations) on the run
overview page predict how much time Smart Orchestration features would save your
suite.

### <Icon name="angle-right" /> How do I enable Spec Prioritization?

An admin can toggle it on at the project level: open the project in Cypress
Cloud, go to **Project Settings**, scroll to the **Smart Orchestration** section,
and toggle **Spec Prioritization**. See the
[Spec Prioritization guide](/cloud/features/smart-orchestration/spec-prioritization#Enable-Spec-Prioritization)
for the full steps.

### <Icon name="angle-right" /> How do I know Spec Prioritization took effect?

When Spec Prioritization fires, the run's detail tab displays a **"Prioritized
failed specs from run #X"** label, where **#X** links back to the source run
whose failures were moved to the front. The label only appears when Cypress Cloud
actually reordered specs, so its presence confirms prioritization took effect and
lets you trace which previous failures drove the order. If you don't see it,
confirm the feature is toggled on and that the previous run recorded failures to
prioritize.

## Auto Cancellation

### <Icon name="angle-right" /> What is Auto Cancellation in Cypress?

[Auto Cancellation](/cloud/features/smart-orchestration/run-cancellation) is a
Cypress Cloud [Smart Orchestration](/cloud/features/smart-orchestration/overview)
feature that automatically cancels a recorded run once the number of failed
tests reaches a threshold you configure. It stops Cypress from handing out new
specs, marks the run as cancelled, and reports how much CI time was saved, so you
don't pay for tests that run after a run has already failed. It is available on
the Business and Enterprise plans.

### <Icon name="angle-right" /> How many test failures trigger an auto cancellation?

By default, a single failure cancels the run. You can set a higher threshold in
your project's Smart Orchestration settings, or override it per run with the
[`--auto-cancel-after-failures`](/app/references/command-line#auto-cancel-after-runs)
CLI flag. Only genuinely failed tests count toward the threshold; flaky tests (which
fail an attempt but then pass on retry) are not considered and never trigger an
auto cancellation.

### <Icon name="angle-right" /> Does Auto Cancellation stop tests that are already running?

No. Specs that are already in progress when the threshold is reached finish
running so you still get their complete results. Cypress only stops handing out
_new_ specs. In a parallelized run, this means machines can keep running the
specs they had already started at the moment of cancellation, but none of them
will pick up a new spec once the run is cancelled.

### <Icon name="angle-right" /> How do I disable Auto Cancellation for a single run?

Pass `--auto-cancel-after-failures false` to `cypress run`. This overrides the
project setting for that run only, which is useful for important branches that
need the full suite to run every time.

### <Icon name="angle-right" /> Is Auto Cancellation free?

No. Auto Cancellation is a paid Smart Orchestration feature available on the
[Business and Enterprise Cypress Cloud plans](https://cypress.io/pricing).

### <Icon name="angle-right" /> What is the difference between Auto Cancellation and manual cancellation?

Auto Cancellation is triggered automatically when a run reaches the configured
failure threshold, and the UI labels it _"canceled due to auto-cancellation."_
A manual cancellation happens when a user cancels the run from Cypress Cloud,
which the UI labels _"manually canceled"_ and attributes to that user.

### <Icon name="angle-right" /> How do I find the tests that triggered an auto cancellation?

The failed tests that triggered the cancellation are the ones counted toward
your threshold. The fastest way to reach them is to click the **failed** test
indicator in the [run header](/cloud/features/recorded-runs#Run-header), which
opens the [Test Results tab](/cloud/features/recorded-runs#Test-Results-tab)
pre-filtered to the failures, or to use the
[Tests for Review](/cloud/features/recorded-runs#Tests-for-Review) panel, which
orders results by failures first. Open a failed test's
[detail sidebar](/cloud/features/recorded-runs#Test-detail-sidebar) and
[Test Replay](/cloud/features/test-replay) to debug it. A cancelled run
only includes results for specs that had already started, so it may not contain
every failure the full suite would have produced.

## Flaky Test Management

### <Icon name="angle-right" /> What is a flaky test?

A flaky test is one that both passes and fails across retry attempts without any
change to the code. It fails once, runs again on the same code, and passes. See
[Flaky Test Management](/cloud/features/flaky-test-management) for how Cypress
Cloud detects and tracks them.

### <Icon name="angle-right" /> How does Cypress detect flaky tests?

With [test retries](/app/guides/test-retries) enabled, Cypress Cloud records
every retry attempt from your recorded CI runs and flags any test that fails an
attempt before ultimately passing as flaky, then scores it by
[severity](/cloud/features/flaky-test-management#Flake-severity) based on its
flake rate.

### <Icon name="angle-right" /> What causes flaky tests?

Flake usually comes from timing issues, race conditions, or differences between
your local and CI environments. [Test Replay](/cloud/features/test-replay) lets
you compare a passing and failing attempt on the same code to find the cause.

### <Icon name="angle-right" /> How do I fix a flaky test?

Open a failing attempt from the flaky test details panel in
[Test Replay](/cloud/features/test-replay) to inspect the DOM, network requests,
and console at the moment of failure, then compare it against a passing attempt
on the same code to pinpoint the root cause.

### <Icon name="angle-right" /> How is flake rate calculated?

Flake rate is the share of recent runs affected by flake: the number of runs
where the spec had a flaky test divided by the total number of runs in the
current window. See
[Flake severity](/cloud/features/flaky-test-management#Flake-severity) for how
flake rate maps to severity levels.

### <Icon name="angle-right" /> Do I need test retries enabled to detect flaky tests?

Yes. [Test retries](/app/guides/test-retries#Configure-Test-Retries) are the
fundamental mechanism that lets Cypress Cloud detect flaky tests, so enabling
them is required for any Flaky Test Management feature.

### <Icon name="angle-right" /> Which Cypress Cloud plan is required for Flaky Test Management?

Flake detection, analytics, and alerting require a
[Team Cypress Cloud plan](https://cypress.io/pricing). Enterprise Reporting and
the Data Extract API require an Enterprise plan, and
[Cloud MCP](/cloud/integrations/cloud-mcp) is included on every Cypress Cloud
plan.

## Cypress Cloud Account

### <Icon name="angle-right" /> What is a Cypress Cloud organization?

A Cypress Cloud organization is the top-level container that groups your
[projects](/cloud/account-management/projects),
[users](/cloud/account-management/users),
[teams](/cloud/account-management/teams), billing and usage, and
[integrations](/cloud/account-management/organizations#Integrations). It lets you manage access
control and application quality across every project from one place instead of configuring each
project individually.

### <Icon name="angle-right" /> How do I create an organization in Cypress Cloud?

Open the organization switcher in [Cypress Cloud](https://on.cypress.io/cloud) and click
**Create new organization**. A "Default Project" is created automatically, which you can rename and
configure in [Project Settings](/cloud/account-management/projects).

### <Icon name="angle-right" /> Can I have more than one organization?

Yes. You can create multiple organizations to separate projects by team, business unit, or client,
and switch between them using the organization switcher. Usage and
[enterprise analytics](/cloud/features/analytics/enterprise-reporting) roll up within each
organization.

### <Icon name="angle-right" /> Who can manage an organization?

Organization owners and admins can invite users, create teams, configure
[Cloud AI](/cloud/account-management/organizations#Manage-Cloud-AI), and set up integrations. Only
owners can rename or delete an organization and configure
[single sign-on (SSO)](/cloud/account-management/enterprise-sso). See
[user roles](/cloud/account-management/users#User-roles) for the full permissions breakdown.

### <Icon name="angle-right" /> How do I delete an organization?

You can delete an organization you own once it has no projects. First
[delete](/cloud/account-management/projects#Delete-Project) or
[transfer ownership](/cloud/account-management/projects#Transfer-ownership) of every project to
another organization, then delete the organization from its settings.

### <Icon name="angle-right" /> What is my Organization ID?

Your Organization ID is a unique identifier that is linked to your organization.
Instructions on how to find your ID are in the
[Cypress Cloud Guide.](/cloud/account-management/organizations#Organization-ID)

### <Icon name="angle-right" /> What if I can't access my Cypress Cloud account?

1. If you haven't signed up, see the
   [Sign Up with an Invitation](/cloud/account-management/users#Sign-Up-with-an-Invitation)
   instructions.

2. Try resetting your password. If you never received the email, try the
   following:
   - Try signing in with Google or GitHub
   - Check the trash and spam folder
   - Verify it's the correct email address

If the troubleshooting tips above did not resolve the issue or involves SSO,
reach out to [support](mailto:support@cypress.io).

### <Icon name="angle-right" /> Can I delete my Cypress account?

You can delete your Cypress account from
[your Cypress Cloud profile](https://cloud.cypress.io/profile). Deleting your
account cannot be undone! By deleting your Cypress account, all associated data
in your account will be permanently deleted.

### <Icon name="angle-right" /> How do I invite a user to Cypress Cloud?

An organization [Owner or Admin](/cloud/account-management/users#User-roles) can
invite users from the **Users & Teams** page by clicking **Invite User**, adding
one or more email addresses, and selecting a [role](/cloud/account-management/users#User-roles).
Invited users receive an email with a link to accept the invitation. You can also
use **Copy invite link** to share your own message. Anyone who joins through that
link is given the default **Member** role. See
[Invite users](/cloud/account-management/users#Invite-users) for details.

### <Icon name="angle-right" /> What are the Cypress Cloud user roles?

Cypress Cloud has five roles that control what a user can see and change:
**Viewer** (read-only access to projects and runs), **Member** (the everyday
developer role, including record keys and App Quality configuration), **Team
Admin** (manages members and settings for their own projects), **Org Admin**
(manages all users and both organization and project settings), and **Org
Owner** (full control, including billing, SSO, and deletion). See the full
[permissions tables](/cloud/account-management/users#User-roles) for an
exact breakdown.

### <Icon name="angle-right" /> What is the difference between an Org Admin and an Org Owner?

An **Org Admin** can manage all users and edit organization and project
configurations, but cannot perform owner-only actions. An **Org Owner** can do
everything an Org Admin can, plus invite or edit other owners, set up SSO, edit
the organization name, and delete the organization. Only owners can grant other
users 'owner' access. See
[User roles](/cloud/account-management/users#User-roles).

### <Icon name="angle-right" /> Can someone request access to my organization instead of being invited?

Yes. If a teammate already has access to Cypress and your project's source code,
they can request to join your organization directly from the Cypress App, and an
Owner or Admin can accept or deny the request. This lets you onboard teammates
without inviting everyone up front. User requests are not available if
your organization is configured for SSO. See
[User requests](/cloud/account-management/users#User-requests).

### <Icon name="angle-right" /> How do I change a user's email address in Cypress Cloud?

To change a user's email, an **Owner** or **Admin** invites the new email address
and removes the previous one. To update your billing email, use the
[Billing & Usage](/cloud/account-management/billing-and-usage) page or contact
[billing@cypress.io](mailto:billing@cypress.io). See
[User updates](/cloud/account-management/users#User-updates).

### <Icon name="angle-right" /> Does Cypress Cloud support Okta for Government?

Yes. Our Okta integration is a standard SAML 2.0 integration, so Okta for
Government uses the same setup steps as commercial Okta. Two values differ: the
Identity Provider Single sign-on URL and the X.509 signing certificate, which
you need to download from your Okta for Government app because certificates do
not transfer between tenants. If you are migrating from commercial Okta, note
that we store one SSO configuration per organization, so saving your Okta for
Government details replaces the existing configuration. See
[Okta for Government](/cloud/account-management/enterprise-sso#Okta-for-Government).

## Teams

### <Icon name="angle-right" /> What is a team in Cypress Cloud?

A [team](/cloud/account-management/teams) is a reusable group of users that is granted
access to a specific set of projects. Teams let you control project access once at the
team level, instead of project by project, user by user, so each person sees only the
projects relevant to their work.

### <Icon name="angle-right" /> Who can create and manage teams?

Organization [owner or admin](/cloud/account-management/users#User-roles) roles can create
teams. Once a team exists, owners, admins, and the dedicated
[team admin](/cloud/account-management/teams#Manage-teams) role can configure it by assigning
projects and members. The team admin role lets day-to-day team members manage their own
projects without routing every request through organization-level admins.

### <Icon name="angle-right" /> Do teams affect access to public projects?

No. [Public projects](https://on.cypress.io/what-is-project-access) are visible to all
Cypress Cloud users, including those outside of your organization, regardless of team
membership. Teams only control access to private projects.

### <Icon name="angle-right" /> What is the _Everyone_ team?

Every user in your organization is automatically a member of a default team named _Everyone_,
which has access to all projects by default. If you don't need to separate project access,
you can leave the _Everyone_ team as-is. When you adopt a team structure, you can remove the
_All projects_ assignment from the _Everyone_ team to enforce access through your own teams.
See [Manage teams](/cloud/account-management/teams) for setup best practices.

## Debugging

### <Icon name="angle-right" /> How do I debug a Cypress test that fails in CI but passes locally?

Record the run to Cypress Cloud, open the failing test, and use
[Test Replay](/cloud/features/test-replay) to replay the exact CI run. You can
step through the command log and inspect the DOM, network requests, and console
logs as they happened in CI, so you can find the difference between your local
environment and CI without reproducing the failure on your machine. See the
[Debug Failing Tests guide](/cloud/guides/debug-failing-tests) for the full
workflow.

### <Icon name="angle-right" /> Can I debug a CI failure without reproducing it locally?

Yes. [Test Replay](/cloud/features/test-replay) captures the complete state of
each test as it ran in CI and lets you replay it with full debugging capability.
This is the primary reason teams use Cypress Cloud for debugging: it removes the
need to recreate a CI environment locally.

### <Icon name="angle-right" /> How do I know if a test failure is a real bug or just flaky?

Use [Flaky Test Management](/cloud/features/flaky-test-management) to see whether
a test has a history of passing on retry, and
[Branch Review](/cloud/features/branch-review) to compare your branch against its
base and determine whether your change introduced the failure or it already
existed.

### <Icon name="angle-right" /> Do I need to change my tests to debug them in Cypress Cloud?

No. You only need to [record your runs](/cloud/get-started/setup) with
`cypress run --record`. Test Replay, Error Summaries, and the test detail sidebar
work automatically, with no changes to your test code.

## Test Replay

### <Icon name="angle-right" /> What is Test Replay?

[Test Replay](/cloud/features/test-replay) enables you and your team to troubleshoot and debug failed tests faster. After updating to Cypress `v13`, the new feature will automatically record all browser events and “replay” what your application under test looked like.

Wind back the clock to any point in an application's test execution and directly interact with tests as they happened in CI. Debug complex problems as if you were there when they first happened. You can:

- **Inspect the DOM** at the exact time of a test failure to debug tests quickly
- **View important debugging dimensions** such as network requests, console logs, and more
- **Save time recreating errors in CI locally** - replay tests as they happened in CI

<DocsImage
  src="/img/cloud/features/test-replay/test-replay-ui.png"
  alt="Test Replay Demo"
  width="80%"
/>

### <Icon name="angle-right" /> How is Cypress Test Replay different from other "replay" services?

There is an important distinction between _session_ replay services (LogRocket, FullStory, DataDog, etc) and Cypress Test Replay. In session replay, user actions are captured as the application is used and delivered back in a replay-able format, usually video or stitched DOM snapshots. These are valuable tools for gathering product insight such as user behavior, per session.

Cypress Test Replay captures every detail of your test runs as they happen in CI. Remember, these tests are running in a headless manner on a virtual machine with no UI being rendered. Sometimes tests will error or fail indicating an issue in your application. Since Cypress Cloud is monitoring the health of your CI test suite, each Test Replay offers a chance to step back in time to analyze and use [time travel debugging](/app/core-concepts/open-mode#Time-traveling), network requests, console logs, JavaScript errors, and element rendering to address problems directly. This is incredibly valuable for developer and team productivity. No more hours wasted recreating CI issues on your local machine!

### <Icon name="angle-right" /> How much does Test Replay cost?

Nothing. It's free and included in all Cypress Cloud plans.

<CloudFreePlan />

### <Icon name="angle-right" /> Can I use Test Replay for tests recorded in different browsers?

Test Replay uses [Chrome DevTools Protocol(CDP)](https://chromedevtools.github.io/devtools-protocol/), so currently supports Chromium-based browsers (Chrome, Edge, and the deprecated Electron browser) only.

Test Replay would be disabled, with a message that it's only available on Chromium, for tests run in Firefox or WebKit (Safari). You can still record and capture test [artifacts](/cloud/features/recorded-runs#Artifacts) (screenshots, videos, and CI logs) via other browsers in separate [run groups](/cloud/features/smart-orchestration/parallelization#Grouping-test-runs).

### <Icon name="angle-right" /> Can I replay tests from historical Cypress Cloud runs?

Test Replay is available for tests recorded using Cypress `v13` and up. Tests recorded prior to this will not have Test Replay enabled in Cypress Cloud. You will still have any artifacts collected during the pre `v13` test runs.

### <Icon name="angle-right" /> Can I enable or disable Test Replay for specific, individual tests, or is it a global setting? Can I configure my settings so that Test Replay is only enabled for failing test retries?

At this time, users can only opt-out of Test Replay via [project-level settings](/cloud/features/test-replay#Opt-out-of-Test-Replay) in Cypress Cloud. There is no local option for opting out at this time.

### <Icon name="angle-right" /> Can I share my test replays?

Yes! You can share Test Replays with any team members who have access to view your Cypress Cloud runs like QA, marketing, design, etc. Open the replay, copy the URL from the browser address bar and pass it along.

### <Icon name="angle-right" /> Will Test Replay write any assets to the file system?

Yes, but they are stored in a temporary directory and deleted after the run. There is nothing to `.gitignore`.

### <Icon name="angle-right" /> Is the network tab feature available exclusively in Test Replay?

All of the data within Test Replay's Developer Tools in Cypress Cloud (including network events) are already available to you when running tests locally in the Cypress app via your browser's built-in developer tools (e.g. Chrome DevTools). When reviewing a test run that occurred in CI, you can review the network events within Test Replay in Cypress Cloud.

### <Icon name="angle-right" /> Can I `console.log()` data in the console view of the Developer Tools panel?

Yes. This displays console logs from within the application under test or your spec files. You may need to use `JSON.stringify(Object)` to display deeply nested data.

### <Icon name="angle-right" /> Does Cypress Test Replay network redaction change what I can test?

No, your Cypress tests and assertions are not affected.

### <Icon name="angle-right" /> Does network redaction change what I can debug in Cypress Test Replay?

For most tests, no. You keep request timing, status codes, and the structure of each request. If you will need to inspect the redacted value itself in Cypress Cloud, turn redaction off for that project before recording.

### <Icon name="angle-right" /> Is network redaction in Cypress Test Replay on by default?

Yes. It applies to every project in Cypress Cloud with Test Replay turned on, with no configuration required.

### <Icon name="angle-right" /> Can I redact additional values specific to my application in Cypress Test Replay?

Not today. If you need a value covered that isn't, reach out to your Cypress Cloud account team.

### <Icon name="angle-right" /> Do I need a specific Cypress version to get network redaction in Test Replay?

Redaction isn't tied to a specific Cypress version.

### <Icon name="angle-right" /> What if I don't want Cypress Test Replay network traffic captured at all?

Turn off Test Replay for that project in Cypress Cloud. This stops capture of the DOM, Command Log, network traffic, and browser console logs.

## Cloud CLI

### <Icon name="angle-right" /> What is the Cypress Cloud CLI?

The [Cypress Cloud CLI](/cloud/integrations/cloud-cli) (`cy-cloud`) lets you
query your Cypress Cloud data from the command line. You can check the status of
a run, read the error and stack trace for a failed test, save a failure
screenshot, and pull the [Test Replay](/cloud/features/test-replay) timeline of
commands, network requests, and console logs, all without opening a browser.
Every command returns JSON, so it works in shell scripts, CI jobs, and AI
coding agents.

### <Icon name="angle-right" /> How do I install the Cypress Cloud CLI?

Install `@cypress/cloud` globally with your package manager (for example,
`npm install @cypress/cloud`), then run `cy-cloud login`. You need a
Cypress Cloud account, the Cloud CLI integration enabled for your organization,
and Node.js `22.21.0` or later. See the
[Cloud CLI documentation](/cloud/integrations/cloud-cli) for full setup steps.

### <Icon name="angle-right" /> How do I authenticate the Cloud CLI in CI?

Set the `CYPRESS_CLOUD_TOKEN` environment variable to a
[personal access token](/cloud/integrations/cloud-cli#Personal-access-token),
which you generate from your [Cypress Cloud profile](https://cloud.cypress.io/profile).
This authenticates without an interactive `login` step and without writing
credentials to disk, and it takes precedence over any stored credentials. Note
that `cy-cloud logout` clears stored credentials but does not unset that
environment variable.

See [Authenticate the Cloud CLI](/cloud/integrations/cloud-cli#Authenticate) for
the full setup, including OAuth and personal access token options.

### <Icon name="angle-right" /> How is the Cloud CLI different from Cloud MCP?

Both give programmatic access to your Cypress Cloud data.

[Cloud MCP](/cloud/integrations/cloud-mcp) is a remote server your AI client
connects to, and the agent selects Cypress tools automatically, which suits
conversational, in-editor debugging.

[Cloud CLI](/cloud/integrations/cloud-cli) is a command-line tool for humans,
scripts, and terminal-based agents, which suits automation and custom tooling.

Many teams use both.

### <Icon name="angle-right" /> Which URL does the Cloud CLI need allowed on a restrictive VPN?

The Cloud CLI communicates with the Cypress Cloud API at
`https://cloud-api.cypress.io`, and sign-in also uses `https://cloud.cypress.io`.
Add these to your allowlist if you run the CLI behind a restrictive VPN or
firewall. See the full list of
[URLs to allow](#Im-working-with-a-restrictive-VPN-Which-subdomains-do-I-have-to-allow-on-my-VPN-for-Cypress-Cloud-to-work-properly).

### <Icon name="angle-right" /> Which Cypress Cloud plans is the Cloud CLI available on?

The Cloud CLI is available on all Cypress Cloud plans, including the free Starter
plan, at no additional cost. An organization admin enables it once from the
**Integrations** page in Cypress Cloud.

### <Icon name="angle-right" /> Does the Cloud CLI have usage limits?

Yes. Cloud CLI requests are rate limited per user, defaulting to 100 requests
per hour, and the same limit applies across all plans. Contact
[support@cypress.io](mailto:support@cypress.io) if you need a higher limit.

Rate limits are separate from data availability. What data you can retrieve
follows the same recording limits and data retention policies as the rest of
Cypress Cloud, which do vary by plan.

### <Icon name="angle-right" /> Which version of Cypress do I need to use the Cloud CLI?

The Cloud CLI reads recorded run data from Cypress Cloud, so there is no minimum
Cypress app version. You do need to be recording runs to Cloud with
`cypress run --record`.

### <Icon name="angle-right" /> Do I need to change my tests to use the Cloud CLI?

No. The Cloud CLI reads data your runs already record. You do not modify test
code to use it.

### <Icon name="angle-right" /> Why am I getting an authentication error from the Cloud CLI?

Confirm you are logged in with `cy-cloud status`. If you authenticate through the
`CYPRESS_CLOUD_TOKEN` environment variable, verify the token is set and valid.
Remember that `cy-cloud logout` does not unset that environment variable.

### <Icon name="angle-right" /> Why can't the Cloud CLI find my run or project?

Verify the Cloud CLI integration is enabled for your organization, and that your
Cypress Cloud user has access to the project. The CLI only returns data you can
already see in Cypress Cloud.

### <Icon name="angle-right" /> What does the Cloud CLI error "Replay not available" mean?

That test does not have Test Replay data available. Confirm
[Test Replay](/cloud/features/test-replay) capturing was enabled for the run, and
that the run is within your data retention window.

## Cloud AI :sparkles:

### <Icon name="angle-right" /> What is Cloud AI?

Cloud AI is part of Cypress AI: capabilities in Cypress Cloud (such as Test Intent Summaries, Error Summaries, and UI Coverage Test Generation) plus AI in the Cypress App ([Studio AI](/app/guides/cypress-studio) and [cy.prompt()](/api/commands/prompt)) when you're connected to Cloud. These capabilities are continuously being added to improve insights and make it easier to accomplish tasks.

See [AI at Cypress](/cloud/features/cypress-ai-features) for the full picture. For [`cy.prompt`](/api/commands/prompt) execution limits, billing, and the grace period, see [cy.prompt](#cyprompt) below.

### <Icon name="angle-right" /> Do AI features require a paid plan?

No. Every Cypress AI capability and tool is available without a paid
subscription:

- **No Cypress Cloud account needed:** the
  [Cypress skills for AI agents](/app/tooling/ai-skills), the
  [`cypress tap` CLI](/app/tooling/cypress-tap), and
  [Cypress Studio](/app/guides/cypress-studio) recording (without AI
  recommendations).
- **Any Cloud plan, including the free Starter plan:**
  [`cy.prompt`](/api/commands/prompt), Studio AI recommendations, Test Intent
  Summaries, Error Summaries, [Cloud MCP](/cloud/integrations/cloud-mcp), and
  the [Cloud CLI](/cloud/integrations/cloud-cli).
- **Included with a premium solution:** UI Coverage Test Generation comes with
  [UI Coverage](/ui-coverage/get-started/introduction), and agent-ready
  accessibility reports come with
  [Cypress Accessibility](/accessibility/get-started/introduction).

A paid plan raises limits rather than unlocking capabilities: a larger
`cy.prompt` execution allowance and higher hourly limits for `cy.prompt` and
Studio AI. See
[AI usage limits](/cloud/features/cypress-ai-features#Usage-limits).

## cy.prompt

### <Icon name="angle-right" /> What is a cy.prompt execution?

Every time a [`cy.prompt`](/api/commands/prompt) command runs, in open mode or run
mode, that counts as a single cy.prompt execution. Usage is treated consistently
whether you are authoring and running tests locally or in CI runs.

As an example: if a test suite includes 3 `cy.prompt` commands in the test code and they are each invoked exactly once,
each full run of that suite consumes 3 `cy.prompt` executions.

Track usage on your organization's
[Billing & Usage](/cloud/account-management/billing-and-usage#Prompt-executions)
page. For migrating from `cy.prompt` to regular Cypress code, see the
[App FAQ](/app/faq#cyprompt).

### <Icon name="angle-right" /> What is AI self-healing?

[`cy.prompt`](/api/commands/prompt) self-heals a step when the element it needs
has changed since the step last ran, so tests keep passing as the UI evolves. When possible, the step may self-heal from a cache of previously-successful selectors for the element referenced in that spec. If no good selector exists, `cy.prompt` will create a new one using AI to find the appropriate element. See
[Self-healing](/app/guides/ai-test-generation#Self-healing) in the AI Test
Generation guide.

### <Icon name="angle-right" /> What are the cy.prompt usage limits?

Beyond your plan's execution allowance, `cy.prompt` has two additional sets of
limits.

**Per-user hourly limits** apply only to runs that are not recording to Cypress
Cloud:

- Free accounts: 100 prompts per hour per user, and 500 prompt steps per hour per
  user.
- Paid accounts (or on a free trial): 600 prompts per hour per user, and 3,000
  prompt steps per hour per user.

**Per-prompt limits** apply to every `cy.prompt` call:

- Up to 50 steps per call, to maintain context fidelity and produce reliable,
  executable commands.
- System-wide limits apply to the total input length. Very long prompts may be
  rejected or require splitting. To stay within these limits, keep one action or
  assertion per step and split long flows into multiple `cy.prompt` calls.

### <Icon name="angle-right" /> My organization shows that it is over the limit during the `cy.prompt` grace period, will I be charged anything for this?

No. There are no charges or limiting behavior related to any usage prior to the
August 1, 2026 cutoff.

### <Icon name="angle-right" /> What happens at the end of the `cy.prompt` grace period?

Your accumulated usage from before August 1, 2026 will be fully ignored for
billing purposes. On August 1, 2026, your organization will start with a count
of zero `cy.prompt` executions consumed. You will see a limit that matches your
plan and is pro-rated to your contract term.

For example, if you have 6 months remaining on your plan on August 1, 2026, and
the plan has 2,000 built-in cy.prompt executions for the year, you would have
1,000 executions available.

### <Icon name="angle-right" /> What happens when I exceed my allowed limit of cy.prompt executions?

You will see warnings in the Cypress Cloud UI as you approach your limit, and
after you cross it.

On a paid plan:

- Your tests and `cy.prompt` will run normally. You will not be automatically charged for prompt executions over your plan's limit.
- If you regularly go over your limit, we ask that you update your plan to
  match your usage.

On a free plan:

- AI self-healing and new prompt creation will be turned off for the rest of
  your monthly billing cycle.
- When your plan renews, these features will work again.

### <Icon name="angle-right" /> What happens when AI is disabled for my organization?

Existing prompt commands and steps will continue to execute, but operations that
require AI to function will fail. This includes most self-healing behavior and
the creation of new prompt commands.

Organization admins and owners can enable or disable AI capabilities from
[organization settings](/cloud/account-management/organizations#Manage-Cloud-AI).

### <Icon name="angle-right" /> When does my usage reset?

Usage is tracked similar to test results and resets on the same schedule with the
start of the billing period for your existing plan. See
[When does my billing period reset?](#When-does-my-billing-period-reset) and your
organization's
[Billing & Usage](/cloud/account-management/billing-and-usage) page for dates.

### <Icon name="angle-right" /> Can I buy increased limits?

You can upgrade your plan to gain increased execution limits, along with the
other benefits of higher-level plans. See
[Cypress Cloud plans](https://www.cypress.io/pricing?utm_source=docs.cypress.io&utm_medium=cloud-faq)
for details.

Reach out to your Cypress representative if you have questions about this, or
if you are on a plan where a self-serve upgrade is not an option for you.

### <Icon name="angle-right" /> Can I be notified of usage approaching limits?

Yes. On the [Billing & Usage](/cloud/account-management/billing-and-usage#Usage-notification)
page, you can set thresholds for email alerts based on usage, similar to the
ones you already get for test management.

### <Icon name="angle-right" /> What limitations does cy.prompt have?

See the [Limitations](/api/commands/prompt#Limitations) section in the
[`cy.prompt` API reference](/api/commands/prompt) to learn what commands and
other techniques are not supported.

Review the steps of your generated tests to confirm they are behaving as
intended, especially if attempting steps that are documented as not supported.

---

### Partials AGENTS (`docs/partials/AGENTS.md`)

# Agent rules: partials

The root [`AGENTS.md`](../../AGENTS.md) still applies; this file adds the rules
specific to `docs/partials/`, the shared MDX fragments rendered inside other
pages. Reasoning lives in
[`AGENTS_REFERENCE.md`](../../AGENTS_REFERENCE.md#partials).

## What belongs here

A partial earns its indirection only by being rendered in **more than one
place**. Before adding one, check that at least two pages will use it. Before
removing the second-to-last reference to an existing one, inline it into the
remaining page and delete the file.

```shell
# which pages render <CloudFreePlan />?
grep -rl "CloudFreePlan" docs --include="*.mdx"
```

## Writing one

- Name it `_kebab-case.mdx`. The leading underscore is what keeps Docusaurus
  and `scripts/lint-frontmatter.js` from treating it as a page, so it is not
  optional.
- No frontmatter and no H1. A partial is a fragment, not a page.
- It inherits the host page's MDX scope, so every component registered in
  `src/theme/MDXComponents.js` is available with no import.
- Headings inside a partial are the one place a custom `{#Anchor}` id is
  correct. The host page cannot rename them, so the explicit id is what keeps
  inbound links stable (see `_header-yields.mdx`).

## Registering one

Partials are used as global components (`<CloudFreePlan />`) with no per-page
import, which takes two edits to `src/theme/MDXComponents.js`: the import
**and** the name in the exported object. Miss the second and the component
renders as literal text.

```js
import CloudFreePlan from '@site/docs/partials/_cloud_free_plan.mdx'
// ...then add `CloudFreePlan,` to the exported object below.
```

Deleting a partial means deleting the registration in the same PR.

## Partials that supply a page's headings

When a partial provides most of a page's content, its headings are missing from
the right-hand table of contents unless the page re-exports them:

```jsx
import { toc as viewsToc } from '@site/docs/partials/_views.mdx'

export const toc = [
  ...viewsToc,
  { value: 'See also', id: 'See-also', level: 2 },
]
```

See `docs/accessibility/configuration/views.mdx` for the full pattern.

---

### Partials  Accessibility Premium Note (`docs/partials/_accessibility-premium-note.mdx`)

:::tip

**Cypress Accessibility** is a paid premium solution. [Schedule a demo](<https://www.cypress.io/accessibility?utm_medium=premium-solution-tip&utm_source=docs.cypress.io&utm_content=Schedule a demo>) today and see how easy it is to enhance your accessibility testing while speeding up your development process.

:::

---

### Partials  Anatomy Of An Error (`docs/partials/_anatomy-of-an-error.mdx`)

Cypress prints several pieces of information when an error occurs during a
Cypress test.

1. **Error name**: This is the type of error (e.g. `AssertionError`,
   `CypressError`)
2. **Error message**: This generally tells you what went wrong. It can vary in
   length. Some are short like in the example, while some are long, and may tell
   you exactly how to fix the error.
3. **Learn more:** Some error messages contain a **Learn more** link that will
   take you to relevant Cypress documentation.
4. **Code frame file**: This is usually the top line of the stack trace and it
   shows the file, line number, and column number that is highlighted in the
   code frame below. Clicking on this link will open the file in your
   [preferred file opener](/app/tooling/IDE-integration#File-Opener-Preference)
   and highlight the line and column in editors that support it.
5. **Code frame**: This shows a snippet of code where the failure occurred, with
   the relevant line and column highlighted.
6. **View stack trace**: Clicking this toggles the visibility of the stack
   trace. Stack traces vary in length. Clicking on a blue file path will open
   the file in your
   [preferred file opener](/app/tooling/IDE-integration#File-Opener-Preference).
7. **Print to console button**: Click this to print the full error to your
   DevTools console. The lines in that stack trace are usually clickable and
   open the files in your DevTools.

<DocsImage
  src="/img/app/core-concepts/open-mode/command-failure-error.png"
  alt="example command failure error"
/>

---

### Partials  App Quality Config Editing (`docs/partials/_app-quality-config-editing.mdx`)

Configuration lives in Cypress Cloud, not in your repository. To view or change it for a project:

1. Open your project in Cypress Cloud and go to **Project Settings**.
2. Select the **App Quality** tab, which holds the configuration editor.
3. Edit the configuration as JSON, then **Save**. **Discard** reverts unsaved edits back to the last saved version.

The editor validates your JSON against the schema when you save, so an invalid configuration can't be saved, and it shows how long ago the configuration was last saved.

---

### Partials  App Quality Config Who Can Edit (`docs/partials/_app-quality-config-who-can-edit.mdx`)

### Who can edit configuration

Editing is limited to Admin users by default. Your Cypress point-of-contact can enable editing for all users on request.

---

### Partials  Assertion Retry Boundaries (`docs/partials/_assertion-retry-boundaries.mdx`)

#### An assertion in the middle of a chain locks in the subject

`.should()` and `.and()` retry as part of the command that precedes them. Once
every assertion in the chain passes, Cypress locks in the subject at that point,
so queries that come after it retry from that subject rather than from the top
of the chain. If your application re-renders the DOM in that window, those later
queries run against a detached element.

```javascript
cy.get('.list')
  .find('li')
  .eq(2)
  .should('contain', 'Header')
  .and('be.visible') // once these pass, the li element is locked in
  .children('.child') // if the DOM re-renders, this li may be detached
```

Split the chain into separate statements so each one re-queries from the top.
[Assertions as retry boundaries](/app/core-concepts/retry-ability#Assertions-as-retry-boundaries)
covers the pattern in full.

#### An action command locks in the element it acted on

An action command such as [`.click()`](/api/commands/click) locks in its subject
the same way, so an assertion chained after it re-checks that element without
re-querying for it. This is why asserting on a class the click toggles works,
while asserting on an element the click replaces fails with
`The subject is no longer attached to the DOM`.

```javascript
// the click toggles classes on the same element
cy.get('button').click().should('have.class', 'active')

// if the click re-renders the button, alias it and query again
cy.get('button').as('btn').click()
cy.get('@btn').should('have.class', 'active')
```

---

### Partials  Attributefilters (`docs/partials/_attributefilters.mdx`)

To recognize the same element across [snapshots](/ui-coverage/core-concepts/element-identification#Snapshots) and group similar elements together, Cypress builds an identifier for each element from its attributes and its position in the DOM. When an element carries attributes that change from render to render, such as auto-generated IDs, hashed class names, or state-based flags like `link--focused`, those unstable values leak into the identifier. The result is one real element reported as several, or distinct elements collapsed into the wrong group, which inflates your element counts and hides the coverage and accessibility findings you care about.

The `attributeFilters` configuration property tells Cypress which attributes and values it may **not** use for identification and grouping. Filter out the unstable attributes and Cypress falls back to the stable ones, so a single element stays a single element across snapshots and your reports deduplicate cleanly.

## Why use attributeFilters?

- **Stop duplicate elements**: When an element's `id`, `class`, or other attribute is regenerated on each render, the same control is counted many times. Filtering the volatile attribute lets Cypress identify it consistently.
- **Improve grouping accuracy**: Removing attributes that differ between otherwise-identical elements (for example a per-row `data-cy="user-123"`) lets Cypress group them as one repeated component.
- **Ignore library-specific attributes**: Attributes injected by frameworks (Angular's `ng-*`, Emotion/JSS hashed classes, and similar) rarely describe an element's purpose and often add noise.

If instead you want Cypress to _prefer_ a particular attribute as an identifier when it is available, use [`significantAttributes`](/ui-coverage/configuration/significantattributes). `attributeFilters` only ever removes attributes from consideration; it never promotes them.

## Built-in filters

Cypress already excludes the most common sources of unstable identifiers, such as auto-generated IDs and hashed CSS classes, so many applications need no `attributeFilters` configuration at all.

Your configured rules run **before** these built-in filters, so a rule with `include: true` can re-enable an attribute that a built-in filter would otherwise drop. Add `attributeFilters` when your application produces unstable identifiers that these defaults don't already cover.

## Scope

:::info

**Note:** setting `attributeFilters` at the root of your configuration impacts both UI Coverage and Cypress Accessibility reports. To configure the products separately, nest the property under a `uiCoverage` or `accessibility` key. A nested `attributeFilters` completely replaces a root-level one for that product; the two lists are not merged.

:::

## Setting attributeFilters

To add or edit `attributeFilters`, open the **App Quality** tab in your project settings in Cypress Cloud. See [Setting configuration](/ui-coverage/configuration/overview#Setting-configuration) for details, including how to regenerate past reports with a new configuration without rerunning your tests.

## Syntax

```json title="App Quality Config"
{
  "attributeFilters": [
    {
      "attribute": string,
      "value": string,
      "include": boolean,
      "comment": string
    }
  ]
}
```

To scope rules to a single product, nest the property under a `uiCoverage` or `accessibility` key, as described in [Scope](#Scope) above.

### Options

| Option      | Required | Default | Description                                                                                                                                                                           |
| ----------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `attribute` | Required |         | A regular expression matched against attribute names. Must be a valid HTML attribute name.                                                                                            |
| `value`     | Optional | `.*`    | A regular expression matched against the attribute's value.                                                                                                                           |
| `include`   | Optional | `true`  | Whether the matched attribute may be used for identification (`true`) or is ignored (`false`).                                                                                        |
| `comment`   | Optional |         | A note about why this rule exists, for your team's benefit. Comments appear only in the configuration itself. They have no effect on identification and are not displayed in reports. |

Each rule accepts only these four properties. Cypress Cloud validates your configuration and rejects any unrecognized property, as well as two rules that are exactly identical.

## How rules are applied

Whether Cypress may use an attribute to identify an element is decided by the **first** rule whose `attribute` and `value` both match. Because the first match wins, order your rules from most specific to least specific: put `include: true` exceptions first, then broader `include: false` catch-all rules. For example, you can exclude every `aria-label` from identification with a catch-all rule, while keeping a few known-stable values by listing `include: true` rules for them first.

An attribute that matches no rule is available for use, so `include: true` is only needed to define exceptions.

Keep these matching details in mind when writing patterns:

- **Patterns match the whole string.** Each `attribute` and `value` pattern is anchored automatically, as if wrapped in `^(...)$`, so it must match the entire name or value. Use wildcards for partial matches: `value: "user-.*"` matches `user-123`, whereas `value: "user"` matches only the exact string `user`. If your pattern already starts with `^` or ends with `$`, it is used as written.
- **Escape backslashes for JSON.** Because JSON uses the backslash as its own escape character, a regex token like `\d` must be written `\\d` in the configuration. A single backslash is dropped, turning `\d` into a literal `d` that matches nothing you intended.
- **Attribute names are matched case-insensitively; values are matched case-sensitively.**
- **Only attributes and individual `class` tokens can be filtered.** Rules never apply to an element's tag name or its position among siblings (`nth-child`), which Cypress may still fall back to when no attributes are usable.

## Examples

### Excluding framework-generated IDs

React's `useId` hook (used by libraries like MUI and Radix) produces `id` values such as `:r0:` that change on every render. Excluding them lets Cypress identify each field by its stable `name` instead.

```json title="App Quality Config"
{
  "attributeFilters": [
    {
      "attribute": "id",
      "value": ":r.*",
      "include": false,
      "comment": "React useId() values are regenerated on every render"
    }
  ]
}
```

#### HTML

```xml
<form>
  <input id=":r0:" name="email" type="email" />
  <input id=":r1:" name="password" type="password" />
</form>
```

#### Element identifiers displayed

```
[name="email"]
[name="password"]
```

---

### Filtering an ID and the attributes that reference it

When you filter a dynamic `id`, also filter the attributes that point at it, or elements will still be identified by those related dynamic values. Here Angular Material generates `mat-*` IDs and wires them through `for` and `aria-describedby`. Common relationships to filter alongside an `id` include:

- Form associations (`for` on labels)
- ARIA relationships (`aria-labelledby`, `aria-describedby`, `aria-controls`, `aria-owns`, `aria-details`)

```json title="App Quality Config"
{
  "attributeFilters": [
    {
      "attribute": "id|for|aria-describedby|aria-labelledby",
      "value": "mat-.*",
      "include": false,
      "comment": "Angular Material regenerates mat-* ids per render"
    }
  ]
}
```

#### HTML

```xml
<div>
  <label for="mat-input-0">Email</label>
  <input id="mat-input-0" name="email" aria-describedby="mat-hint-2" />
  <span id="mat-hint-2">We'll only use this to sign you in.</span>
</div>
```

#### Element identifiers displayed

```
label
[name="email"]
span
```

---

### Keeping one attribute while excluding a whole family

Because the first matching rule wins, an `include: true` rule listed before a broad `include: false` rule protects the attributes it matches. Here Cypress keeps identifying elements by your `data-cy` test hook while ignoring the stateful `data-*` attributes that component libraries add and change as the UI updates.

```json title="App Quality Config"
{
  "attributeFilters": [
    {
      "attribute": "data-cy",
      "include": true,
      "comment": "Always identify elements by our test hook"
    },
    {
      "attribute": "data-.*",
      "include": false,
      "comment": "Ignore library state attributes like data-state, data-headlessui-state"
    }
  ]
}
```

#### HTML

```xml
<button data-cy="menu-toggle" data-headlessui-state="open" data-state="active">
  Menu
</button>
```

#### Element identifiers displayed

```
[data-cy="menu-toggle"]
```

---

### Grouping repeated elements by ignoring per-row IDs

Filtering a per-instance value lets Cypress group otherwise-identical elements into a single repeated component instead of tracking each row separately. Here each delete button carries the row's database ID, so removing that value collapses them into one group.

```json title="App Quality Config"
{
  "attributeFilters": [
    {
      "attribute": "id",
      "value": "delete-user-\\d+",
      "include": false,
      "comment": "Row action ids include the per-user database id"
    }
  ]
}
```

#### HTML

```xml
<button id="delete-user-4821" class="delete-btn">Delete</button>
<button id="delete-user-9034" class="delete-btn">Delete</button>
```

#### Element identifiers displayed

```
.delete-btn (2 instances)
```

## Confirming a filter worked

You don't need to rerun your tests to check a rule. Regenerate a historical run from its **Properties** tab and the report is reprocessed with your current configuration. Confirm the change by checking that an element that previously appeared multiple times now appears once, or that a set of repeated elements collapsed into a single entry.

If nothing changed, revisit [How rules are applied](#How-rules-are-applied). The most common causes are a pattern that doesn't fully match the value, an earlier rule taking precedence, or a report that was processed before the configuration was saved.

---

### Partials  Auto Cancellation Benefits (`docs/partials/_auto-cancellation-benefits.mdx`)

<Icon name="check-circle" color="green" /> **Benefits:** Cancelling a run once
test failures reach your threshold will:

1. **Save time.** Identify failures early and resolve issues faster.
2. **Reduce CI costs.** Cut down on unnecessary test execution, leading to significant savings for large test suites.
3. **Free up CI resources.** Stop spending machines on a failed run and keep CI pipelines available for validating fixes.
4. **Optimize future runs.** With **[Spec Prioritization](/cloud/features/smart-orchestration/spec-prioritization)** and **Auto Cancellation**, failed tests run first in the next attempt, stopping early if issues persist to maximize efficiency.

---

### Partials  Ci Provider Cloud Steps (`docs/partials/_ci_provider_cloud_steps.mdx`)

1. [Recording test results with the `--record` flag](/cloud/get-started/setup)
   to Cypress Cloud.
   - In-depth and shareable
     [test reports](/cloud/features/recorded-runs#Latest-Runs).
   - Visibility into test failures via quick access to [Test Replay](/cloud/features/test-replay), error messages, stack
     traces, screenshots, videos, and contextual details.
   - [Integrating testing with the pull-request (PR) process](/cloud/integrations/github)
     via
     [commit status check guards](/cloud/integrations/github#Status-checks)
     and convenient
     [test report comments](/cloud/integrations/github#Pull-request-comments).
   - [Detecting flaky tests](/cloud/features/flaky-test-management) and surfacing
     them via [Slack alerts](/cloud/features/flaky-test-management#Slack) or
     [GitHub PR status checks](/cloud/features/flaky-test-management#GitHub).

2. [Parallelizing test runs](/cloud/features/smart-orchestration/parallelization)
   and optimizing their execution via
   [intelligent load-balancing](/cloud/features/smart-orchestration/load-balancing#Balance-strategy)
   of test specs across CI machines with the `--parallel` flag.

3. Organizing and consolidating multiple `cypress run` calls by labeled groups
   into a single report within [Cypress Cloud](https://on.cypress.io/cloud). In
   the example above we use the `--group UI-Chrome` flag to organize all UI tests for the Chrome browser into a group labeled "UI-Chrome" inside the Cypress Cloud report.

---

### Partials  Cloud Free Plan (`docs/partials/_cloud_free_plan.mdx`)

To get started with Cypress Cloud,
[sign up](https://cloud.cypress.io/signup) to start your **30 day free trial** - including all
premium Cypress Cloud features and plenty of test results
to let you experience the power of Cypress Cloud!

---

### Partials  Component Testing Error States (`docs/partials/_component-testing-error-states.mdx`)

`cy.mount()` is an asynchronous Cypress command: it _enqueues_ the mount and
returns immediately, before the component ever renders. When a component throws
during render, the error surfaces as an uncaught exception rather than as a
synchronous throw.

By default Cypress fails the test on any uncaught exception, so to assert on a
render error you listen for it with
[`cy.on('uncaught:exception')`](/api/cypress-api/catalog-of-events#Uncaught-Exceptions)
and return `false` to prevent Cypress from failing the test:

---

### Partials  Cookie Default Domain (`docs/partials/_cookie-default-domain.mdx`)

The `domain` option defaults to the hostname of the application under test.
Before [`cy.visit()`](/api/commands/visit) loads a page, the application under
test is on `about:blank`, so Cypress uses the hostname it serves the spec from
instead (usually `localhost`). Pass `domain` explicitly to work with cookies on
another domain before visiting.

---

### Partials  Cy Env Assert Derived Value (`docs/partials/_cy-env-assert-derived-value.mdx`)

Every assertion writes to the Command Log, and the entry contains the values
being compared. Assertions accept no logging options, so you cannot suppress
them. Assert on a boolean you derive from the value instead.

<Icon name="exclamation-triangle" color="red" /> **Incorrect Usage**

```javascript
cy.env(['apiKey']).should('deep.include', { apiKey: 'secret-key-12345' })
// ❌ Command Log: assert expected { apiKey: 'secret-key-12345' } to deep
// include { apiKey: 'secret-key-12345' }
```

<Icon name="check-circle" color="green" /> **Correct Usage**

```javascript
cy.env(['apiKey']).then(({ apiKey }) => {
  expect(Boolean(apiKey)).to.be.true
})
// ✅ Command Log: assert expected true to be true
```

---

### Partials  Cy Env Vs Cypress Expose (`docs/partials/_cy-env-vs-cypress-expose.mdx`)

Both [`cy.env()`](/api/commands/env) and [`Cypress.expose()`](/api/cypress-api/expose) provide access to configuration values in Cypress, but they serve different security and execution needs. Choosing the right API helps avoid accidental exposure of sensitive data and keeps configuration intent clear.

#### Use Cypress.expose() for public configuration

Recommended when:

- **Values are public or non-sensitive** - Examples include feature flags, API versions, environment labels, or plugin configuration that is safe to appear in browser state.
- **Synchronous access is needed** - `Cypress.expose()` returns values immediately, without requiring Cypress command chaining.

#### Use `cy.env()` for sensitive or secret values

Choose `cy.env()` when security, scoping, and controlled access matter. Recommended when:

- **Values are sensitive** - API keys, passwords, tokens, or any data that should not be broadly exposed to the browser.
- **Security is a priority** - `cy.env()` only exposes the variables you explicitly request and does not automatically serialize them into browser state.
- **You're already working within Cypress command chains**: `cy.env()` is asynchronous and designed to be used inside Cypress tests and hooks.

**Example: choosing the right API**

```javascript
// ✅ Use cy.env() for sensitive values
cy.env(['apiKey']).then(({ apiKey }) => {
  cy.request({
    url: 'https://api.example.com/users',
    headers: { Authorization: `Bearer ${apiKey}` },
  })
})

// ✅ Use Cypress.expose() for public configuration
const apiVersion = Cypress.expose('apiVersion') // Synchronous, public value
const featureFlag = Cypress.expose('featureFlag') // Safe to expose in browser
```

---

### Partials  Cy Env Yielded Value Caution (`docs/partials/_cy-env-yielded-value-caution.mdx`)

:::caution

`cy.env()` logs the key names you ask for and never the values. That protection
ends at the command boundary. The object `cy.env()` yields is an ordinary
JavaScript object, and Cypress does not mask, redact, or track the values inside
it. Assertions, [`.its()`](/api/commands/its),
[`.invoke()`](/api/commands/invoke), and any chained command that fails can all
print a value to the [Command Log](/app/core-concepts/open-mode#Command-Log) and
the [console output](/app/core-concepts/open-mode#Console-output). What happens
to a value after `cy.env()` yields it is up to you. See
[Handling the yielded value safely](/api/commands/env#Handling-the-yielded-value-safely).

:::

---

### Partials  Default Selector Priority (`docs/partials/_default-selector-priority.mdx`)

### Default Selector Priority

1. `data-cy`
2. `data-test`
3. `data-testid`
4. `data-qa`
5. `name`
6. `id`
7. `class`
8. `tag`
9. `attributes`
10. `nth-child`

---

### Partials  Document Domain Workaround (`docs/partials/_document-domain-workaround.mdx`)

:::caution

<Icon name="exclamation-triangle" /> **Re-Enabling document.domain Injection**

As of Cypress [v14.0.0](/app/references/changelog#14-0-0), [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain)
will no longer be injected into `text/html` pages by default.

This means you must now use `cy.origin()` when navigating between different _origins_
in the same test. Previously, `cy.origin()` was only necessary when navigating between
different [superdomains](/app/guides/cross-origin-testing#Parts-of-a-URL) in the same test.

By setting the
[injectDocumentDomain](/app/references/configuration#injectDocumentDomain) configuration option to `true`,
Cypress will attempt to inject `document.domain` into `text/html` pages.

A superdomain is comprised of the trailing two elements of the hostname, delimited by
a `.` (period). Given `https://www.cypress.io`, the superdomain is determined to be
`cypress.io`. When this option is enabled, `cy.origin()` is not necessary when navigating
between `https://www.cypress.io` and `https://docs.cypress.io`, but is necessary
when navigating between `https://www.cypress.io` and `https://www.auth0.com`.

- This will cause issues with certain sites, especially those that use
  [origin-keyed agent cluster](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin-Agent-Cluster)s.
- This option is deprecated, and will be removed in a future version of Cypress.
  :::

---

### Partials  Fixture Vs Readfile (`docs/partials/_fixture-vs-readfile.mdx`)

|                               | `cy.fixture()`                                          | `cy.readFile()`                             |
| ----------------------------- | ------------------------------------------------------- | ------------------------------------------- |
| Path is relative to           | `fixturesFolder`                                        | The project root                            |
| File extension                | Optional                                                | Required                                    |
| Reads from disk               | Once per path and encoding, then yields the cached copy | On every call                               |
| Retries until assertions pass | No                                                      | Yes, reading the file again on each retry   |
| Images by default             | A `base64` string                                       | A `utf8` string                             |
| Default timeout               | `responseTimeout`                                       | `defaultCommandTimeout`                     |
| Command Log                   | Not logged                                              | Logged                                      |
| Missing file                  | Always fails                                            | Can be asserted with `.should('not.exist')` |

---

### Partials  Force Http1 Deprecation (`docs/partials/_force-http1-deprecation.mdx`)

:::caution

[`forceHttp1`](/app/references/configuration#forceHttp1) is both introduced and deprecated in Cypress 16. It exists only to give suites time to migrate, or as a temporary escape hatch while an issue you have filed is fixed, and it will be removed once the native browser network is supported long term. Do not set it to `true` only to avoid updating tests for the native browser network, such as skipping `Cypress.isBrowser()` gates. Treat it as a temporary aid, not a permanent setting.

:::

---

### Partials  Header Assertions (`docs/partials/_header-assertions.mdx`)

### Assertions [<Icon name="question-circle" title="Learn about assertions"/>](/app/core-concepts/introduction-to-cypress#Assertions) {#Assertions}

---

### Partials  Header Requirements (`docs/partials/_header-requirements.mdx`)

### Requirements [<Icon name="question-circle" title="Learn about chaining commands"/>](/app/core-concepts/introduction-to-cypress#Chains-of-Commands) {#Requirements}

---

### Partials  Header Timeouts (`docs/partials/_header-timeouts.mdx`)

### Timeouts [<Icon name="question-circle" title="Learn about timeouts"/>](/app/core-concepts/introduction-to-cypress#Timeouts) {#Timeouts}

---

### Partials  Header Yields (`docs/partials/_header-yields.mdx`)

### Yields [<Icon name="question-circle" title="Learn about subject management"/>](/app/core-concepts/introduction-to-cypress#Subject-Management) {#Yields}

---

### Partials  Import Mount Functions (`docs/partials/_import-mount-functions.mdx`)

Different frameworks render their components differently, so we provide
framework-specific `mount()` functions, which can be imported like so:

<Tabs>
<TabItem value='React'>

:::note

<strong>A note for React users</strong>

The `mount()` command exported from the
[cypress/react](https://github.com/cypress-io/cypress/tree/develop/npm/react)
module supports standard JSX syntax for mounting components.

:::

```js
import { mount } from 'cypress/react'
```

</TabItem>

<TabItem value='Vue'>

:::note

<strong>A note for Vue users</strong>

The `mount()` command exported from the
[cypress/vue](https://github.com/cypress-io/cypress/tree/develop/npm/vue)
library uses [Vue Test Utils](https://vue-test-utils.vuejs.org/) internally, but
instead of mounting your components in a virtual browser in node, it mounts them
in your actual browser.

:::

```js
import { mount } from 'cypress/vue'
```

</TabItem>
<TabItem value='Angular'>

:::note

<strong>A note for Angular users</strong>

The `mount()` command exported from the
[cypress/angular](https://github.com/cypress-io/cypress/tree/develop/npm/angular)
library uses [Angular TestBed](https://angular.io/api/core/testing/TestBed)
internally, but instead of mounting your components in a virtual browser in
node, it mounts them in your actual browser.

:::

```ts
import { mount } from 'cypress/angular'
```

</TabItem>
</Tabs>

---

### Partials  Intellisense Code Completion (`docs/partials/_intellisense-code-completion.mdx`)

:::info

✨ IntelliSense is available in your Cypress spec files by adding a special
triple slash comment line. Read about
[Intelligent Code Completion](/app/tooling/IDE-integration#Triple-slash-directives).

:::

---

### Partials  Inverted Contains Selection (`docs/partials/_inverted-contains-selection.mdx`)

There is no built-in negation for [`cy.contains()`](/api/commands/contains), so
there is no way to ask it directly for the elements that do _not_ contain a
piece of text. Instead, select the full set of elements and remove the matching
ones with [`.not()`](/api/commands/not) and the
[jQuery :contains](https://api.jquery.com/contains-selector/) selector. The
match is a case-sensitive substring match.

```html
<ul>
  <li>Test: Name</li>
  <li>Test: Name (1)</li>
  <li>Test: Name (2)</li>
  <li>Test: Name (3)</li>
</ul>
```

```javascript
// yields only <li>Test: Name</li>, the item without a numeric suffix
cy.get('li').not(':contains("(")')
```

The same approach works with [`.filter()`](/api/commands/filter) and the
[:not()](https://api.jquery.com/not-selector/) selector when you would rather
keep a positive filter:

```javascript
// yields the rows that are not disabled
cy.get('tr').filter(':not(.disabled)')
```

---

### Partials  Native Browser Network Browsers (`docs/partials/_native-browser-network-browsers.mdx`)

| Browser                | `forceHttp1: false` (default) | `forceHttp1: true`  |
| ---------------------- | ----------------------------- | ------------------- |
| Chrome, Chromium, Edge | Native browser network        | Legacy network path |
| Firefox, WebKit        | Legacy network path           | Legacy network path |
| Electron               | Legacy network path           | Legacy network path |

Firefox and WebKit continue to use the legacy network path because Cypress has not
implemented a native browser network path for them yet. Electron also uses the legacy
network path; see
[Electron is deprecated as a test browser](/app/references/migration-guide#Electron-browser-deprecated).

---

### Partials  Profiles (`docs/partials/_profiles.mdx`)

One Cypress Cloud project usually records many kinds of runs (pull request checks, nightly regression suites, per-team smoke tests), and each kind is best served by a different App Quality configuration. The `profiles` property lets you keep a single base configuration and layer targeted overrides on top of it. The right override is selected automatically from the [run tags](/app/references/command-line#cypress-run-tag-lt-tag-gt) you already pass to `cypress run`, so a pull request run and a full regression run can each get exactly the configuration that makes their report actionable, with no changes to your test code and no second project to maintain.

Before reaching for profiles, consider whether separate Cypress Cloud projects would be simpler. Distinct projects for different applications or teams usually keep reporting and tracking clearer, and are the recommended first choice. Reach for profiles when the runs belong in one project but need different configuration.

## Why use profiles?

- **Tune pull request checks against regression runs**: Gate merges with a narrow configuration focused on your most critical flows, so the report a developer sees on a PR is small, fast to act on, and high in "solvability". Keep a wide configuration on the full regression suite to track everything else on a slower cadence.
- **Team-specific reporting**: When multiple teams share one project, each team can tag its runs and see a report scoped to the pages or elements it owns, filtering out everyone else's. Nobody has to read around results they don't care about.
- **Purpose-built audit runs**: A one-off audit, such as a localization pass, a design-system sweep, or a deep dive on an area you normally exclude, can use configuration you'd never want applied to every run.

## How profiles work

### Selecting a profile

Profiles are selected by matching run tags to profile names. When you record a run with the [`--tag`](/app/references/command-line#cypress-run-tag-lt-tag-gt) flag, Cypress Cloud walks the `profiles` array in order and applies the **first profile whose `name` exactly matches one of the run's tags**. Matching is an exact, case-sensitive string comparison: `aq-config-regression` matches only the tag `aq-config-regression`, not `AQ-Config-Regression` or `aq-config-regression-nightly`. When several tags match different profiles, the first match in the array wins (so list more specific profiles before broader ones), and the order the tags appear on the run makes no difference. If no tag matches, your base configuration is used unchanged.

Profiles are resolved when a run is processed, not when your tests execute. Reprocessing a past run re-applies the profiles and configuration you have saved now, so you can adjust a profile and see its effect on an existing run without recording again.

### How a profile changes your configuration

When a profile applies, its `config` is laid over your base configuration one setting at a time. Only the settings you include in the profile change; everything else stays exactly as it is in your base configuration. A few things are worth knowing so the result matches what you expect:

- **A setting in a profile fully replaces the base version of that setting.** Lists are not combined. If your base configuration has three `elementFilters` rules and a profile defines its own `elementFilters`, the profile's rules are used on their own, so copy over any base rules you still want to apply.
- **Anything you leave out of a profile stays the same.** You only need to list what's different for that kind of run; the rest is inherited from your base configuration.
- **The `accessibility` and `uiCoverage` objects are merged one level deep.** Overriding a single setting inside one of them, such as `accessibility.significantAttributes`, leaves the sibling settings in that object (like `accessibility.elementFilters`) untouched, so you can adjust one product-specific setting without restating the rest.

### What a profile can and can't change

A profile's `config` accepts any App Quality configuration setting your base configuration supports: the same `viewFilters`, `elementFilters`, `views`, and product-specific settings you'd set at the root. Two limits are worth knowing:

- **You can't nest a `profiles` array inside a profile.** Profiles live only at the top level of your configuration; one level of overrides is the maximum.
- **There's no switch to skip a run or turn a product off.** A profile can only change configuration values. To suppress a report for a certain kind of run, point its profile at a deliberately narrow configuration (for example, `viewFilters` that exclude every view) so the run produces an empty or tightly scoped report instead.

## Best practices

Use a naming convention like `aq-config-*` (for example, `aq-config-regression`, `aq-config-pr`) so it's obvious that a tag exists for configuration lookup rather than for filtering or grouping runs in Cypress Cloud.

Being explicit this way helps avoid accidentally changing or removing a tag that a profile depends on. Because names are matched exactly against run tags, keep them stable: renaming a profile or changing a tag silently falls back to the base configuration for those runs.

## Syntax

```json title="App Quality Config"
{
  "profiles": [
    {
      "name": string,
      "config": {
        // Any App Quality configuration options
      },
      "comment": string
    }
  ]
}
```

### Options

| Option    | Required | Description                                                                                                                                                                                                                    |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`    | Required | Identifies the profile so a run can select it. Its only purpose is matching: the profile applies when one of the run's tags is an exact, case-sensitive match for this value. It isn't shown in reports or used anywhere else. |
| `config`  | Required | An object containing any App Quality configuration options, except a nested `profiles` array. These values override the root configuration.                                                                                    |
| `comment` | Optional | A note about why this profile exists, for your team's benefit. Comments appear only in the configuration itself. They have no effect on behavior and are not displayed in reports.                                             |

---

### Partials  Record Key Env Var (`docs/partials/_record-key-env-var.mdx`)

:::caution

`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.

:::

---

### Partials  Results Api Env Vars (`docs/partials/_results-api-env-vars.mdx`)

The `@cypress/extract-cloud-results` helper detects the correct Cloud run by matching environment variables from where it runs against those present when the run was recorded, which is why it works automatically from the same CI context (as in the examples above).

Knowing which variables it looks for helps with more complex setups and with local iteration: set them to match what was present in CI to pull a specific run (recorded within the last 7 days) from your machine.

### Prerequisites

Two prerequisites apply to every provider:

1. Record the Cypress run and run your validation script within the same CI run (the same build, workflow, or pipeline).
2. Run the validation script _after_ the run has been recorded, either in a separate job that depends on the recording job (using your provider's dependency option, such as `needs`, `dependsOn`, or `requires`), or serially after the recording step in the same job.

### Environment variables by CI provider

Each CI provider has a unique combination of components, patterns, and environment variables that must be interpreted by this module. Expand a provider below for its essential environment variables.

<AccordionBlock title="GitHub Actions" icon={<Icon name="github" />}>

References: [Understanding GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) | [GitHub Actions default environment variables](https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables)

**Essential environment variables**

- `GITHUB_ACTIONS` - Presence identifies the environment as a GitHub Actions environment.
- `GITHUB_RUN_ID` - Value uniquely identifies a GitHub Actions workflow instance. Value does not change as jobs in the workflow are re-executed.
- `GITHUB_RUN_ATTEMPT` - Value identifies the workflow instance's attempt index. Value is incremented each time jobs are re-executed.

</AccordionBlock>

<AccordionBlock title="GitLab" icon={<Icon name="gitlab" />}>

References: [GitLab CI/CD pipelines](https://docs.gitlab.com/ee/ci/pipelines/) | [GitLab predefined variables](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)

**Essential environment variables**

- `GITLAB_CI` - Presence identifies the environment as a GitLab CI environment.
- `CI_PIPELINE_ID` - Value uniquely identifies a GitLab pipeline workflow. This value does not change as jobs in the pipeline are retried.
- `CI_JOB_NAME` - Value uniquely identifies a single job name within a pipeline. Ex. `run-e2e`.
- `CI_JOB_ID` - Value uniquely identifies an execution instance of a job. This value will change each time a job is executed/re-executed.

</AccordionBlock>

<AccordionBlock title="Jenkins" icon={<Icon name="jenkins" />}>

References: [Jenkins documentation](https://www.jenkins.io/doc/) | [Jenkins environment variables](https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables)

Jenkins is heavily customizable through the usage of plugins, which limits the amount of assumptions we can make about available environment variables and overall behavior.

We have implemented Jenkins support within this module using the broadest set of available default values. For the purposes of this documentation, though, we will discuss terms related to [Jenkins Pipeline support](https://www.jenkins.io/doc/book/pipeline/getting-started/).

**Essential environment variables**

- `JENKINS_HOME` - Presence identifies the environment as a Jenkins environment.
- `BUILD_URL` - Value uniquely identifies a Jenkins job execution, including name and id characteristics.

</AccordionBlock>

<AccordionBlock title="Azure" icon={<Icon name="microsoft" />}>

References: [Azure Pipelines key concepts](https://learn.microsoft.com/en-us/azure/devops/pipelines/get-started/key-pipelines-concepts?view=azure-devops) | [Azure Pipelines predefined variables](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml)

> Note: Cypress v13.13.1 is the earliest Cypress release that records the environment variables necessary for this module to identify runs in an Azure environment. Previous Cypress versions are not supported in Azure pipelines.

**Essential environment variables**

- `TF_BUILD` and `AZURE_HTTP_USER_AGENT` - Combined presence identifies the environment as an Azure pipeline environment.
- `SYSTEM_PLANID` - Value uniquely identifies a pipeline run. Value does not change as jobs within the pipeline are retried from failure.
- `SYSTEM_JOBID` - Value uniquely identifies a job execution. Value changes each time a job is retried from failure, in conjunction with the `SYSTEM_JOBATTEMPT` being incremented.
- `SYSTEM_JOBATTEMPT` - Value identifies the pipelines shared attempt index. Value is incremented when jobs are retried from failure.

</AccordionBlock>

<AccordionBlock title="CircleCI" icon={<Icon name="cog" />}>

References: [About CircleCI](https://circleci.com/docs/about-circleci/) | [CircleCI built-in environment variables](https://circleci.com/docs/variables/#built-in-environment-variables)

> Note: Cypress v13.13.1 is the earliest Cypress release that records the environment variables necessary for this module to identify runs in an CircleCI environment. Previous Cypress versions are not supported in CircleCI pipelines.

**Essential environment variables**

- `CIRCLECI` - Presence identifies the environment as a CircleCI environment.
- `CIRCLE_PIPELINE_ID` - Value uniquely identifies a CircleCI pipeline, created on push or manually triggered through the UI. This value does not change as workflows within the pipeline are re-executed.
- `CIRCLE_WORKFLOW_ID` - Value uniquely identifies an instance of a workflow's execution within a pipeline. This value will be updated upon each workflow execution; in other words, retrying a workflow from failure from the Circle UI will create a new workflow with a new `CIRCLE_WORKFLOW_ID` value available to the jobs executed within it.
- `CIRCLE_WORKFLOW_JOB_ID` - Value uniquely identifies an execution instance of a named job within a workflow instance.

</AccordionBlock>

<AccordionBlock title="AWS CodeBuild" icon={<Icon name="aws" />}>

References: [AWS CodeBuild documentation](https://docs.aws.amazon.com/codebuild/) | [AWS CodeBuild environment variables](https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html)

**Essential environment variables**

- `CODEBUILD_BUILD_ID` - Presence identifies the environment as an AWS CodeBuild environment. Value uniquely identifies a build.

</AccordionBlock>

<AccordionBlock title="Drone" icon={<Icon name="cog" />}>

References: [Drone pipeline overview](https://docs.drone.io/pipeline/overview/) | [Drone environment reference](https://docs.drone.io/pipeline/environment/reference/)

**Essential environment variables**

- `DRONE` - Presence identifies the environment as a Drone environment.
- `DRONE_BUILD_NUMBER` - Value uniquely identifies a Drone build.

</AccordionBlock>

<AccordionBlock title="Bitbucket" icon={<Icon name="bitbucket" />}>

References: [Bitbucket Cloud documentation](https://support.atlassian.com/bitbucket-cloud/docs/) | [Bitbucket variables and secrets](https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/)

**Essential environment variables**

- `BITBUCKET_BUILD_NUMBER` - Presence identifies the environment as a Bitbucket environment. Value uniquely identifies a build.
- `BITBUCKET_STEP_RUN_NUMBER` - Value indicates a build step execution index and increments when a step is retried. Initial value of 1.

</AccordionBlock>

<AccordionBlock title="Buildkite" icon={<Icon name="cog" />}>

References: [Buildkite documentation](https://buildkite.com/docs) | [Buildkite environment variables](https://buildkite.com/docs/pipelines/environment-variables)

**Essential environment variables**

- `BUILDKITE` - Presence identifies the environment as a Buildkite environment.
- `BUILDKITE_BUILD_ID` - Value uniquely identifies a build. This value does not change across different jobs within the same build.
- `BUILDKITE_JOB_ID` - Value uniquely identifies a job execution. Each job in a build has a unique job ID.
- `BUILDKITE_RETRY_COUNT` - Value indicates the retry attempt for a job. Default value of 0.

</AccordionBlock>

### Local development example

To iterate on your verification script and see everything working without putting code into your CI environment, simulate the CI context for a specific Cypress run locally. This can save a lot of time when getting started.

If you executed a run in GitHub Actions and it was recorded to Cypress Cloud, you would set these 5 environment variables to replicate the context of that run locally and execute your local handler script. This is a great way to iterate on your script and verify everything is working as expected, without having to integrate anything in CI. It's also useful for debugging.

```shell
CYPRESS_PROJECT_ID=AAA
CYPRESS_RECORD_KEY=BBB
GITHUB_ACTIONS=true
GITHUB_RUN_ID=111
GITHUB_RUN_ATTEMPT=1
node verifyResults.js
```

The Results API will then look for the Cypress Cloud run that matches this run ID. If there is more than one Cypress Cloud run found for that GitHub Actions Run, you can pass run tags to narrow down to one run's report.

---

### Partials  Significantattributes Validation (`docs/partials/_significantattributes-validation.mdx`)

Cypress Cloud rejects a configuration when:

- An entry isn't a valid HTML attribute name. Names can't contain spaces, quotes, or the characters `>`, `/`, and `=`.
- The same attribute name appears twice in the list.
- An entry isn't a plain string, for example an object.

---

### Partials  Sitemap Scan Example (`docs/partials/_sitemap-scan-example.mdx`)

import CodeBlock from '@theme/CodeBlock'
import {
  copy,
  singleTestCode,
  separateTestCode,
} from '@site/docs/partials/sitemapScanCode'

If your project lacks existing Cypress tests, a common approach is to drive{' '}
{copy[props.product].name} from a sitemap or an array of target URLs. Visiting
each URL performs a light interaction that {copy[props.product].name} records,
giving you a first {copy[props.product].reportKind} report for the pages your
suite doesn't reach yet.

### Example: Visit every sitemap URL in a single test

The example below fetches your `sitemap.xml` at runtime and visits every URL it
finds in a single test. This is the quickest way to get started, with no list to
maintain:

<CodeBlock language="js">{singleTestCode[props.product]}</CodeBlock>

{props.product === 'accessibility' ? (

<p>
  The <code>scrollIntoView</code> call is optional. Test Replay captures the
  full page for accessibility analysis on load, so you only need it when content
  appears through progressive scrolling, such as lazy-loaded images or infinite
  lists. It can also be worth keeping to exercise scrolling itself, since a page
  that cannot be scrolled to reach its content is an accessibility problem in
  its own right.
</p>

) : null}

### Example: Visit each URL in separate tests

The single-test scan above is quick to set up, but putting each URL in a
separate test is often the better choice:

- **Tracking**: each page becomes a distinct test in Cypress Cloud, so a page
  that fails to load shows up as its own failing test with its own
  [Test Replay](/cloud/features/test-replay), instead of collapsing the whole
  scan into one pass/fail.
- **Performance**: a single test that visits every page keeps accumulating DOM
  snapshots and command history as it runs, which slows it down and makes it
  harder to debug. Separate tests each start clean, so they stay fast.
- **Isolation**: [test isolation](/app/core-concepts/writing-and-organizing-tests#Test-Isolation)
  resets the browser state between pages, so one page's cookies or storage can't
  leak into the next.

Because Cypress defines tests when the spec loads (before any command runs), the
list of URLs has to exist before the run starts rather than come from a sitemap
fetched at runtime. You can hard-code it in the spec, import it from a committed
file, or generate it in your Cypress config and pass it to the spec. This
documentation's own test suite takes the last approach: it builds the list of
pages in `cypress.config` and loops over them to create one test per page.

<CodeBlock language="js">{separateTestCode[props.product]}</CodeBlock>

The result is a first-load {copy[props.product].reportKind} report for every URL
in your site. Any Cypress tests you write for specific workflows automatically
expand the {copy[props.product].reportKind} area to include the states and
variations those workflows reach.

---

### Partials  Source Maps (`docs/partials/_source-maps.mdx`)

Cypress uses source maps to enhance the error experience. Stack traces are
translated so that your source files are shown instead of the generated file
that is loaded by the browser. This also enables displaying code frames. Without
inline source maps, you will not see code frames.

By default, Cypress will include an inline source map in your spec file, so you
will get the most out of the error experience. If you
[modify the preprocessor](/api/node-events/preprocessors-api#Usage), ensure that inline
source maps are enabled to get the same experience. Some examples of this include:

- With webpack and the
  [webpack preprocessor](https://github.com/cypress-io/cypress/tree/develop/npm/webpack-preprocessor), set
  [the `devtool` option](https://webpack.js.org/configuration/devtool/) to
  `inline-source-map`.
- With esbuild and the
  [esbuild preprocessor](https://github.com/bahmutov/cypress-esbuild-preprocessor/tree/main), set
  [the `sourcemap` option](https://esbuild.github.io/api/#sourcemap) to `inline` when
  [creating the bundler](https://github.com/bahmutov/cypress-esbuild-preprocessor#esbuild-options).
- With cucumber and the
  [cucumber preprocessor](https://github.com/badeball/cypress-cucumber-preprocessor/tree/master)
  third party bundlers are used to bundle the code.
  - For esbuild and the
    [esbuild preprocessor](https://github.com/bahmutov/cypress-esbuild-preprocessor/tree/main),
    set [the `sourcemap` option](https://esbuild.github.io/api/#sourcemap) to `inline` when
    [creating the bundler](https://github.com/bahmutov/cypress-esbuild-preprocessor#esbuild-options).
    Note: the cucumber preprocessor documentation for the esbuild bundler describes an experimental
    option: `prettySourceMaps`, but this option is buggy and setting source maps on the esbuild
    bundler directly works better.
  - The other bundlers all default their source maps appropriately.

If using [TypeScript](https://www.typescriptlang.org/) with any custom preprocessor, you will want to make sure that the [TypeScript](https://www.typescriptlang.org/)
compiler is generating source maps. This can be done by setting the [`sourceMap`](https://www.typescriptlang.org/tsconfig/#sourceMap) option in your
`tsconfig.json` to `true`. The [`inlineSourceMap`](https://www.typescriptlang.org/tsconfig/#inlineSourceMap) option is **not** recommended as it does not provide an accurate code frame.
See our recommended [tsconfig.json](/app/tooling/typescript-support#Configure-tsconfigjson) as a reference.

---

### Partials  Support File Configuration (`docs/partials/_support-file-configuration.mdx`)

A great place to put this configuration is in the
[supportFile](/app/core-concepts/writing-and-organizing-tests#Support-file),
since it is loaded before any test files are evaluated.

---

### Partials  Test Replay Info (`docs/partials/_test-replay-info.mdx`)

:::tip

<strong>Debugging Cypress Cloud Test Runs?</strong>

Don't rely on artifact representations or reproducing failing conditions locally. Replay the test as it executed during the recorded run with full debug capability using [<Logo src="/img/cloud/features/test-replay/replay-icon.svg" alt="Test Replay icon" /> Test Replay](/cloud/features/test-replay).

:::

---

### Partials  Then Should And Difference (`docs/partials/_then-should-and-difference.mdx`)

### What's the difference between `.then()` and `.should()`/`.and()`?

`.then()` hands the yielded subject to a callback function and should be used
when you need to manipulate some values or do some actions.

When using a callback function with `.should()` or `.and()`, on the other hand,
there is special logic to rerun the callback function until no assertions throw
within it. You should be careful of side effects in a `.should()` or `.and()`
callback function that you would not want performed multiple times.

---

### Partials  Ui Coverage Premium Note (`docs/partials/_ui-coverage-premium-note.mdx`)

:::note

<Icon useCypressIcon name="technology-ui-coverage" size="16" className="inline mt-[-2px]" /> **UI Coverage** turns your runs into a visual map of the interactive elements your tests exercise and the ones they miss, with no code changes or instrumentation. [Schedule a demo](<https://www.cypress.io/ui-coverage?utm_medium=premium-solution-tip&utm_source=docs.cypress.io&utm_content=Schedule a demo>).

:::

---

### Partials  Url Parts Diagram (`docs/partials/_url-parts-diagram.mdx`)

<DocsImage
  src="/img/api/url-parts-standard.svg"
  alt="Diagram of the URL https://example.com:8080/app/users?tab=1#section split into its parts: protocol is https:, hostname is example.com, port is 8080, host is example.com:8080, origin is https://example.com:8080, pathname is /app/users, search is ?tab=1, hash is #section, and href is the whole URL."
  noBorder
/>

In a hash-based route, a query string after the `#` is part of the hash:

<DocsImage
  src="/img/api/url-parts-hash-route.svg"
  alt="Diagram of the hash-based route https://example.com/app/#/users/1?tab=profile split into its parts: pathname is /app/ and hash is #/users/1?tab=profile. The question mark is inside the hash, so search is an empty string."
  noBorder
/>

---

### Partials  Url Allowlist (`docs/partials/_url_allowlist.mdx`)

If you are running the tests from within a restrictive VPN you will need to allow some URLs so that Cypress can have effective communication with Cypress Cloud.

**The URLs are the following:**

- `https://api.cypress.io` - **Cypress API**, **Studio**, **cy.prompt()**
- `https://assets.cypress.io` - **Asset CDN** (Org logos, icons, videos,
  screenshots, etc.)
- `https://authenticate.cypress.io` - **Authentication API**
- `https://capture.cypress.io` - **Cypress Test Replay**
- `https://s3.amazonaws.com/capture.cypress.io` - **Uploading Cypress Test Replay from Test Runner**
- `https://cloud.cypress.io` - **Cypress Cloud**, **Studio**
- `https://cloud-api.cypress.io` - **Cypress Cloud CLI** (`cy-cloud`)
- `https://docs.cypress.io` - **Cypress documentation**
- `https://download.cypress.io` - **CDN download of Cypress binary**
- `https://on.cypress.io` - **URL shortener for link redirects**

**If you have enabled Cloud MCP for your organization, you will want to allow it:**

- `https://mcp.cypress.io` - **Cypress Cloud MCP**

**If you are using GitHub Enterprise or GitLab for Enterprise (Self-managed), you may also need to add the following to the version control IP allowlist:**

- `3.211.102.119` - **Dedicated IP**
- `18.213.72.78` - **Dedicated IP**
- `35.169.145.173` - **Dedicated IP**
- `44.199.152.70` - **Dedicated IP**
- `52.70.95.89` - **Dedicated IP**

---

### Partials  Viewfilters Example Third Party (`docs/partials/_viewfilters-example-third-party.mdx`)

#### Config

```json title="App Quality Config"
{
  "viewFilters": [
    {
      "pattern": "https://app.okta.com/*",
      "include": false,
      "comment": "Exclude the Okta login flow"
    }
  ]
}
```

#### Visited URLs

```
https://app.okta.com/login
https://www.my-app.com/home
https://www.my-app.com/about
```

#### Views shown in UI

```
https://www.my-app.com/home
https://www.my-app.com/about
```

---

### Partials  Viewfilters Matching And Validation (`docs/partials/_viewfilters-matching-and-validation.mdx`)

Pattern matching follows [URL Pattern API](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API) semantics, with a few behaviors worth knowing:

- A pattern that omits the query string and hash matches URLs with any query string or hash. For example, `https://www.my-app.com/admin` matches `https://www.my-app.com/admin?tab=users`.
- Trailing slashes are optional by default: `https://www.my-app.com/admin` matches both `/admin` and `/admin/`. If your pattern ends with a `/`, only URLs with a trailing slash match it.
- A pattern without a protocol and hostname, such as `/admin/*`, matches that path on any protocol, hostname, and port. This is useful when tests run against multiple environments.
- A hostname must match exactly unless it contains a wildcard: `https://my-app.com/*` does not match `https://www.my-app.com/home`, but `https://*.my-app.com/*` does.
- The pattern `*` on its own matches every URL.

### Validation rules

Cypress Cloud rejects a configuration when:

- A rule is missing `pattern` or `include`.
- A `pattern` isn't valid URL Pattern syntax.
- Two rules have the same `pattern`. Duplicates can never both apply, because the first matching rule wins.
- A rule contains a property other than the three listed above.

---

### Partials  Viewfilters Options (`docs/partials/_viewfilters-options.mdx`)

### Options

| Option    | Required | Description                                                                                                                                                                                                                    |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `pattern` | Required | A URL pattern in [URL Pattern API](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API) syntax, matched against the full URL.                                                                                     |
| `include` | Required | Whether matching URLs are included (`true`) or excluded (`false`). There is no default; every rule must state it explicitly.                                                                                                   |
| `comment` | Optional | A note about why this rule exists, for your team's benefit. Comments have no effect on filtering and appear only where the configuration itself is shown: the App Quality configuration editor and a run's **Properties** tab. |

---

### Partials  Viewfilters Shared Examples (`docs/partials/_viewfilters-shared-examples.mdx`)

### Include only your application's URLs

An allowlist inverts the default. The first rule includes your application, and the catch-all `*` rule excludes everything else. Rules are applied in order, so the catch-all must come last.

#### Config

```json title="App Quality Config"
{
  "viewFilters": [
    {
      "pattern": "https://www.my-app.com/*",
      "include": true
    },
    {
      "pattern": "*",
      "include": false,
      "comment": "Exclude everything that isn't the app itself"
    }
  ]
}
```

#### Visited URLs

```
https://www.my-app.com/dashboards
https://www.my-app.com/dashboards/1
https://www.my-app.com/dashboards/2
https://auth.example.com/login
https://checkout.stripe.com/pay
```

#### Views shown in UI

```
/dashboards
/dashboards/*
```

The two numbered dashboard URLs group into a single `/dashboards/*` view through the automatic [view creation rules](/ui-coverage/core-concepts/views#How-views-are-created), which apply to included URLs as usual.

---

### Exclude error pages in every environment

Patterns without a protocol and hostname match on any environment your tests run against, whether that's `localhost`, a staging domain, or production.

#### Config

```json title="App Quality Config"
{
  "viewFilters": [
    {
      "pattern": "/404",
      "include": false
    },
    {
      "pattern": "/error/*",
      "include": false
    }
  ]
}
```

#### Visited URLs

```
http://localhost:3000/home
http://localhost:3000/404
https://staging.my-app.com/error/500
```

#### Views shown in UI

```
http://localhost:3000/home
```

---

### Partials  Viewfilters Syntax (`docs/partials/_viewfilters-syntax.mdx`)

## Syntax

```json title="App Quality Config"
{
  "viewFilters": [
    {
      "pattern": string,
      "include": boolean,
      "comment": string
    }
  ]
}
```

---

### Partials  Viewfilters Troubleshooting Validation Errors (`docs/partials/_viewfilters-troubleshooting-validation-errors.mdx`)

### Error: `Missing include boolean`

Every rule must set `include` explicitly; there is no default value. Add `"include": false` to exclude matching URLs, or `"include": true` to include them.

### Error: `No duplicate patterns allowed`

Each `pattern` in `viewFilters` must be unique. Because the first matching rule wins, a second rule with the same pattern can never apply; remove it or merge the two rules.

---

### Partials  Views (`docs/partials/_views.mdx`)

The `views` configuration groups the URLs your tests visit into views using URL patterns. Views are the distinct pages of your application that your reports are organized around. URLs that differ only by numeric IDs or UUIDs are grouped automatically (`/users/123` and `/users/456` become a single `/users/*` view), but other dynamic values are not: `/users/alice` and `/users/bob` appear as two separate views unless a `views` pattern groups them.

## Why use views?

- **Group dynamic URLs**: Combine URLs with dynamic values that the automatic rules don't recognize, such as usernames or slugs, into a single view.
- **Split views by query parameters**: By default, query strings are ignored when views are created, so `/home?status=done` and `/home?status=new` group into a single `/home` view. A pattern that captures a query parameter lets you report on them separately.
- **Create distinct view groups**: Use `groupBy` to create a separate view for each value of a meaningful URL parameter, while still grouping the parts that are dynamic.
- **Consolidate environments**: Patterns can span subdomains, or omit the protocol and hostname entirely, so the same page visited on different environments rolls up into one view.

## Scope

:::info

**Note:** setting `views` impacts both Accessibility and UI Coverage reports.
It is defined at the root of your configuration and, unlike `viewFilters` and
`elementFilters`, it cannot be nested under an `accessibility` or `uiCoverage`
key to configure each product separately.

:::

The `views` configuration applies to URLs visited in end-to-end tests. Views for component tests are created from the path of the spec file, and are not affected by this configuration.

## Syntax

```json title="App Quality Config"
{
  "views": [
    {
      "pattern": string,
      "groupBy": string | [string],
      "comment": string
    }
  ]
}
```

A view can also be defined as just a pattern string when no other options are needed:

```json title="App Quality Config"
{
  "views": ["https://www.my-app.com/users/*"]
}
```

### Options

| Option    | Required | Default | Description                                                                                                                                                                                                                                          |
| --------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pattern` | Required |         | A URL pattern to group matching URLs into a single view. Uses [URL Pattern API](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API) syntax.                                                                                            |
| `groupBy` | Optional |         | One or more named parameters from the pattern that should create separate views. Accepts a single string or an array of strings. Each name must appear in `pattern` as a named parameter (for example, `:type`), in the path, query string, or hash. |
| `comment` | Optional |         | A description of the purpose of this view configuration. Has no effect on behavior.                                                                                                                                                                  |

## How are URLs matched to views?

- Patterns are evaluated in the order they are defined, and each URL is grouped into the view of the first pattern it matches. A URL only ever belongs to one view.
- URLs that don't match any pattern are grouped by the [automatic view grouping rules](/ui-coverage/core-concepts/views#How-views-are-created), where possible.
- A pattern that doesn't match any URLs in the run does not appear in the report.
- URLs excluded by a `viewFilters` rule are excluded before `views` patterns are applied. A `views` pattern cannot bring an excluded URL back into the report.

Pattern matching follows [URL Pattern API](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API) semantics, with a few behaviors worth knowing:

- A pattern that omits the query string and hash matches URLs with any query string or hash. For example, `https://www.my-app.com/users/*` matches `https://www.my-app.com/users/bob#settings`.
- Trailing slashes are optional by default: `/users/bob` and `/users/bob/` both match a pattern ending in `/users/:name`. If your pattern ends with a `/`, only URLs with a trailing slash match it.
- A pattern without a protocol and hostname, such as `/users/*`, matches that path on any protocol, hostname, and port.

## Using groupBy

The `groupBy` property creates distinct views based on named parameters in your URL pattern. For example, if your pattern is `/analytics/:type/:id`, using `groupBy: ["type"]` creates a separate view for each unique value of `type` (like `/analytics/performance/:id` and `/analytics/usage/:id`).

This is particularly useful when:

- Different parameter values represent distinct functional areas
- You want to track coverage separately for different categories of content
- URL parameters determine significant UI changes

URLs with the same values for the specified parameters are grouped together, while different values create distinct views. Values can be captured from named parameters in the path, the query string, or the hash of the pattern.

## How views are named

A view created from your configuration is named by the pattern you wrote. When `groupBy` is used, the grouped parameters are replaced with their matched values, and any remaining named parameters and wildcards stay in the name, as the examples below show.

When every view in a report shares the same protocol and hostname, view names are displayed without them. The examples below show the names as they appear in this most common case.

## Examples

### Grouping dynamic path parameters

#### Config

```json title="App Quality Config"
{
  "views": [
    {
      "pattern": "https://www.my-app.com/users/*"
    }
  ]
}
```

#### Visited URLs

```
https://www.my-app.com/users/alice
https://www.my-app.com/users/bob
https://www.my-app.com/users/bob#settings
https://www.my-app.com/users?assigned=true
```

#### Views shown in UI

```
/users/*
/users
```

The first three URLs match the pattern and group into `/users/*`. The last URL doesn't match (its path is `/users`, not `/users/` followed by more), so the automatic grouping rules create a `/users` view for it, with its query string ignored.

---

### Grouping with a named path parameter

A named parameter like `:name` matches a single path segment, just like `*`, but keeps a readable placeholder in the view name and can be referenced by `groupBy`.

#### Config

```json title="App Quality Config"
{
  "views": [
    {
      "pattern": "https://www.my-app.com/users/:name"
    }
  ]
}
```

#### Visited URLs

```
https://www.my-app.com/users/alice
https://www.my-app.com/users/bob
https://www.my-app.com/users/bob#settings
https://www.my-app.com/users?assigned=true
```

#### Views shown in UI

```
/users/:name
/users
```

---

### Grouping by a path parameter

#### Config

```json title="App Quality Config"
{
  "views": [
    {
      "pattern": "https://www.my-app.com/analytics/:type/:id",
      "groupBy": ["type"]
    }
  ]
}
```

#### Visited URLs

```
https://www.my-app.com/analytics/performance/amara
https://www.my-app.com/analytics/performance/harper
https://www.my-app.com/analytics/usage/amara
https://www.my-app.com/analytics/usage/harper
```

#### Views shown in UI

```
/analytics/performance/:id
/analytics/usage/:id
```

---

### Grouping by a query parameter

The `?*status=:status{&*}?` syntax captures the `status` query parameter wherever it appears in the query string, regardless of what other parameters surround it, and `#*` allows any hash.

#### Config

```json title="App Quality Config"
{
  "views": [
    {
      "pattern": "https://www.my-app.com/home?*status=:status{&*}?#*",
      "groupBy": ["status"]
    }
  ]
}
```

#### Visited URLs

```
https://www.my-app.com/home?page=1&status=done
https://www.my-app.com/home?status=done&group=2
https://www.my-app.com/home?tag=trip&status=new&group=4
https://www.my-app.com/home?tag=trip&status=new#statusView
```

#### Views shown in UI

```
/home?*status=done{&*}?
/home?*status=new{&*}?
```

View names keep the query string portion of the pattern as you wrote it, with the grouped parameter replaced by its matched values.

---

### Grouping URLs across subdomains

Each unique value of `:path*` creates a view, and the same path visited on different subdomains is grouped into a single view. All of the views share the `*.my-app.com` hostname pattern, so it is omitted from the view names.

#### Config

```json title="App Quality Config"
{
  "views": [
    {
      "pattern": "https://*.my-app.com/:path*",
      "groupBy": ["path"]
    }
  ]
}
```

#### Visited URLs

```
https://staging1.my-app.com/home
https://staging2.my-app.com/home
https://www.my-app.com/home
https://staging1.my-app.com/profile
https://www.my-app.com/profile/edit
```

#### Views shown in UI

```
/home
/profile
/profile/edit
```

## Troubleshooting

### A pattern you configured doesn't appear in the report

A pattern that doesn't match any URLs in the run is dropped from the report. Confirm that the pattern matches the full URL, including the protocol and hostname, or omit them so the pattern matches any origin. Also check that a `viewFilters` rule isn't excluding the URLs before `views` patterns are applied.

### Error: `Value "..." was not found in the pattern`

Each name in `groupBy` must appear in `pattern` as a named parameter. For example, `groupBy: ["type"]` requires `:type` somewhere in the pattern's path, query string, or hash.

### Error: `No duplicate values allowed - "..." was added multiple times`

Each pattern in `views` must be unique. Named parameters are compared as wildcards, so `/users/:name` and `/users/*` count as the same pattern and trigger this error.

---

### Partials  Warning Setup Node Events (`docs/partials/_warning-setup-node-events.mdx`)

:::caution

⚠️ This code is part of the
[setupNodeEvents](/app/plugins/plugins-guide#Using-a-plugin) function and
thus executes in the Node environment. You cannot call `Cypress` or `cy`
commands in this function, but you do have the direct access to the file system
and the rest of the operating system.

:::

---

### Ui Coverage Changelog (`docs/ui-coverage/changelog.mdx`)

---
title: 'Changelog: UI Coverage'
description: 'Track new features, improvements, and bug fixes for Cypress UI Coverage, including configuration options, CI integrations, and Results API updates.'
sidebar_label: Changelog
sidebar_position: 200
---

<ProductHeading product="ui-coverage" />

# Changelog

## Week of May 18, 2026

- **UI Coverage in Enterprise Reporting:** UI Coverage trends are now available in the [Enterprise Reporting](/cloud/features/analytics/enterprise-reporting#UI-Coverage) area of Cypress Cloud, so you can track coverage scores across all projects and runs and see when they improve or drift over time. See the [Monitor Changes](/ui-coverage/guides/monitor-changes) guide for details.

## Week of Apr 27, 2026

- **UI Coverage in Cypress Cloud MCP:** AI agents can now query UI Coverage for a run through the [Cypress Cloud MCP server](/cloud/integrations/cloud-mcp), using three new tools:
  - `cypress_get_ui_coverage_report`: Returns a run's overall coverage score, tested and untested element and link counts, and the riskiest views.
  - `cypress_get_ui_coverage_views`: Browses all of the views in a run beyond the riskiest ones in the report.
  - `cypress_get_ui_coverage_elements`: Drills down into individual elements, with filtering by tested or untested status and by view.

  The `cypress_get_runs` tool now also reports each run's UI Coverage score. See [working with AI agents](/ui-coverage/work-with-ai-agents) for example prompts and setup.

## Week of Feb 06, 2026

- **Buildkite support for the Results API:** You can now fetch UI Coverage results from Buildkite CI using the [Results API](/ui-coverage/results-api).

## Week of Jan 16, 2026

- **Bitbucket support for the Results API:** You can now fetch UI Coverage results from Bitbucket CI using the [Results API](/ui-coverage/results-api).

## Week of Dec 19, 2025

- **Document scoping for nested contexts (`documentScope`):** The `elementFilters`, `elements`, `elementGroups`, and `allowedInteractionCommands` configuration properties now accept an optional `documentScope` field that scopes selectors to specific document hosts, such as iframes or shadow DOM hosts. This lets you filter, identify, group, or restrict interactions for elements inside nested document contexts without changing your application's DOM. Chain multiple hosts in the array to target elements within nested documents, such as an iframe that contains a shadow DOM component. See the [Element Filters](/ui-coverage/configuration/elementfilters), [Elements](/ui-coverage/configuration/elements), [Element Groups](/ui-coverage/configuration/elementgroups), and [Allowed Interaction Commands](/ui-coverage/configuration/allowedinteractioncommands) documentation for details and examples.

## Week of Dec 12, 2025

- **Per-run configuration with `profiles`:** The `profiles` configuration property lets you apply different configuration settings to different runs based on [run tags](/app/references/command-line#cypress-run-tag-lt-tag-gt). Use it to customize UI Coverage behavior for specific environments, branches, or test scenarios. See the [Profiles](/ui-coverage/configuration/profiles) guide for details.
- **Inline configuration comments:** All configuration objects now support an optional `comment` property for documenting why a value is set. Comments make your configuration easier to understand and maintain, especially across teams or when revisiting it later.
- **Guide: block pull requests and set policies:** A new guide on [blocking pull requests and setting policies](/ui-coverage/guides/block-pull-requests) shows how to use the Results API to enforce coverage standards, compare results against baselines, and automatically block pull requests when coverage thresholds are not met.

## Week of Jun 23, 2025

- **Custom interaction commands:** UI Coverage now lets you define custom commands that count toward coverage scores, restrict which kinds of interactions are allowed for certain elements, and include assertions in coverage calculations. See the new configuration properties:
  - [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands)
  - [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands)

## Week of Jun 02, 2025

- **Drone CI support for the Results API:** You can now fetch UI Coverage results from Drone CI using the [Results API](/ui-coverage/results-api).

## Week of May 26, 2025

- **AI-powered Test Generation:** We launched Test Generation in Cypress Cloud to help you quickly add tests for the untested elements found in UI Coverage reports, following your existing practices and conventions. Read about [adding your missing tests faster with Test Generation](https://www.cypress.io/blog/add-your-missing-tests-faster-with-test-generation-in-ui-coverage?utm_source=docs.cypress.io&utm_medium=ui-coverage-changelog) for details.

## Week of May 12, 2025

- **AWS CodeBuild support for the Results API:** You can now fetch UI Coverage results from AWS CodeBuild using the [Results API](/ui-coverage/results-api).

## Week of Apr 14, 2025

- **Shadow DOM and iframe support:** UI Coverage can now report on interactions inside Shadow DOM and iframes. Both are off by default. Contact your Cypress representative to opt in.

## Week of Mar 24, 2025

- **UI Coverage in the Data Extract API:** UI Coverage results are now available through the [Data Extract API](/cloud/integrations/data-extract-api), so you can retrieve and analyze your coverage data over time.

## Week of Jan 15, 2025

- **Branch Review integration (Beta):** UI Coverage comparisons are now available in Branch Review, so teams can see how code changes affect test coverage across branches. Comparisons work for all Git providers and support manual run selection for customized comparisons.

## Week of Dec 16, 2024

- **URL handling:** Fixed issues with URLs containing special characters, such as parentheses, that could break view generation.
- **Performance improvements:** Optimized rendering performance for reports that contain large numbers of elements and snapshots.

## Week of Oct 07, 2024

- **Improved table grouping:** The default grouping rules now identify and group elements in tables more accurately.

## Week of Sep 30, 2024

- **Slack messages:** UI Coverage results now appear in Slack messages alongside test results. See our [Slack integration](/cloud/integrations/slack) for setup details.

## Week of Sep 23, 2024

- **Improved link display logic:** Links now display more consistently across reports, matching your defined views more closely.

## Week of Sep 09, 2024

- **Element tooltips:** UI Coverage now shows tooltips for elements that emphasize their selectors, making it easier to navigate coverage reports and identify elements.

## Week of Aug 19, 2024

- **Results API:** The new [Results API](/ui-coverage/results-api) lets you programmatically fetch a run's UI Coverage results in a CI environment. You can act on the results within CI to determine whether they are acceptable or need to be addressed before code changes can merge.
- **Pull and merge request comments:** UI Coverage results now appear in [GitHub](/cloud/integrations/github), [GitLab](/cloud/integrations/gitlab), and [Bitbucket](/cloud/integrations/bitbucket) pull request and merge request comments alongside test results. Install integrations and enable comments in Project Settings.

## Week of Aug 12, 2024

- **Improved `attributeFilters` behavior:** When matching against class attributes, the [`attributeFilters`](/ui-coverage/configuration/attributefilters) configuration option now targets and filters individual class names rather than the entire `class` attribute value.

## Week of Aug 05, 2024

- **View untested elements:** You can now quickly access all untested elements across all views in the "Untested elements" section. Save time and improve your coverage by testing these areas of your application, or use [`elementFilters`](/ui-coverage/configuration/elementfilters) in your UI Coverage [configuration](/ui-coverage/configuration/overview) to ignore certain elements.
- **View tested elements:** You can now quickly access all tested elements across all views in the "Tested elements" section. Spot potentially redundant coverage by reviewing the elements with the highest numbers of interactions and tests.

## Week of Jul 22, 2024

- **View untested links:** You can now quickly access all untested links across all views in the "Untested links" section. Save time and improve your coverage by testing these areas of your application, or use [`viewFilters`](/ui-coverage/configuration/viewfilters) in your UI Coverage [configuration](/ui-coverage/configuration/overview) to ignore certain links.

## Week of Jun 24, 2024

- **View configuration information for each run:** The properties tab now shows the configuration set for the project at the start of the run. This helps you understand what might be driving a score change and distinguishes configuration changes from other factors, such as changes to your application, tests, and Cypress versions. See [viewing configuration for a run](/accessibility/configuration/overview#Viewing-Configuration-for-a-Run).
- **Anchor elements considered interactive:** Anchor elements (`a` tags) are now considered interactive even when they do not have an `href` attribute.

## Week of May 20, 2024

- **Manage configuration in Project Settings:** Owners and admins can now configure what should be tested or ignored in score calculations using an editor within Project Settings, so your team captures what's relevant to your testing strategy:
  - `elementFilters`: Exclude specific elements by CSS selector.
  - `views`: Define URL patterns for grouping in the UI.
  - `viewFilters`: Exclude groups of URLs from reports.
  - `attributeFilters`: Determine which attributes are used for identifying and grouping elements.
  - `elementGroups`: Create custom rules for grouping elements to reduce noise in scores.
  - `significantAttributes`: Prioritize custom attributes over defaults for element identification and grouping.

## Week of Mar 25, 2024

- **Project-level configuration options:** UI Coverage now supports project-level configuration, so you can customize UI Coverage settings without updating your HTML. Exclude specific URLs and elements by selector, and group elements to simplify coverage analysis. For configuration assistance, contact your Account Executive.

## Week of Mar 04, 2024

- **Element interaction details:** UI Coverage now provides detailed insights into the testing status of every interactive element, including interaction types, frequency, and location within the UI. A new tracking system shows where each element has been identified and tested, and link details indicate visit frequency.

## Week of Feb 26, 2024

- **Element grouping improvements:** The `data-cy-ui-group` attribute now supports "cascade" behavior, so you can place it on a wrapper or parent element to pass grouping values down to child interactive elements.
- **Text filter:** You can now filter the "Views" list by name, making it easier to search UI Coverage reports.

## Week of Dec 31, 2023

- **URL grouping:** UI Coverage reports now intelligently group repeated URLs to reduce duplicate views. This simplifies reports and makes it easier to identify and prioritize issues.

---

### Ui Coverage Faq (`docs/ui-coverage/faq.mdx`)

---
title: 'Cypress UI Coverage FAQ'
description: 'Answers to common questions about Cypress UI Coverage: how it differs from code coverage, coverage scores, closing gaps, configuration, and the Results API.'
sidebar_label: FAQ
sidebar_position: 160
---

<ProductHeading product="ui-coverage" />

# Cypress UI Coverage FAQ

<UICovPremiumNote />

## General

### <Icon name="angle-right" /> What is UI Coverage?

[UI Coverage](/ui-coverage/get-started/introduction) is a Cypress Cloud feature that shows you which interactive elements of your application your tests actually exercise. Every recorded run produces a visual report of tested and untested elements across all of your application's [views](/ui-coverage/core-concepts/views), along with a coverage score you can track over time.

### <Icon name="angle-right" /> Do I need to install anything to use UI Coverage?

No. UI Coverage requires no code changes or instrumentation. Reports are generated from [Test Replay](/cloud/features/test-replay) data, so any run recorded to Cypress Cloud with Test Replay on Cypress v13 or later is ready to use. See [setup](/ui-coverage/get-started/setup) for details.

### <Icon name="angle-right" /> How is the UI Coverage score calculated?

The Cypress UI Coverage score compares the number of tested interactive elements to the total number of interactive elements in your application. Three rules determine what goes into that comparison:

- **[Grouped elements](/ui-coverage/core-concepts/element-grouping) count as a single unit.** The group counts once toward the total, and an interaction with any element in the group marks the whole group as tested.
- **Links share the same total.** Each distinct link destination counts as one unit, and counts as tested when a test either interacts with the link or visits its destination.
- **Only [visible](/ui-coverage/core-concepts/interactivity#Visibility) elements count.** An element that was never visible in any snapshot is excluded from both the tested and total counts, so it neither raises nor lowers your score.

### <Icon name="angle-right" /> How do I get started with UI Coverage?

Record a run to Cypress Cloud with [Test Replay](/cloud/features/test-replay) enabled on Cypress v13 or later, then open its **UI Coverage** tab. A report is generated automatically for every recorded run, with no code changes, plugin, or instrumentation. From there you can read your coverage score, drill into your lowest-scoring [views](/ui-coverage/core-concepts/views), and optionally tune the report with [App Quality configuration](/ui-coverage/configuration/overview). The [Get Started guide](/ui-coverage/get-started/setup) walks through the whole path.

### <Icon name="angle-right" /> What do I need to use UI Coverage?

Three things: a Cypress project recording to [Cypress Cloud](/cloud/get-started/introduction), [Test Replay](/cloud/features/test-replay) enabled for the run (reports are built entirely from Test Replay data), and Cypress v13 or later. UI Coverage isn't included in standard Cloud plans, so you'll also need it enabled for your organization, which you can do with a [free trial](/ui-coverage/get-started/setup#Step-1-Start-your-UI-Coverage-trial). No test changes, plugins, or code instrumentation are required.

### <Icon name="angle-right" /> Is UI Coverage included in my Cypress Cloud plan?

UI Coverage isn't part of the standard Cypress Cloud plans; it's enabled separately for your organization. You can turn it on for your projects with a [free trial](/ui-coverage/get-started/setup#Step-1-Start-your-UI-Coverage-trial), which uses your existing recorded runs so you can see your coverage gaps before committing. To find out what's available for your account, start a trial or talk to your Cypress point-of-contact.

### <Icon name="angle-right" /> How soon after a run can I see its UI Coverage report?

The report is generated in Cypress Cloud after the run finishes recording, so it's ready shortly after your run completes rather than during the run itself. Nothing in your Cypress pipeline waits on or fails because of UI Coverage; open the run's **UI Coverage** tab once processing finishes to read it.

### <Icon name="angle-right" /> Does UI Coverage work with Cypress component testing?

Yes. UI Coverage reports on both end-to-end and component runs. In component testing, each spec file becomes a single [view](/ui-coverage/core-concepts/views) named by the spec's file path, and every component mounted in that spec is grouped into it. Everything else, including the coverage score, untested elements, and configuration, works the same way as it does for end-to-end runs.

### <Icon name="angle-right" /> Is UI Coverage the same as code coverage?

No. Code coverage measures which lines, branches, or functions of your source code ran during a test. UI Coverage measures your application the way a user meets it: the share of _interactive elements_ (buttons, inputs, links, and controls) your tests actually exercised. The two answer different questions. A line of code can back many controls, and simply importing a module can mark it "covered" without a user ever touching the interface, so high code coverage can still hide untested buttons and pages. UI Coverage closes that gap by reporting on the rendered DOM, and it needs no instrumentation or build tooling to do it. The two are complementary, and many teams track both.

### <Icon name="angle-right" /> Does UI Coverage affect how my tests run or slow them down?

No. UI Coverage adds nothing to test execution. Reports are generated in Cypress Cloud _after_ a run finishes recording, from the [Test Replay](/cloud/features/test-replay) data your run already captured, so there's no extra work during the run and nothing in your Cypress pipeline waits on or fails because of UI Coverage.

### <Icon name="angle-right" /> Does UI Coverage work with my framework, and do I have to change my code?

Yes, and no. UI Coverage analyzes the rendered DOM captured by [Test Replay](/cloud/features/test-replay), not your source code, so it's framework-agnostic. React, Vue, Angular, Svelte, server-rendered HTML, or anything else that produces a DOM works the same way. You don't change your application code, add a plugin, or write any configuration to get a report; configuration is opt-in and comes later, only when you want to sharpen the results.

### <Icon name="angle-right" /> What's the difference between UI Coverage and Cypress Accessibility?

Both are Cypress Cloud [App Quality](/ui-coverage/configuration/overview) features built on the same [Test Replay](/cloud/features/test-replay) data, and both need no code changes. They measure different things: UI Coverage tells you _how much_ of your interactive UI your tests exercise (a coverage score plus untested elements and links), while [Cypress Accessibility](/accessibility/get-started/introduction) tells you _whether_ the UI your tests render has accessibility violations. They share configuration properties like [`viewFilters`](/ui-coverage/configuration/viewfilters) and [`elementFilters`](/ui-coverage/configuration/elementfilters), which you can scope to one product or the other. See [Configuration scope](/ui-coverage/configuration/overview#Configuration-scope).

### <Icon name="angle-right" /> Can I use UI Coverage with AI agents?

Yes. Because every report is structured data about which interactive elements your tests exercised, a compatible AI agent can read it and act on it through the [Cypress Cloud MCP](/cloud/integrations/cloud-mcp). An agent can pull a run's coverage score and untested elements, summarize the biggest gaps, correlate a coverage drop with specific specs, and draft targeted tests to close the gaps, while your team keeps ownership of what "enough coverage" means for each area. See [Use AI agents with UI Coverage](/ui-coverage/work-with-ai-agents) for example prompts and how to tune reports for clearer agent signal.

## Finding coverage gaps

### <Icon name="angle-right" /> How do I find which parts of my UI aren't tested?

Record a run to Cypress Cloud with [Test Replay](/cloud/features/test-replay) enabled, then open its **UI Coverage** tab. Every recorded run produces a report automatically, with no code changes. The report ranks your application's [views](/ui-coverage/core-concepts/views) by coverage score, lists the untested interactive elements on each one, and flags the pages your tests never visited as [untested links](/ui-coverage/core-concepts/interactivity#Untested-Links). The [Identify coverage gaps](/ui-coverage/guides/identify-coverage-gaps) guide walks through the full workflow step by step.

### <Icon name="angle-right" /> Where should I start if my UI Coverage score is low?

In Cypress Cloud, start with your lowest-scoring [views](/ui-coverage/core-concepts/views), weighed against how critical each one is to your users, since a checkout or signup view at 40% is more urgent than a settings page at the same score. Before writing tests, rule out noise: third-party widgets counted as untested elements (exclude them with [`elementFilters`](/ui-coverage/configuration/elementfilters)) and links to pages you'll never test (exclude them with [`viewFilters`](/ui-coverage/configuration/viewfilters)) both lower a score without pointing to a real gap. See [Why is my UI Coverage score lower than I expect?](#Why-is-my-UI-Coverage-score-lower-than-I-expect) and [Identify coverage gaps](/ui-coverage/guides/identify-coverage-gaps).

### <Icon name="angle-right" /> In Cypress UI Coverage, what's the difference between an untested element, an untested link, and an untested view?

They describe three different gaps. An **untested element** is an interactive element (a button, input, or control) on a page your tests opened that no recognized command interacted with. An **untested link** is an `<a>` element whose destination URL was never visited during the run. An **untested view** is a page discovered from those untested links that no test ever opened, so it has no coverage at all. Untested elements and untested links both count against your score; untested views surface pages that need a test to reach them. See [Interactivity](/ui-coverage/core-concepts/interactivity#Untested-Links) and [Views](/ui-coverage/core-concepts/views).

### <Icon name="angle-right" /> How do I find pages my tests never visit?

Use the **Untested links** section of the UI Coverage report. It lists links whose destinations your Cypress tests never opened during the run, and expanding one shows a **Referrers** tab (the views that link to the page) and a **URLs** tab (the concrete destinations, grouped for dynamic routes like `/orders/*`). Because a page with no view can still be linked from a tested page, this is how UI Coverage surfaces flows your suite is missing entirely. Add navigation to reach them, as shown in [Address coverage gaps](/ui-coverage/guides/address-coverage-gaps#Cover-untested-links).

## Closing coverage gaps

### <Icon name="angle-right" /> How do I close a coverage gap in Cypress UI Coverage?

Add a test that exercises the untested element the report surfaces. First [confirm each gap is worth testing](/ui-coverage/guides/address-coverage-gaps#Step-1-Confirm-the-gap-is-real), starting with the ones that carry the most risk, such as controls on your checkout or login views, then close each one either with [Test Generation](#What-is-Test-Generation-in-Cypress-UI-Coverage) or by writing a targeted test yourself. An element moves from untested to tested once a [recognized interaction command](/ui-coverage/core-concepts/interactivity#Interaction-Commands) targets it. See [Address coverage gaps](/ui-coverage/guides/address-coverage-gaps) for the full workflow.

### <Icon name="angle-right" /> What is Test Generation in Cypress UI Coverage? {#What-is-Test-Generation-in-Cypress-UI-Coverage}

Test Generation uses AI to draft a Cypress test for an untested interactive element, following the setup and conventions your existing specs already use. Select an untested element in the report, click **Generate test code**, and choose a spec from the list of specs where that element appears. Cypress generates a test that reproduces the setup to reach the element (reusing your custom commands), performs an appropriate interaction, and leaves a `TODO` marking where to add your assertions. Treat it as a reviewed starting point, then add the assertions that prove the flow works. See [Generate tests from UI Coverage reports](/ui-coverage/guides/address-coverage-gaps#Generate-tests-from-UI-Coverage-reports).

### <Icon name="angle-right" /> Can Cypress UI Coverage write tests for me?

Yes, through [Test Generation](#What-is-Test-Generation-in-Cypress-UI-Coverage). It produces a working test that exercises the untested element so UI Coverage counts it, built from the same patterns and custom commands your existing specs use. It's a starting point rather than a finished test: you copy the snippet into the suggested spec and add the assertions that verify behavior. Test Generation is part of UI Coverage and isn't available on standard Cloud plans; it also requires a report processed on or after November 21, 2024, project membership, and that AI capabilities are enabled for your organization.

### <Icon name="angle-right" /> How do I test a page that my Cypress suite never visits?

Add navigation to the page so it renders during a run. Pages your tests link to but never visit appear in the [**Untested links**](/ui-coverage/core-concepts/interactivity#Untested-Links) section, and UI Coverage can't report on any element they contain until a test goes there. Add a `cy.visit()` (or a click that navigates to it), which turns the untested link green and creates a [view](/ui-coverage/core-concepts/views) for the page that then surfaces its own untested elements. Test Generation doesn't apply to untested links; it targets interactive elements, so navigation is the fix here.

### <Icon name="angle-right" /> How do I cover an element that only appears after login or a click?

Drive the interaction that puts the UI into that state before interacting with the element. A control inside a collapsed menu, a modal, or a section that only renders after signing in won't be exercised until your test reveals it, so click the toggle or run your `cy.login()` command first, then interact with the now-visible element. Each new state your tests reach adds its snapshot to the Cypress UI Coverage report, so previously hidden elements start appearing as tested.

### <Icon name="angle-right" /> Which coverage gaps should I fix first in Cypress UI Coverage?

Prioritize by risk, not by count. Start with the views behind your highest-value flows (checkout, login, account settings), then untested links, which often hide an entire flow rather than a single control, and weight the list by real usage so a heavily used page with low coverage is closed before a lightly used one. See [Confirm the gap is real](/ui-coverage/guides/address-coverage-gaps#Step-1-Confirm-the-gap-is-real) and [Start with your lowest-scoring views](/ui-coverage/guides/identify-coverage-gaps#Step-3-Start-with-your-lowest-scoring-views).

### <Icon name="angle-right" /> Why did closing one coverage gap reveal more untested elements?

Because visiting a page or reaching a new state exposes controls Cypress UI Coverage had never seen. When a test navigates to a previously [untested link](/ui-coverage/core-concepts/interactivity#Untested-Links), UI Coverage creates a [view](/ui-coverage/core-concepts/views) for that page and lists every interactive element on it, most of which start untested. This is expected, and it's why closing gaps is a loop: each pass surfaces the next set of elements to prioritize.

## Comparing reports across runs

### <Icon name="angle-right" /> How do I compare UI Coverage reports between two runs?

You have two routes. In [Branch Review](/cloud/features/branch-review) in Cypress Cloud, pick a **base run** and a **changed run** from the dropdowns (or let Cypress select them automatically when the changed run is tied to a pull request) and it shows only what changed between them: the elements and pages that became untested, the gaps the change closed, and everything new it added. If you'd rather stay in your editor, the [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) lets an AI agent pull both runs' coverage and report the diff for you. Both compare any two runs already recorded to Cypress Cloud. See [Compare reports](/ui-coverage/guides/compare-reports) for the full workflow with each.

### <Icon name="angle-right" /> What's the difference between the base run and the changed run in Branch Review?

The **changed run** is the focal point of the comparison, so everything you see, including every count and drilldown, is data from the changed run. The **base run** is the reference it's measured against. In a pull request, the changed run is your feature branch and the base run is the branch you're merging into, so the diff shows exactly what your change did to coverage.

### <Icon name="angle-right" /> How do I tell whether a pull request reduced my UI Coverage?

Open the pull request's run in [Branch Review](/cloud/features/branch-review) and read the coverage-score change at the top: it's labeled a **coverage improvement** when the score rose and a **reduction in coverage** when it fell. A reduction points you to the **New untested elements** and **New untested links** sections, which list the specific controls and pages the change left untested. You can also ask an AI agent to report the same diff from your editor with the [Cypress Cloud MCP](/cloud/integrations/cloud-mcp). See [Compare reports](/ui-coverage/guides/compare-reports) and [Block pull requests](/ui-coverage/guides/block-pull-requests) to fail CI automatically when coverage drops.

### <Icon name="angle-right" /> What's the difference between a new untested element and a resolved untested element in UI Coverage?

A **new untested element** is untested in the changed run and was either tested in the base run or didn't exist there, so it represents coverage that regressed. A **resolved untested element** was untested in the base run and is now tested, so it's proof a gap was closed. Branch Review shows both, along with a link to the elements untested in both runs. Untested links are broken out the same way. A new untested element appears either because the test code stopped interacting with it, or because an application change added it without a test. See [Compare reports](/ui-coverage/guides/compare-reports#Step-3-Review-new-untested-elements-and-links).

### <Icon name="angle-right" /> Why does a page or element appear as "new" when I compare two UI Coverage runs?

Usually because a dynamic value in the URL or an element attribute isn't being matched consistently across runs. A URL slug that isn't grouped into a stable [view](/ui-coverage/core-concepts/views) can appear as a new page, and an identifier carrying a per-build hash can make one element show as both resolved and new. Group dynamic URLs with [`views`](/ui-coverage/configuration/views) and exclude unstable identifiers with [`attributeFilters`](/ui-coverage/configuration/attributefilters), then regenerate the run. See [Stabilize the comparison](/ui-coverage/guides/compare-reports#Step-6-Stabilize-the-comparison-with-configuration).

### <Icon name="angle-right" /> How do I get an accurate Cypress UI Coverage comparison between two runs?

For an accurate Cypress UI Coverage comparison, compare passing runs that ran similar tests on the same content, so each run visited roughly the same pages and completed the same workflows; then any difference in the diff reflects the change in the newer run. This is what you get out of the box when comparing a pull-request branch against its base. Comparing runs from different points in time is still valid, as long as you account for the other sources of difference as you read the results. To see unified changes for your whole suite, group all of a commit's tests under a single Cypress run per report. This guidance applies whether you compare in Branch Review or with the [Cypress Cloud MCP](/cloud/integrations/cloud-mcp), since both read the same recorded runs. See [Compare reports](/ui-coverage/guides/compare-reports) and [Branch Review best practices](/cloud/features/branch-review#Best-Practices).

### <Icon name="angle-right" /> Do I need to rerun my tests to compare two UI Coverage reports?

No. Branch Review compares two runs that are already recorded to Cypress Cloud, so any two recorded runs can be compared without re-running anything. The same is true when comparing with the [Cypress Cloud MCP](/cloud/integrations/cloud-mcp), which reads those same recorded runs. If you only changed configuration and want to compare the effect, regenerate a past run from its **Properties** tab instead of recording again. See [Compare reports](/ui-coverage/guides/compare-reports).

### <Icon name="angle-right" /> Can I compare UI Coverage reports with an AI agent or the Cypress Cloud MCP?

Yes. The [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) lets a compatible AI agent pull the UI Coverage for two runs and report the diff from your editor, using `cypress_get_runs` to find the runs and `cypress_get_ui_coverage_report`, `cypress_get_ui_coverage_views`, and `cypress_get_ui_coverage_elements` to read each run's coverage. There's no single compare tool; the agent assembles the diff and can then draft a test to close a regression. It's a peer to Branch Review, which remains the place to see full-page DOM snapshots of what changed. See [Compare reports with the Cypress Cloud MCP](/ui-coverage/guides/compare-reports#Compare-reports-with-the-Cypress-Cloud-MCP).

## Monitoring coverage over time

### <Icon name="angle-right" /> How do I track my UI Coverage score over time?

Record runs on a regular cadence so there's always something to compare, then watch the direction the score moves rather than a single number. Record a run for every pull request to catch regressions before they merge, and add a scheduled job (such as a nightly CI cron) that records against a stable environment for a consistent baseline that isn't affected by which files a given pull request touched. From there, [Branch Review](/cloud/features/branch-review) diffs any two runs and the [Results API](/ui-coverage/results-api) enforces the trend in CI. See [Monitor changes](/ui-coverage/guides/monitor-changes) for the full workflow.

### <Icon name="angle-right" /> How do I get notified when my UI Coverage changes?

Connect [Slack](/cloud/integrations/slack) or [Microsoft Teams](/cloud/integrations/microsoft-teams) to your project so your team is alerted whenever a run finishes, with Slack surfacing UI Coverage results directly. To put the change in front of reviewers, connect a version control integration ([GitHub](/cloud/integrations/github#Pull-request-comments), [GitLab](/cloud/integrations/gitlab#Merge-Request-comments), or [Bitbucket](/cloud/integrations/bitbucket#Pull-Request-comments)) so Cypress Cloud comments on each pull request with the run summary and a link straight to Branch Review. For a destination those integrations don't reach, use [Cypress Cloud webhooks](/cloud/integrations/webhooks): Cypress Cloud sends `run.uiCoverage.completed` when the UI Coverage report finishes processing. See [Monitor changes](/ui-coverage/guides/monitor-changes#Step-1-Record-runs-on-a-regular-cadence).

### <Icon name="angle-right" /> Can I see UI Coverage trends across all my projects?

Yes. [Enterprise Reporting](/cloud/features/analytics/enterprise-reporting#UI-Coverage) in Cypress Cloud rolls UI Coverage trends up across every project in your organization rather than one run at a time. You can view high-level trends, download reports, or pull the numbers through the [data extract API](/cloud/integrations/data-extract-api) to build your own dashboards. See [Track trends across projects](/ui-coverage/guides/monitor-changes#Step-4-Track-trends-across-projects).

## Reducing test duplication

### <Icon name="angle-right" /> What is test duplication in Cypress UI Coverage?

Test duplication is when many separate tests exercise the same interactive element to pass _through_ a flow rather than to test it, such as every test clicking a **Log in** or **Continue** button during setup. UI Coverage surfaces it in the **Tested elements** section, where those shared setup steps rise to the top on interaction and test count. It's wasted suite time, not a coverage gap: the element is tested, just redundantly. See [Reduce test duplication](/ui-coverage/guides/reduce-test-duplication).

### <Icon name="angle-right" /> How do I find elements my tests exercise more than they need to?

Open the **Tested elements** section of the Cypress UI Coverage report. It lists every interactive element your tests exercised, with an **Interactions** column (how many times a command targeted it) and a **Tests** column (how many separate tests touched it), and it's sorted by interactions with the most-exercised elements first. A control that a large share of your suite interacts with, such as a **Log in** or **Continue** button, is usually shared setup being repeated across tests. Expand a row to break its counts down by view and open [Test Replay](/cloud/features/test-replay) on each occurrence. See [Reduce test duplication](/ui-coverage/guides/reduce-test-duplication).

### <Icon name="angle-right" /> What's the difference between the Interactions and Tests columns in UI Coverage?

In Cypress UI Coverage, **Interactions** counts every recognized command against an element across the run, so one test that hits a control in a loop can run the number up on its own. **Tests** counts the distinct tests that interacted with it, so a high number there means many _separate_ tests all touch the same control. The **Tests** column is the better signal for duplication, because shared setup repeated across your suite shows up as one element touched by a large share of your tests.

### <Icon name="angle-right" /> How do I reduce test duplication?

Use Cypress UI Coverage to find the elements at the top of the **Tested elements** list, confirm with [Test Replay](/cloud/features/test-replay) that the tests are passing _through_ a flow rather than testing it, then replace the repeated UI steps with a single programmatic step: cache authentication with [`cy.session()`](/api/commands/session), set a cookie or storage flag directly, or seed state with [`cy.request()`](/api/commands/request). Keep one test that still drives the flow through the UI so its coverage is preserved. The [Reduce test duplication](/ui-coverage/guides/reduce-test-duplication) guide walks through the full workflow.

### <Icon name="angle-right" /> Does reducing test duplication lower my UI Coverage score?

No. In Cypress UI Coverage, an element stays tested as long as at least one test still interacts with it, so consolidating redundant setup removes _interactions_, not _coverage_. When you replace a UI login in 200 tests with [`cy.session()`](/api/commands/session) and keep one test that drives the login form, the form's interaction count drops sharply while it remains marked as tested, and your overall score is unchanged.

### <Icon name="angle-right" /> What's the difference between reducing noise and reducing test duplication in UI Coverage?

[Reducing noise](/ui-coverage/guides/reduce-noise) is a report-accuracy problem: the report over-counts because one control is reported as many elements, or unrelated pages are split into separate views, and you fix it with [App Quality configuration](/ui-coverage/configuration/overview) in Cypress Cloud. [Reducing test duplication](/ui-coverage/guides/reduce-test-duplication) is a test-effort problem: the report is correct, but your suite repeats the same setup across many tests, and you fix it in your test code by consolidating that setup.

## Interactive elements

### <Icon name="angle-right" /> What does Cypress UI Coverage count as an interactive element?

UI Coverage follows the WHATWG definition of [interactive content](https://html.spec.whatwg.org/dev/dom.html#interactive-content), plus a few Cypress-specific rules. In short, an element counts when it is natively interactive (like `<a>`, `<button>`, or a form control), when it has an interactive ARIA `role` (such as `button` or `tab`), or when it is keyboard-focusable with `tabindex="0"` or higher. See [Interactive Elements](/ui-coverage/core-concepts/interactivity#Interactive-Elements) for the full rules.

### <Icon name="angle-right" /> Why doesn't Cypress UI Coverage track my custom widget as an interactive element?

UI Coverage detects interactivity from HTML semantics, not from event handlers, so a `<div>` with a click handler isn't recognized as interactive. The best fix is to give the control real semantics, such as using a `<button>` or adding an appropriate `role`, which also improves accessibility. When that isn't possible, add [`data-cy-ui-interactive="include"`](/ui-coverage/core-concepts/interactivity#Overriding-interactive-elements-with-data-cy-ui-interactive) to the element so UI Coverage tracks it.

### <Icon name="angle-right" /> How do I stop Cypress UI Coverage from tracking an element or a whole section?

You have two options. In your markup, add [`data-cy-ui-interactive="exclude"`](/ui-coverage/core-concepts/interactivity#Overriding-interactive-elements-with-data-cy-ui-interactive) to a single element or `data-cy-ui-interactive="exclude-all"` to a container to also exclude everything inside it (and `reset` to re-enable a subtree). To do the same from Cypress Cloud without changing application code, add an [`elementFilters`](/ui-coverage/configuration/elementfilters) rule with `include: false`. Excluded elements are removed from both the report and the score.

## Views and URLs

### <Icon name="angle-right" /> Why do similar URLs show up as separate views in Cypress UI Coverage?

Automatic grouping only replaces path segments that are numbers or IDs (UUIDs and UUID-like values) with a wildcard. Segments like usernames or slugs are not recognized as dynamic, so `/users/alice` and `/users/bob` remain separate views. Add a [`views`](/ui-coverage/configuration/views) pattern to group them yourself. See [how views are created](/ui-coverage/core-concepts/views#How-views-are-created) for the full set of automatic rules.

### <Icon name="angle-right" /> Do query parameters create separate Cypress UI Coverage views?

No. Query strings are ignored when grouping, so `/dashboard?tab=overview` and `/dashboard?tab=settings` become a single `/dashboard` view. If a query parameter meaningfully changes the page, use a [`views`](/ui-coverage/configuration/views) pattern with `groupBy` on that parameter to split it into separate views.

### <Icon name="angle-right" /> How do I create a separate UI Coverage view for each value of a URL parameter?

In Cypress UI Coverage, write a [`views`](/ui-coverage/configuration/views) pattern that names the parameter, then list that name in `groupBy`. For a pattern like `/analytics/:type/:id`, `groupBy: ["type"]` creates a distinct view for each `type` value (such as `/analytics/performance/:id` and `/analytics/usage/:id`) while still collapsing the dynamic `:id`. `groupBy` accepts a single string or an array of strings, and each name can come from the path, query string, or hash. See [Using groupBy](/ui-coverage/configuration/views#Using-groupBy).

### <Icon name="angle-right" /> How do I exclude URLs from UI Coverage?

In Cypress Cloud, add a [`viewFilters`](/ui-coverage/configuration/viewfilters) rule with `include: false` for a URL pattern. Excluding a URL removes its snapshots from the report and stops links pointing to it from counting against your coverage score. The [Ignore views and links](/ui-coverage/guides/ignore-views-and-links) guide walks through common cases.

### <Icon name="angle-right" /> In Cypress UI Coverage, what's the difference between viewFilters and views?

They do opposite things. [`viewFilters`](/ui-coverage/configuration/viewfilters) _removes_ URLs from your report and score, so excluded pages and the links pointing to them stop counting. [`views`](/ui-coverage/configuration/views) _keeps_ URLs but changes how they're grouped and named, so related pages collapse into a single view or a dynamic route splits into several. Use `viewFilters` for pages you don't own or intend to test, and `views` to organize the pages you do. See [Which option do I need?](/ui-coverage/configuration/overview#Which-option-do-I-need).

### <Icon name="angle-right" /> How do I exclude a third-party login or OAuth page from UI Coverage?

Add a [`viewFilters`](/ui-coverage/configuration/viewfilters) rule with `include: false` for the provider's URL, such as `{ "pattern": "https://acme.okta.com/*", "include": false }`. Tests that sign in through an external identity provider (Okta, Auth0, and similar) capture snapshots of its pages, and your links to it count as untested elements. One rule removes both, while every other URL stays included by default. See [Ignore views and links](/ui-coverage/guides/ignore-views-and-links).

### <Icon name="angle-right" /> Can I exclude a URL from UI Coverage without affecting Cypress Accessibility?

Yes. A [`viewFilters`](/ui-coverage/configuration/viewfilters) list at the root of your configuration applies to both products, but nesting it under a `uiCoverage` key applies it to UI Coverage only, so Cypress Accessibility keeps scanning the URL. A nested list completely replaces the root-level one for UI Coverage; the two are not merged, so include every rule UI Coverage needs. See [Scope](/ui-coverage/configuration/viewfilters#Scope).

### <Icon name="angle-right" /> Why is a URL still in my UI Coverage report after I excluded it with viewFilters?

The most common causes in Cypress UI Coverage are:

- An earlier rule matches the URL first. Rules apply in order and the first match wins, so a broad `include: true` rule listed before your exclusion prevents it from ever applying.
- The pattern doesn't match the full URL. Hostnames must match exactly (`https://my-app.com/*` doesn't match `www.my-app.com`), or you can use a path-only pattern like `/admin/*` to match any hostname.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

See [pattern matching behavior](/ui-coverage/configuration/viewfilters#How-are-viewFilters-rules-applied) for details.

### <Icon name="angle-right" /> Can I include only specific URLs in UI Coverage?

Yes. In Cypress Cloud, list `include: true` rules for the URLs you want, followed by a catch-all rule that excludes everything else: `{ "pattern": "*", "include": false }`. Because the first matching rule wins, the catch-all must come last. See [Include only your application's URLs](/ui-coverage/configuration/viewfilters#Include-only-your-applications-URLs) for a complete example.

### <Icon name="angle-right" /> Why is a page missing from my Cypress UI Coverage report?

Views are created from URLs your tests actually visit, so a page that no test navigates to has no view. Check [untested links](/ui-coverage/core-concepts/interactivity#Untested-Links) in the report, where pages that are linked to but never visited appear. Also confirm that a [`viewFilters`](/ui-coverage/configuration/viewfilters) rule isn't excluding the page unintentionally.

### <Icon name="angle-right" /> What is an untested link in Cypress UI Coverage?

An untested link is an `<a>` element whose destination URL is never visited during your run. Because a link points to a page, an untested link surfaces a flow your suite is missing even when no [view](/ui-coverage/core-concepts/views) exists for that page. Untested links count against your score unless you exclude their destination with [`viewFilters`](/ui-coverage/configuration/viewfilters). See [Untested Links](/ui-coverage/core-concepts/interactivity#Untested-Links).

### <Icon name="angle-right" /> Why don't `mailto:` and `tel:` links appear in Cypress UI Coverage?

Contact links, meaning anchors whose `href` uses `tel:`, `mailto:`, or `sms:`, aren't treated as interactive elements, so they never appear in reports and never count toward your score. If you need one tracked, add [`data-cy-ui-interactive="include"`](/ui-coverage/core-concepts/interactivity#Overriding-interactive-elements-with-data-cy-ui-interactive) to the anchor.

### <Icon name="angle-right" /> Why does Cypress UI Coverage count an external or non-`http` link as an untested link?

Any `href` that resolves to a URL is treated as a link to a destination, including absolute URLs to external sites and schemes like `ftp:`, `file:`, `data:`, `blob:`, or a custom app scheme. If the destination is never visited, it appears as an untested link. Only `#`, `javascript:`, on-page fragments like `#pricing`, and the contact schemes above are excluded. Exclude destinations you don't intend to test with [`viewFilters`](/ui-coverage/configuration/viewfilters). See [Which hrefs count as links](/ui-coverage/core-concepts/interactivity#Which-hrefs-count-as-links).

### <Icon name="angle-right" /> In Cypress UI Coverage, what's the difference between a hash route like `#/settings` and a page anchor like `#pricing` for untested links?

The leading slash. A hash route (`#/settings`) is treated as a URL, so it can be a destination and can appear as an untested link if never visited. A page anchor, or document fragment (`#pricing`), points to a section of the current page, so it's an ordinary interactive element that must be interacted with to count as tested and never appears as an untested link.

## Element grouping and identification

### <Icon name="angle-right" /> How does UI Coverage group elements automatically?

Out of the box, with no Cypress Cloud configuration, UI Coverage combines elements it recognizes as variations of the same control. It groups interactive elements that share the same [identifying attribute](/ui-coverage/core-concepts/element-identification#How-an-element-is-identified) value (such as a `data-cy="favorite"` button repeated on every card), form controls with their `<label>`, controls in the same position across table and grid rows, repeated structures that share a tag and class hierarchy, and links that resolve to the same [view](/ui-coverage/core-concepts/views). Automatic grouping needs at least two similar elements; a control that appears once stays on its own. See [Element Grouping](/ui-coverage/core-concepts/element-grouping#Automatic-grouping) for the full set of rules.

### <Icon name="angle-right" /> How does grouping affect my UI Coverage score?

A [group](/ui-coverage/core-concepts/element-grouping) counts once toward your total element count in Cypress Cloud, and interacting with any one member marks the whole group as tested. So a list of 50 identical "Remove" buttons contributes a single unit to your score, and one test that removes one item covers all 50. This keeps repeated elements from inflating your total and keeps a single untested set from sinking your score for no real gap in testing.

### <Icon name="angle-right" /> Why does my UI Coverage report show one group instead of every repeated element?

That's grouping working as intended. When UI Coverage detects that many elements are copies of the same control, such as a "Delete" button on every table row, it collapses them into one named group so the report stays readable and the score reflects distinct behaviors rather than raw element counts. If the automatic grouping is combining elements you'd rather see separately, split them apart with an [`elementGroups`](/ui-coverage/configuration/elementgroups) rule in your Cypress Cloud configuration.

### <Icon name="angle-right" /> Which UI Coverage grouping mechanism wins when more than one could apply?

The [`data-cy-ui-group` markup attribute](/ui-coverage/core-concepts/element-grouping#Grouping-with-markup-attributes) takes priority over everything, then [`elementGroups`](/ui-coverage/configuration/elementgroups) configuration rules in Cypress Cloud, and finally the [automatic grouping rules](/ui-coverage/core-concepts/element-grouping#Automatic-grouping) apply to whatever no attribute or rule claimed. Elements removed by [`elementFilters`](/ui-coverage/configuration/elementfilters) are never grouped at all.

### <Icon name="angle-right" /> What happens if two UI Coverage elementGroups rules match the same element?

In Cypress UI Coverage, the first matching rule in your [`elementGroups`](/ui-coverage/configuration/elementgroups) configuration wins, so list specific rules before broad catch-all rules. A rule that appears after another rule matching the same elements never applies to them.

### <Icon name="angle-right" /> Can I group UI Coverage elements in my application code instead of Cypress Cloud configuration?

Yes. Add the [`data-cy-ui-group` attribute](/ui-coverage/core-concepts/element-grouping#Grouping-with-markup-attributes) to your markup, and elements sharing the same attribute value are grouped together with no Cloud configuration needed. Placing the attribute on a wrapper element groups every interactive element inside it. Groups defined this way take priority over [`elementGroups`](/ui-coverage/configuration/elementgroups) configuration rules.

### <Icon name="angle-right" /> Can I group or filter UI Coverage elements inside iframes or shadow DOM?

Yes. In Cypress UI Coverage, the [`elementGroups`](/ui-coverage/configuration/elementgroups), [`elementFilters`](/ui-coverage/configuration/elementfilters), [`elements`](/ui-coverage/configuration/elements), and [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) configuration options all accept a `documentScope` property that limits a rule to elements inside specific iframes or shadow DOM hosts. List one CSS selector per host, ordered from the outermost document to the innermost.

**Note:** Shadow DOM and iframe processing for UI Coverage is optional and off by default. If you are experiencing unexpected results, reach out to your Cypress representative or use the feedback button in the product.

### <Icon name="angle-right" /> Why isn't my element group showing up in the UI Coverage report?

The most common causes in Cypress UI Coverage are:

- An earlier `elementGroups` rule matches the same elements, and the first matching rule wins.
- The elements are excluded by [`elementFilters`](/ui-coverage/configuration/elementfilters), so they're never considered for grouping.
- The elements declare a group in markup with the `data-cy-ui-group` attribute, which takes priority over configuration rules.
- The selector matches a container rather than the interactive elements themselves.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> How do I exclude elements from UI Coverage?

In Cypress Cloud, add an [`elementFilters`](/ui-coverage/configuration/elementfilters) rule with `include: false` for a CSS selector that matches the elements. Excluded elements are removed from the report and don't count toward your coverage score. This is the standard way to remove third-party widgets, such as chat launchers or cookie banners, from your reports. The [Ignore elements](/ui-coverage/guides/ignore-elements) guide walks through common cases.

### <Icon name="angle-right" /> How do I exclude a third-party widget like a chat launcher or cookie banner from UI Coverage?

In Cypress Cloud, add an [`elementFilters`](/ui-coverage/configuration/elementfilters) rule with `include: false` whose selector matches the widget's container _and_ its descendants, so every control inside it is removed rather than just the wrapper. For a support chat like Intercom, that's `{ "selector": "#intercom-container, #intercom-container *", "include": false }`. Widgets rendered inside an iframe or shadow DOM are removed by pairing a `*` selector with [`documentScope`](/ui-coverage/configuration/elementfilters#Options). See [Ignore elements](/ui-coverage/guides/ignore-elements) for the full walkthrough.

### <Icon name="angle-right" /> Should I exclude UI Coverage elements with elementFilters or data-cy-ui-interactive?

Both remove an element from the report and the score; choose by who owns the decision. Use [`elementFilters`](/ui-coverage/configuration/elementfilters) to manage exclusions centrally in Cypress Cloud with no code change, which fits when the team editing configuration isn't the team that owns the markup. Use the [`data-cy-ui-interactive`](/ui-coverage/core-concepts/interactivity#Overriding-interactive-elements-with-data-cy-ui-interactive) attribute (`exclude` on one element, `exclude-all` on a container) when the exclusion belongs next to the markup that owns it. `elementFilters` also supports `include: true` exceptions and `documentScope`, which the markup attribute doesn't.

### <Icon name="angle-right" /> Do excluded elements count toward my UI Coverage score?

No. In Cypress UI Coverage, an element excluded by [`elementFilters`](/ui-coverage/configuration/elementfilters) doesn't appear in the report and doesn't count toward the score, whether your tests interacted with it or not. It's also not considered by [`elementGroups`](/ui-coverage/configuration/elementgroups) or [`elements`](/ui-coverage/configuration/elements) rules.

### <Icon name="angle-right" /> Why isn't my UI Coverage elementFilters rule excluding an element?

The most common causes in Cypress UI Coverage are:

- The selector matches a container instead of the element itself. Filters use standard CSS matching against each tracked element, so `footer` matches only the `<footer>` element. Use a descendant selector like `footer *` to exclude everything inside a container.
- An earlier `elementFilters` rule already matched the element, and the first matching rule wins. An `include: true` rule above your exclude rule protects the elements it matches.
- The rule has a `documentScope` that doesn't match the element's iframe or shadow DOM hosts.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> Can I exclude elements from UI Coverage without affecting Cypress Accessibility?

Yes. An `elementFilters` list at the root of your configuration applies to both products, but nesting it under a `uiCoverage` or `accessibility` key applies it to that product only. A nested list completely replaces a root-level one for that product; the two are not merged. See [Exclude elements](/ui-coverage/configuration/elementfilters#Scope).

### <Icon name="angle-right" /> Why does one element appear as multiple elements in my Cypress UI Coverage report?

This usually means the element's identifying attributes change between [snapshots](/ui-coverage/core-concepts/element-identification#Snapshots), for example auto-generated IDs or dynamic class names. Use [`attributeFilters`](/ui-coverage/configuration/attributefilters) to ignore the dynamic attributes, or [`elements`](/ui-coverage/configuration/elements) to define the element's identity explicitly. See [troubleshooting](/ui-coverage/troubleshooting) for more scenarios.

### <Icon name="angle-right" /> Which attributes does UI Coverage use to identify elements?

Cypress UI Coverage checks a prioritized list of attributes on each element and uses the first one present with a usable value. In order, that's: `data-cy-ui-id` (which replaces the element's identity outright), any attributes you add to [`significantAttributes`](/ui-coverage/configuration/significantattributes), then the default test attributes `data-cy`, `data-test`, `data-testid`, `data-test-id`, `data-qa`, and `row-id`, falling back to `id` and `name` when none of those are present. See [Element Identification](/ui-coverage/core-concepts/element-identification#How-an-element-is-identified) for the full priority list and how identification works across snapshots.

### <Icon name="angle-right" /> How does UI Coverage identify an element that has no test attribute or id?

When an element has none of the [identifying attributes](/ui-coverage/core-concepts/element-identification#How-an-element-is-identified), Cypress UI Coverage falls back to identifying it by its structure and position in the DOM. Because that identity is less stable than an attribute you control, adding a stable `data-cy` (or similar) attribute is the reliable fix. See [When an element has no identifying attribute](/ui-coverage/core-concepts/element-identification#When-an-element-has-no-identifying-attribute).

### <Icon name="angle-right" /> How do I make UI Coverage use my own attribute to identify elements?

Add the attribute name to [`significantAttributes`](/ui-coverage/configuration/significantattributes). In Cypress UI Coverage, attributes you list are checked before the default list, in the order you list them, so an attribute your application already renders, such as `data-component-name`, can identify, name, and group elements in your reports.

### <Icon name="angle-right" /> In UI Coverage, does significantAttributes replace the default attribute list?

No. In Cypress UI Coverage, your attributes are checked first, and the defaults still apply after them, so an element without any of your attributes is identified exactly as it would be without configuration. Listing a default attribute like `data-qa` promotes it above the other defaults. To stop an attribute from being used at all, use [`attributeFilters`](/ui-coverage/configuration/attributefilters) instead.

### <Icon name="angle-right" /> Can I use a non-`data-` attribute like aria-label as a UI Coverage significant attribute?

Yes. In Cypress UI Coverage, any valid HTML attribute qualifies, not only `data-*` attributes. Listing [`aria-label`](/ui-coverage/configuration/significantattributes) identifies elements by their label text, which gives icon-only controls a readable identity. Because UI Coverage lists every interactive element, it also surfaces every label for a person to read and judge for clarity, since automated accessibility tools confirm only that a label exists, not that it is well written.

### <Icon name="angle-right" /> Why isn't my UI Coverage elements rule applying?

In Cypress UI Coverage, an [`elements`](/ui-coverage/configuration/elements) rule applies only when its selector matches exactly one interactive element in a snapshot. The most common causes are:

- The selector matches more than one interactive element in the same snapshot, so the rule is skipped for that snapshot. Add [`documentScope`](/ui-coverage/configuration/elements#Options) or a more specific selector, or use [`elementGroups`](/ui-coverage/configuration/elementgroups) if several elements should share an identity.
- The selector only matches non-interactive elements, such as a wrapper around the actual button or input.
- The element is excluded by [`elementFilters`](/ui-coverage/configuration/elementfilters), so it's never considered.
- A later `elements` rule matches the same element, and the last matching rule wins.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> How do I stop dynamic IDs or class names from splitting one UI Coverage element into many?

Add an [`attributeFilters`](/ui-coverage/configuration/attributefilters) rule with `include: false` that matches the unstable attribute and value, for example an `id` like `:r11:` or a hashed `class`. Once the volatile attribute is ignored, Cypress identifies the element by a stable attribute instead, so the same control is recognized across [snapshots](/ui-coverage/core-concepts/element-identification#Snapshots) and counted once. When you filter a dynamic `id`, also filter the attributes that reference it (`for`, `aria-labelledby`, `aria-describedby`, and similar), or the element can still be identified by those related values.

### <Icon name="angle-right" /> Do I need to configure UI Coverage attributeFilters for auto-generated IDs?

Often not. Cypress already ignores the most common unstable identifiers, including values containing UUIDs or long hexadecimal hashes, digit-only `id`/`name`/`for`/`aria-*` values, and generated `class` patterns like `jss*` and `ng-tns-*`. Add an [`attributeFilters`](/ui-coverage/configuration/attributefilters) rule only when your application produces unstable attributes these built-in filters don't already cover.

### <Icon name="angle-right" /> In UI Coverage, what's the difference between attributeFilters and significantAttributes?

They pull in opposite directions. [`attributeFilters`](/ui-coverage/configuration/attributefilters) _removes_ attributes from consideration so Cypress won't identify elements by them, while [`significantAttributes`](/ui-coverage/configuration/significantattributes) _prioritizes_ attributes so Cypress prefers them when they're available. Use `attributeFilters` to hide noisy or dynamic attributes, and `significantAttributes` to promote a stable attribute such as `data-component-name`.

### <Icon name="angle-right" /> Why isn't my UI Coverage attributeFilters rule working?

The most common causes in Cypress UI Coverage are:

- The pattern doesn't match the full value. Patterns are anchored automatically (as if wrapped in `^(...)$`), so `value: "user"` matches only the exact string `user`. Use wildcards for partial matches, such as `value: "user-.*"`.
- An earlier rule matches the same attribute first, and the first matching rule wins. List specific `include: true` exceptions before broad `include: false` rules.
- The rule targets a tag name or sibling position. Only attributes and individual `class` tokens can be filtered, not an element's tag name or `nth-child` position.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

## Interaction commands

### <Icon name="angle-right" /> Which Cypress commands does UI Coverage count as coverage by default?

UI Coverage marks an element as tested when it's targeted by one of a default set of Cypress interaction commands: `blur`, `check`, `clear`, `click`, `dblclick`, `focus`, `rightclick`, `scrollIntoView`, `scrollTo`, `select`, `selectFile`, `submit`, `trigger`, `type`, and `uncheck`. Commands outside this set, including plugin commands like `realClick` and `realHover` and assertions, don't count until you add them with [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands) or [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands). See [Interaction Commands](/ui-coverage/core-concepts/interactivity#Interaction-Commands).

Two commands in this list behave differently from the rest. `scrollIntoView` credits the element's nearest **scrollable ancestor**, not the element you called it on, so it usually produces no coverage for the target itself. Use a real interaction to mark that element tested. `scrollTo` credits only an exact match and is never credited through a parent element.

### <Icon name="angle-right" /> How do I make UI Coverage count cypress-real-events commands like realClick and realType?

[`cypress-real-events`](https://github.com/dmtrKovalenko/cypress-real-events) commands (`realClick`, `realType`, `realHover`) aren't built-in Cypress commands, so UI Coverage doesn't count them until you list them in [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands), nested under the `uiCoverage` key. Once listed, the elements they target are marked as tested.

### <Icon name="angle-right" /> Why isn't my custom command counted as an interaction in UI Coverage?

Two conditions must both hold. First, the command name must be listed in [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands) (or [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands)), matched case-sensitively and written exactly as you registered it. Second, the command must log a [snapshot](/ui-coverage/core-concepts/element-identification#Snapshots) that references the subject element, so UI Coverage knows which element to credit. In practice, register the command with [`prevSubject`](/api/cypress-api/custom-commands#Arguments), call [`Cypress.log`](/api/cypress-api/cypress-log) with the subject as `$el`, and capture a snapshot. If you added the command after a run was processed, regenerate the run to apply the change.

### <Icon name="angle-right" /> In UI Coverage, what's the difference between additionalInteractionCommands and allowedInteractionCommands?

In Cypress UI Coverage, [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands) _extends_ the set of commands recognized as interactions everywhere, so a custom or plugin command counts as coverage on any element. [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) works _per element_: for elements matching a selector, only the commands you list count, which lets you both restrict coverage to a meaningful interaction and accept commands that are otherwise ignored. Use `additionalInteractionCommands` to recognize a command globally, and `allowedInteractionCommands` to control which commands matter for specific elements.

### <Icon name="angle-right" /> How do I require a specific interaction in UI Coverage, like a hover, to mark an element tested?

In Cypress UI Coverage, add an [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) rule whose `selector` matches the element and whose `commands` list contains only the interaction you require. Because matching a rule replaces the default commands for that element, interactions you didn't list, including a plain `click`, no longer mark it tested, so the element only counts once the meaningful interaction runs.

### <Icon name="angle-right" /> Can I count assertions as UI Coverage?

Yes. In Cypress UI Coverage, assertions don't count by default, but an [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) rule listing `assert` credits assertions against the matching elements. This is useful for read-only elements such as status badges or computed totals that your tests validate but never interact with. Remember that the rule replaces the defaults for those elements, so include any other commands you also want to accept alongside `assert`.

### <Icon name="angle-right" /> In UI Coverage, do commands in allowedInteractionCommands also need to be in additionalInteractionCommands?

No. In Cypress UI Coverage, listing a command in an [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) rule automatically registers it as a recognized interaction, so a custom or plugin command works without also appearing in [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands). As with any custom command, it only produces coverage if it logs a snapshot that references the subject element.

### <Icon name="angle-right" /> Why did an element stop counting as tested in UI Coverage after I added an allowedInteractionCommands rule?

In Cypress UI Coverage, once an element matches an [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) rule, only the commands listed in the matching rules count for it, and the default commands no longer apply. If your tests exercise the element with a command you didn't list, it's now treated as untested. Add that command to the rule, or tighten the `selector` so the rule doesn't match elements you didn't intend to restrict.

## Configuration

### <Icon name="angle-right" /> Do I need to configure anything to use UI Coverage?

No. Cypress UI Coverage works out of the box with no configuration. Every recorded run produces a report automatically. Configuration is opt-in and incremental: add a rule only when you want to sharpen the report, such as ignoring a dynamic attribute, filtering out a third-party widget, or grouping related elements. See the [Configuration overview](/ui-coverage/configuration/overview) for what each option does.

### <Icon name="angle-right" /> Where do I set UI Coverage configuration?

In the **App Quality** tab of your project settings in Cypress Cloud. By default, only Admin users can edit configuration; your Cypress point-of-contact can change this on request. See [Setting configuration](/ui-coverage/configuration/overview#Setting-configuration).

### <Icon name="angle-right" /> How do I document why a UI Coverage configuration rule exists?

Add a `comment` property to any rule. Comments are for humans only and have no effect on behavior, so they're the supported place to explain a rule for teammates or your future self. Because Cypress Cloud rejects properties it doesn't recognize, `comment` is the only field you can use for freeform notes. See [Comments](/ui-coverage/configuration/overview#Comments).

### <Icon name="angle-right" /> Why is Cypress Cloud rejecting my UI Coverage configuration as invalid?

Cypress Cloud validates your configuration against a strict schema and rejects any property it doesn't recognize. The usual causes are a misspelled property name, a value of the wrong type (for example, a string where an array is expected), or a note added on an unsupported field. Put explanations in a [`comment`](/ui-coverage/configuration/overview#Comments) instead. The editor reports the offending property so you can correct it before saving.

### <Icon name="angle-right" /> Do I need to rerun my tests after changing UI Coverage configuration?

No. You can regenerate any historical run from its **Properties** tab, and the report is reprocessed with the current configuration. This lets you iterate on configuration and see the effects immediately without running your Cypress tests again.

### <Icon name="angle-right" /> Does my configuration apply to Cypress Accessibility too?

Root-level properties like [`viewFilters`](/ui-coverage/configuration/viewfilters), [`elementFilters`](/ui-coverage/configuration/elementfilters), and [`views`](/ui-coverage/configuration/views) apply to both UI Coverage and Cypress Accessibility. To configure the products separately, nest `viewFilters`, `elementFilters`, `attributeFilters`, or `significantAttributes` under a `uiCoverage` or `accessibility` key; the nested list completely replaces the root-level one for that product. See [Configuration scope](/ui-coverage/configuration/overview#Configuration-scope).

### <Icon name="angle-right" /> Can I use different UI Coverage configuration for different runs?

Yes. In Cypress UI Coverage, the [`profiles`](/ui-coverage/configuration/profiles) property applies configuration overrides based on [run tags](/app/references/command-line#cypress-run-tag-lt-tag-gt), so a smoke-test run and a full regression run can each use their own settings.

## Profiles

### <Icon name="angle-right" /> How do I apply different UI Coverage settings to different runs?

In your project's App Quality configuration in Cypress Cloud, add a [`profiles`](/ui-coverage/configuration/profiles) array, give each profile a `name`, and record the run with a matching [`--tag`](/app/references/command-line#cypress-run-tag-lt-tag-gt). When a run's tag matches a profile's `name`, that profile's `config` overrides your base configuration for that run, so a smoke run and a full regression run can each use their own settings without changing your test code. If no tag matches, the base configuration is used unchanged.

### <Icon name="angle-right" /> Does a UI Coverage profile override my base configuration or merge with it?

Cypress Cloud overrides one property at a time with a shallow merge, not a deep merge. Any property the profile lists replaces the root value for that property entirely (arrays are replaced, not concatenated), so if a profile defines [`elementFilters`](/ui-coverage/configuration/elementfilters), repeat any root rules you still want to keep. Properties the profile doesn't mention are inherited from the root. The `uiCoverage` and `accessibility` objects merge one level deep, so a profile can override `uiCoverage.elementGroups` while still inheriting `uiCoverage.attributeFilters`. See [How a profile changes your configuration](/ui-coverage/configuration/profiles#How-a-profile-changes-your-configuration).

### <Icon name="angle-right" /> If a run has multiple tags that match profiles, which UI Coverage profile is used?

Cypress Cloud uses the first profile in the [`profiles`](/ui-coverage/configuration/profiles) array whose `name` matches one of the run's tags. The tie is broken by the order of the profiles array, not the order of the tags on the run, so reordering tags on the command line never changes which profile applies.

### <Icon name="angle-right" /> Why isn't my UI Coverage profile applied even though I tagged the run?

The most common causes are:

- The run tag doesn't exactly match the profile `name`. Matching is case-sensitive and exact, so `aq-config-regression` matches only the tag `aq-config-regression`, not `AQ-Config-Regression` or `aq-config-regression-nightly`.
- The tag never reached Cypress Cloud. Profiles are selected from the tags passed to `cypress run --record --tag`, so a run recorded without `--record`, or without that specific `--tag`, falls back to the base configuration.
- An earlier profile in the array also matches one of the tags and is used instead, because the first match wins.
- The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.

### <Icon name="angle-right" /> Can a profile turn off UI Coverage or skip a run entirely?

There's no dedicated "skip this run" switch in a profile. To suppress a report for certain runs, point a profile at a deliberately narrow configuration (for example, [`viewFilters`](/ui-coverage/configuration/viewfilters) that exclude every view) so Cypress Cloud produces an empty or tightly scoped report for the run instead. See [Why use profiles?](/ui-coverage/configuration/profiles#Why-use-profiles).

## Results API and CI

### <Icon name="angle-right" /> What are the prerequisites for using the Cypress UI Coverage Results API?

A few conditions must hold before `getUICoverageResults` can return a report:

- **Test Replay must be enabled** for the run. UI Coverage reports are built from [Test Replay](/cloud/features/test-replay) data, so a run recorded with Test Replay off has no report and the helper throws. Enable it in your project settings.
- **Record with Cypress v13 or later.** [Azure Pipelines](/app/continuous-integration/overview#Azure-Pipelines) and [CircleCI](/app/continuous-integration/circleci) additionally require **Cypress v13.13.1 or later** to capture the CI metadata needed to identify runs.
- **The run must have been recorded within the last 7 days.** Older runs can no longer be identified from CI context.
- **Run the script after recording, in the same CI build**, so the run it should report on already exists.

### <Icon name="angle-right" /> How do I fail a CI build or block a pull request when Cypress UI Coverage drops?

Use the [Results API](/ui-coverage/results-api). Add a step to your CI workflow that installs the `@cypress/extract-cloud-results` module and calls `getUICoverageResults()` after your Cypress run. The helper returns the run's coverage summary and per-view breakdown, and your script decides whether to fail, for example by throwing an error when `summary.coverage` is below a threshold. Because the check lives in your CI job, nothing in the Cypress run itself fails; enforcement is entirely opt-in. See [Block pull requests and set policies](/ui-coverage/guides/block-pull-requests) for a complete example.

### <Icon name="angle-right" /> Do I need to install anything to use the Cypress UI Coverage Results API?

Only in CI. Install the `@cypress/extract-cloud-results` module in your CI install step with `npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz`. Don't add it to your `package.json` dependencies; install it separately with `--force` so you always get the latest version, as documented in the [Results API installation steps](/ui-coverage/results-api#Installation).

### <Icon name="angle-right" /> Why can't the Cypress UI Coverage Results API find my Cypress Cloud run?

`getUICoverageResults` identifies the run from the CI environment variables present when the run was recorded, so the most common causes are:

- The script runs in a **different CI build** than the one that recorded the run, or **before** the `cypress run --record` step. Run it after recording, in the same build.
- The run was recorded **more than 7 days ago**. Only runs from the last 7 days can be identified from CI context.
- You record **multiple runs in one CI build** but didn't pass `runTags`. Tag each run with `--tag` and pass the matching tag to `getUICoverageResults`.
- The run was recorded on an **unsupported Cypress version**. Azure Pipelines and CircleCI require Cypress v13.13.1 or later.

See [Required CI environment variables](/ui-coverage/results-api#Required-CI-environment-variables) for how each provider is matched.

### <Icon name="angle-right" /> Why does the Cypress UI Coverage Results API say no report was found for my run?

UI Coverage reports are generated from [Test Replay](/cloud/features/test-replay) data. If Test Replay was disabled for the run, no report is produced and the helper throws. Enable Test Replay in your project settings and record a new run.

### <Icon name="angle-right" /> How do I get Cypress UI Coverage results when I record multiple runs in one CI build?

Record each run with a distinct [`--tag`](/app/references/command-line#cypress-run-tag-lt-tag-gt) and pass that same tag to the helper via `runTags`. For example, `cypress run --record --tag staging` is retrieved with `getUICoverageResults({ runTags: ['staging'] })`. Without tags, Cypress can't tell the runs apart and can't return a single run's results.

### <Icon name="angle-right" /> Can I see which App Quality configuration or profile produced a Cypress UI Coverage report?

Yes. The result object includes a `config` property containing the [App Quality Config](/ui-coverage/configuration/overview) as saved for the project when the run was processed. Read `config.value` for the rules and `config.updatedAt` for when that configuration last changed. `config.value` is not resolved against the run's tags, so if a [Profile](/ui-coverage/configuration/profiles) applied you match the run's tags against profile names yourself. See [Assert the configuration](/ui-coverage/results-api#Assert-the-configuration).

### <Icon name="angle-right" /> Should I block pull requests on a coverage threshold or on new coverage gaps?

Both are valid Cypress UI Coverage policies, and they suit different situations. A **coverage threshold** fails the build when overall or per-view coverage drops below a fixed percentage; it's simple and works well once your coverage is already where you want it, or for holding a critical flow like checkout to a high bar. A **baseline comparison** fails only when a run introduces _new_ untested elements, which is the better fit for an existing app with known coverage debt: it stops gaps from growing without blocking every pull request until all the old debt is paid down. Many teams enforce a threshold on critical views and a baseline everywhere else. See [Block pull requests and set policies](/ui-coverage/guides/block-pull-requests#Choose-a-policy).

### <Icon name="angle-right" /> How do I block a pull request only when new untested elements are introduced?

Compare each run against a stored **baseline** instead of a fixed threshold. Record a known-good run, save each [view's](/ui-coverage/core-concepts/views) `untestedElementsCount` to a small JSON file committed to your repository, then in CI use the [Cypress UI Coverage Results API](/ui-coverage/results-api) to fail the build only when a view's untested-element count rises above its baseline (or a new view arrives carrying untested elements). This lets you pay down existing gaps on your own schedule while preventing new ones from merging. The [Block pull requests and set policies](/ui-coverage/guides/block-pull-requests#comparing-against-a-baseline) guide has the complete script.

### <Icon name="angle-right" /> Why compare untested-element counts instead of the UI Coverage score when gating pull requests?

The [coverage score](/ui-coverage/guides/identify-coverage-gaps#Step-2-Read-your-overall-coverage-score) is the share of your app's interactive elements that your tests exercise (tested ÷ total, with grouped elements counting once), which makes it ideal for tracking direction over time but noisy as a per-run gate: adding a single test can reveal a whole page of previously unseen elements and _lower_ the score even though coverage improved. In Cypress UI Coverage, a view's `untestedElementsCount` is a more direct answer to "did this change add gaps?": if it rises against the baseline, the change introduced untested elements regardless of what the percentage did. Note the two aren't interchangeable, since the score's denominator also counts navigable links while `untestedElementsCount` doesn't. See [Why compare untested-element counts instead of the coverage score?](/ui-coverage/guides/block-pull-requests#Why-compare-untested-element-counts-instead-of-the-coverage-score).

### <Icon name="angle-right" /> Where should I store my UI Coverage baseline?

Commit the Cypress UI Coverage baseline JSON file to version control so it's reviewed and versioned alongside the code that changes your coverage, and is available to every CI run. If you can't commit it, store it as a CI build artifact retrieved on later runs, or in a database when you need richer versioning across many projects. For long-lived branches, keep branch-specific baseline files so a feature branch isn't gated against `main`'s numbers. See [Best practices](/ui-coverage/guides/block-pull-requests#Where-to-store-the-baseline).

## Troubleshooting

### <Icon name="angle-right" /> Why is my UI Coverage score lower than I expect?

A few sources of untested elements commonly lower a Cypress UI Coverage score without pointing to a real gap in your suite. Third-party widgets, such as chat launchers, cookie banners, and analytics overlays, are interactive elements each counted as untested; exclude them with [`elementFilters`](/ui-coverage/configuration/elementfilters). [Untested links](/ui-coverage/core-concepts/interactivity#Untested-Links) to pages no test visits, including your own help center, marketing pages, and external sites, also count against the score; exclude their destinations with [`viewFilters`](/ui-coverage/configuration/viewfilters). Finally, one control [split into many](/ui-coverage/troubleshooting#One-element-is-reported-as-many) by an unstable attribute adds duplicate untested elements. See [the coverage score looks wrong](/ui-coverage/troubleshooting#The-coverage-score-looks-wrong) for the fixes.

### <Icon name="angle-right" /> Why does an element my test interacts with still show as untested in UI Coverage?

Usually the command your test uses isn't one UI Coverage recognizes. It counts only a [default set of interaction commands](/ui-coverage/core-concepts/interactivity#Interaction-Commands), so custom commands and plugin commands like `cypress-real-events`' `realClick` don't count until you add them with [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands) or [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands). A custom command also has to log a [snapshot](/ui-coverage/core-concepts/element-identification#Snapshots) referencing the element it acts on. And if you added an `allowedInteractionCommands` rule, only the commands you listed count for the matching elements, so a command you left out, even a plain `click`, no longer marks them tested. See [an element you tested is shown as untested](/ui-coverage/troubleshooting#An-element-you-tested-is-shown-as-untested).

### <Icon name="angle-right" /> I changed my UI Coverage configuration but the report didn't change. Why?

Most often the run was processed before you saved: Cypress UI Coverage reports use the configuration that was applied when they were generated, so [regenerate](/ui-coverage/configuration/overview#Setting-configuration) the run to apply your current configuration. If it still has no effect, check whether an earlier rule matched first (the first matching rule wins for most properties), whether a [nested list replaced a root one](/ui-coverage/configuration/overview#Configuration-scope) instead of merging with it, or whether the configuration failed to save because a property was misspelled or misplaced. See [a configuration rule has no effect](/ui-coverage/troubleshooting#A-configuration-rule-has-no-effect) for the full checklist.

### <Icon name="angle-right" /> How do I debug a UI Coverage report that looks wrong?

Start by [regenerating the run](/ui-coverage/configuration/overview#Setting-configuration) in Cypress Cloud so it reflects your current configuration, then match your symptom to a cause on the [Troubleshooting](/ui-coverage/troubleshooting) page, which covers duplicate elements, mis-grouped elements, tested elements shown as untested, configuration that has no effect, and unexpected scores. Because you can regenerate any past run, the fastest approach is to make one change, regenerate a recent run, and check the result before making the next.

## Using AI agents with Cypress UI Coverage

### <Icon name="angle-right" /> Which Cypress Cloud MCP tools expose UI Coverage data to AI agents?

Cypress Cloud MCP provides three UI Coverage tools: `cypress_get_ui_coverage_report` returns a run's overall coverage score, tested and untested element and link counts, and the top 5 riskiest views; `cypress_get_ui_coverage_views` pages through all views sorted by most untested elements and links; and `cypress_get_ui_coverage_elements` pages through individual elements, filterable by tested or untested and scopable to a single view. Your AI agent selects them automatically based on your prompt.

### <Icon name="angle-right" /> Can Cypress Cloud MCP update my Cypress tests, configuration, or runs?

No. The Cypress UI Coverage MCP tools are read-only: they retrieve report data and can't edit your test code, update your [App Quality configuration](/ui-coverage/configuration/overview), or delete runs. An AI agent can draft test code locally in your editor, but nothing an agent does through Cypress Cloud MCP writes back to Cypress Cloud. Access is also scoped to the projects your Cypress Cloud user can already see. See [Cloud MCP security](/cloud/integrations/cloud-mcp#Security--Privacy).

### <Icon name="angle-right" /> How do I make Cypress UI Coverage reports easier for an AI agent to use?

Shape your Cypress UI Coverage report the same way you would for human review. [Filter out](/ui-coverage/configuration/elementfilters) third-party widgets you don't own, [promote a stable attribute](/ui-coverage/configuration/significantattributes) so elements have clean, readable names, and [group](/ui-coverage/configuration/elementgroups) repeated controls so they count once. A high-signal report gives the agent accurate context and avoids wasting tokens on noise. See [Tune reports for better agent results](/ui-coverage/work-with-ai-agents#Tune-reports-for-better-agent-results).

### <Icon name="angle-right" /> Can an AI agent write Cypress tests for my untested UI Coverage elements?

Yes, with your review. Because Cypress UI Coverage lists untested elements with the selectors and views that produced them, an AI agent can draft Cypress tests targeting those elements and suggest the existing spec file that's the best home for them. Pair the agent with [Cypress AI Skills](/app/tooling/ai-skills) so the tests it drafts follow Cypress best practices and match your project's conventions. Ask it to show a diff before writing files, and confirm intent and risk yourself before merging. See the [prompts to plan and draft tests](/ui-coverage/work-with-ai-agents#Prompts-to-plan-and-draft-tests).

### <Icon name="angle-right" /> Is my Cypress UI Coverage data used to train AI models?

No. Cypress UI Coverage data returned through Cypress Cloud MCP is used only to fulfill the agent's request and is never used to train or improve any LLM. Cypress also has no visibility into your AI assistant's conversation or outputs. See [Cloud MCP security and privacy](/cloud/integrations/cloud-mcp#Security--Privacy).

## See also

- [Troubleshooting UI Coverage](/ui-coverage/troubleshooting) maps common report problems to their causes and fixes.
- [Monitor changes](/ui-coverage/guides/monitor-changes) sets up a repeatable workflow to track coverage trends and catch regressions before they merge.
- [Work with AI agents](/ui-coverage/work-with-ai-agents) uses the Cypress Cloud MCP to read reports, summarize gaps, and draft tests.
- [Results API](/ui-coverage/results-api) fetches a run's UI Coverage results in CI so you can enforce coverage standards.
- [Configuration overview](/ui-coverage/configuration/overview) lists every configuration option and what each one is for.
- [Profiles](/ui-coverage/configuration/profiles) apply different configuration to runs based on run tags.
- [Views](/ui-coverage/core-concepts/views) explains how URLs become views and how automatic grouping works.
- [Element Identification](/ui-coverage/core-concepts/element-identification) covers how elements are identified and grouped across snapshots.
- [Interactivity](/ui-coverage/core-concepts/interactivity) describes which commands count as coverage.

---

### Ui Coverage Results Api (`docs/ui-coverage/results-api.mdx`)

---
title: 'UI Coverage Results API: enforce coverage in CI'
description: 'Programmatically fetch UI Coverage results in CI with @cypress/extract-cloud-results, then block pull requests or fail the build when coverage drops below your thresholds.'
sidebar_label: Results API
sidebar_position: 100
---

<ProductHeading product="ui-coverage" />

# Results API

UI Coverage reports are generated in Cypress Cloud after your run finishes, so
nothing in your Cypress pipeline fails on its own when coverage drops. The
**Results API** closes that loop: it lets you pull a run's UI Coverage results
into your CI job and decide, in code, whether the coverage is good enough to
merge.

<UICovPremiumNote />

With the `getUICoverageResults` helper from the
`@cypress/extract-cloud-results` module you can:

- **Fail a build or block a pull request** when overall coverage falls below a
  threshold, or when a critical view regresses.
- **Enforce different standards per area** of your app, such as requiring
  higher coverage on `/checkout` than on marketing pages.
- **Surface results where your team works** by posting the coverage score and a
  deep link to the report on the pull request or in Slack.
- **Catch navigation gaps** by flagging pages that are linked but never visited,
  using the tested and untested link counts.
- **Track regressions over time** by comparing a run against a stored baseline,
  or by trending results in a dashboard.
- **Read and assert the configuration** that was in place when this UI Coverage report was processed.

See [Examples](#Examples) for a worked script behind each of these.

Because reports are processed server-side from
[Test Replay](/cloud/features/test-replay) data, using the Results API adds no
overhead to your Cypress runs. The enforcement step is entirely opt-in and
lives in your CI workflow.

## How it works

When you call `getUICoverageResults` inside a CI job, the helper:

1. **Identifies the Cypress run** for the current CI build by cross-referencing
   the CI environment variables present when the run was recorded. See
   [Required CI environment variables](#Required-CI-environment-variables) for
   details.
2. **Waits for the UI Coverage report to finish processing.** If the report is
   still processing, the helper polls Cypress Cloud (up to 30 attempts at
   30-second intervals, roughly 15 minutes) before returning.
3. **Returns the results** as a structured object you can assert against, or
   **throws a descriptive error** if no matching run or report can be found.

Because the helper matches the run from the current CI context, call it **after
`cypress run --record` completes within the same CI build**, so the run it should
report on already exists.

As it runs, the helper logs its progress to the console so you can follow along
in your CI logs:

```shell
Cypress found run #68086 (https://cloud.cypress.io/projects/ypt4pf/runs/68086) associated with this CI workflow.
Cypress is fetching the UI Coverage report for run #68086.
Cypress found a UI Coverage report for run #68086 that is still processing. 8 of 12 specs have been processed. Cypress will fetch again in 30 seconds [Attempt 1 of 30]
Cypress found a UI Coverage report for run #68086 (https://cloud.cypress.io/projects/ypt4pf/runs/68086/ui-coverage).
```

A run must also meet a few conditions before a report can be found, including
Test Replay being enabled and a supported Cypress version. See the
[Results API FAQ](/ui-coverage/faq#Results-API-and-CI) for the full list.

## Supported CI providers at a glance

The Results API supports the following CI providers:

- <Icon name="microsoft" inline="true" /> Azure
- <Icon name="cog" inline="true" /> CircleCI
- <Icon name="github" inline="true" /> GitHub Actions
- <Icon name="gitlab" inline="true" /> GitLab
- <Icon name="jenkins" inline="true" /> Jenkins
- <Icon name="aws" inline="true" /> AWS CodeBuild
- <Icon name="cog" inline="true" /> Drone
- <Icon name="bitbucket" inline="true" /> Bitbucket
- <Icon name="cog" inline="true" /> Buildkite

For other CI providers, contact Cypress Support at support@cypress.io to request
support.

## Installation

Install the `@cypress/extract-cloud-results` module in your install step in CI.

<PackageManagerTabs
  install="--force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz"
  exclude="bun"
/>

:::caution

Do not check this module in as a dependency. We recommend you install it
separately, outside of your normal module installation, and use `--force` to
get the latest version.

The `v1` in the URL is the major-version line. Installing with `--force` always
fetches the latest `1.x` release, so you receive fixes and improvements without
changing the URL.

:::

## Usage

### Write your verification script

Write a script to fetch UI Coverage results and assert your coverage criteria.
This script runs in CI.

#### Basic example

This snippet uses the `getUICoverageResults()` helper to log out the results. It
assumes your Project ID and Record Key are set as environment variables. It
works in any of the supported CI providers out of the box:

```javascript title="scripts/verifyUICoverageResults.js"
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults()
  .then((results) => {
    // use `console.dir` instead of `console.log` because the data is nested
    console.dir(results, { depth: Infinity })
  })
  .catch((error) => {
    console.error(error.message)
    process.exit(1)
  })
```

Once you can read the results, add your own logic to act on them. See
[Examples](#Examples) for a worked script behind each supported use case, from
enforcing thresholds to reporting on the pull request.

### `getUICoverageResults` reference

The arguments the helper accepts, the data it returns, and how it behaves on
errors.

#### Arguments

`getUICoverageResults` accepts the following arguments:

```javascript
getUICoverageResults({
  // The Cypress project ID.
  // Optional if the CYPRESS_PROJECT_ID env var is set.
  projectId: string
  // The project's record key.
  // Optional if the CYPRESS_RECORD_KEY env var is set.
  recordKey: string
  // The run tags associated with the run.
  // Required IF you record multiple Cypress runs from a single CI build.
  // Pass the same tags you used when recording each run.
  // Optional if the CYPRESS_RUN_TAG env var is set. That variable holds a
  // single tag only (it is not comma-separated), so pass runTags directly
  // when a run carries more than one tag.
  runTags: string[]
})
```

#### Result properties

`getUICoverageResults` resolves with the following data. A **link** is a navigable
anchor that points at another view; **elements** are the other interactive
controls. Both count toward the coverage score, but the counts below report them
separately, so `testedElementsCount` plus `untestedElementsCount` is **not** the
score's denominator. Add the link counts to reconstruct it.

```javascript
{
  runNumber: number
  runUrl: 'https://cloud.cypress.io/projects/:project_id/runs/:run_number'
  runStatus: 'passed' | 'failed' | 'errored' | 'timedOut' | 'cancelled' | 'noTests' | 'running' | 'overLimit'
  uiCoverageReportUrl: 'https://cloud.cypress.io/[...]'
  summary: {
    // Whether a complete UI Coverage report was generated.
    // For example, if a run was cancelled and the report was expected to
    // cover 20 specs but only 10 ran, this would be a partial report.
    isPartialReport: boolean
    // The report coverage from 0-100 with 2-decimal precision (e.g. 92.45).
    coverage: number
    viewCount: number
    testedElementsCount: number
    untestedElementsCount: number
    testedLinksCount: number
    untestedLinksCount: number
  }
  views: [{
    // The sanitized URL pattern shown in the report.
    displayName: string
    // The view coverage from 0-100 with 2-decimal precision (e.g. 92.45).
    coverage: number
    testedElementsCount: number
    untestedElementsCount: number
    testedLinksCount: number
    untestedLinksCount: number
    uiCoverageReportUrl: 'https://cloud.cypress.io/[...]'
  }]
  // The App Quality configuration used for this report.
  // Present when configuration exists for the project.
  config: {
    // ISO 8601 timestamp of when the configuration was last updated.
    updatedAt: string
    // The App Quality configuration saved for the project when this report was processed.
    value: object
  }
}
```

An example of a returned result:

```javascript
{
  runNumber: 68086,
  runUrl: 'https://cloud.cypress.io/projects/ypt4pf/runs/68086',
  runStatus: 'passed',
  uiCoverageReportUrl:
    'https://cloud.cypress.io/projects/ypt4pf/runs/68086/ui-coverage',
  summary: {
    isPartialReport: false,
    coverage: 87.42,
    viewCount: 12,
    testedElementsCount: 145,
    untestedElementsCount: 21,
    testedLinksCount: 34,
    untestedLinksCount: 8,
  },
  views: [
    {
      displayName: '/checkout',
      coverage: 94.12,
      testedElementsCount: 32,
      untestedElementsCount: 2,
      testedLinksCount: 5,
      untestedLinksCount: 0,
      uiCoverageReportUrl:
        'https://cloud.cypress.io/projects/ypt4pf/runs/68086/ui-coverage/view/a1b2c3d4e5f60718',
    },
    {
      displayName: '/products/*',
      coverage: 78.95,
      testedElementsCount: 15,
      untestedElementsCount: 4,
      testedLinksCount: 9,
      untestedLinksCount: 3,
      uiCoverageReportUrl:
        'https://cloud.cypress.io/projects/ypt4pf/runs/68086/ui-coverage/view/9f8e7d6c5b4a3021',
    },
  ],
  config: {
    updatedAt: '2026-05-14T18:22:03.000Z',
    value: {
      /* App Quality Config, see below */
    },
  },
}
```

#### Reading the applied configuration

The `config` property returns the **App Quality Config** saved for your project when this report was processed, including the full `profiles` array.

:::caution

`config.value` is **not** resolved against the run's tags. If a
[Profile](/ui-coverage/configuration/profiles) applied to this run, `config.value`
still shows the base configuration plus the profile definitions, not the merged
result. If you need to determine which profile applied, match the run's tags against the
`name` of each entry in `config.value.profiles`. Reach out to your Cypress point-of-contact
or use the in-product feedback buttons if you need more than the current functionality.

:::

```json title="App Quality Config"
{
  "viewFilters": [{ "pattern": "/admin/*", "include": false }],
  "uiCoverage": {
    "elementFilters": [{ "selector": ".cookie-banner *", "include": false }]
  },
  "profiles": [
    {
      "name": "production",
      "config": {
        "viewFilters": [{ "pattern": "/internal/*", "include": false }]
      }
    }
  ]
}
```

#### Handling errors

`getUICoverageResults` returns a promise that rejects with a descriptive
`Error` when it can't return results. For example, this happens when no
matching run is found for the CI context, when the run was recorded with Test
Replay disabled,
or when the report is still processing after the poll window elapses. Decide
whether that should fail your build (let the rejection surface, as in the
examples above) or be tolerated (catch it and exit cleanly), depending on how
strict you want the check to be.

```javascript title="scripts/verifyUICoverageResults.js"
getUICoverageResults()
  .then((results) => {
    // assert against results
  })
  .catch((error) => {
    console.error(`Could not verify UI Coverage results: ${error.message}`)
    // Fail the build...
    process.exit(1)
    // ...or treat the check as non-blocking by returning without a non-zero exit.
  })
```

### Add the verification step to CI

In the CI workflow that runs your Cypress tests:

1. Update your install step to install the `@cypress/extract-cloud-results` module.
2. Pass any necessary arguments to `getUICoverageResults`.
3. Add a step, after your Cypress run, that executes your verification script.

#### Example workflow updates

<Tabs groupId="ui-cov-results-api">
<TabItem value="GitHub Actions" active>

```diff title="test_cypress.yaml"
name: My Workflow
on: push

env:
  CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}

jobs:
  run-tests:
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout
        uses: actions/checkout@v7
      - name: install
        run: npm install
      - name: Run Cypress tests
        run: npx cypress run --record
+     - name: Get Cypress UI Coverage
+       run: |
+          npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+          node ./scripts/verifyUICoverageResults.js
```

</TabItem>

<TabItem value="GitLab">

```diff title=".gitlab-ci.yml"
image: node:latest

stages:
  - test

run-tests:
  stage: test
  secrets:
    CYPRESS_RECORD_KEY:
      vault: vault/cypressRecordKey
  script:
    - npm install
    - npx cypress run --record
+   - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+   - node ./scripts/verifyUICoverageResults.js
```

</TabItem>

<TabItem value="Jenkins">

```diff title="Jenkinsfile"
pipeline {
  agent {
    docker {
      image 'cypress/base:22.15.0'
    }
  }

  environment {
    CYPRESS_PROJECT_ID = 'xxxx'
    CYPRESS_RECORD_KEY = credentials('cypress-record-key')
  }

  stages {
    stage('Run Cypress tests') {
      steps {
        sh 'npm ci'
        sh 'npx cypress run --record'
      }
    }

+   stage('Get Cypress UI Coverage') {
+     steps {
+       sh 'npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz'
+       sh 'node ./scripts/verifyUICoverageResults.js'
+     }
+   }
  }
}
```

</TabItem>

<TabItem value="Azure">

```diff title="azure-pipelines.yml"
jobs:
  - job: run_tests
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - task: NodeTool@0
        inputs:
          versionSpec: '22.x'
          displayName: 'Install Node.js'

      - script: npm i
        displayName: 'Install npm dependencies'

      - script: npx cypress run --record
        displayName: 'Run Cypress tests'
        env:
          # avoid warnings about terminal
          TERM: xterm
          CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY)

+     - script: |
+           npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+           node ./scripts/verifyUICoverageResults.js
+       displayName: 'Get Cypress UI Coverage'
+       env:
+         CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID)
+         CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY)
```

</TabItem>

<TabItem value="CircleCI">

```diff title=".circleci/config.yml"
version: 2.1

jobs:
  run-tests:
    docker:
      - image: cypress/base:22.15.0

    working_directory: ~/repo
    steps:
      - checkout
      - run: npm install
      - run: npx cypress run --record
+     - run: npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+     - run: node ./scripts/verifyUICoverageResults.js

workflows:
  version: 2
  tests:
    jobs:
      - run-tests
```

</TabItem>

<TabItem value="AWS CodeBuild" >

```diff title="buildspec.yaml"
phases:
  install:
    runtime-versions:
      nodejs: latest
    commands:
      # Set COMMIT_INFO variables to send Git specifics to Cypress Cloud when recording
      # https://docs.cypress.io/app/continuous-integration/overview#Git-information
      - export COMMIT_INFO_BRANCH="$(git rev-parse HEAD | xargs git name-rev |
        cut -d' ' -f2 | sed 's/remotes\/origin\///g')"
      - export COMMIT_INFO_MESSAGE="$(git log -1 --pretty=%B)"
      - export COMMIT_INFO_EMAIL="$(git log -1 --pretty=%ae)"
      - export COMMIT_INFO_AUTHOR="$(git log -1 --pretty=%an)"
      - export COMMIT_INFO_SHA="$(git log -1 --pretty=%H)"
      - export COMMIT_INFO_REMOTE="$(git config --get remote.origin.url)"
      - npm ci
  pre_build:
    commands:
      - npm run cypress:verify
  build:
    commands:
      - CYPRESS_PROJECT_ID=[slug] npx cypress run --record --key [KEY]
+  post_build:
+    commands:
+      - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+      - CYPRESS_PROJECT_ID=[slug] CYPRESS_RECORD_KEY=[KEY] node ./scripts/verifyUICoverageResults.js
```

</TabItem>

<TabItem value="Drone" >

```diff title=".drone.yml"
kind: pipeline
name: default

steps:
  - name: Run Cypress tests
    image: node:latest
    commands:
      - npm install
      - npx cypress run --record

+  - name: Get Cypress UI Coverage
+    image: node:latest
+    commands:
+      - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+      - node ./scripts/verifyUICoverageResults.js
```

</TabItem>

<TabItem value="Bitbucket" >

```diff title="bitbucket-pipelines.yml"
image: node:latest

pipelines:
  default:
    - step:
        name: Run Cypress tests
        script:
          - npm install
          - npx cypress run --record
+         - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+         - node ./scripts/verifyUICoverageResults.js
```

</TabItem>

<TabItem value="Buildkite" >

```diff title="pipeline.yml"
steps:
  - label: "Run Cypress tests"
    command:
      - npm install
      - npx cypress run --record
+     - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+     - node ./scripts/verifyUICoverageResults.js
```

</TabItem>
</Tabs>

### Recording multiple runs in one CI build

If you record multiple runs in a single CI build, you must record each run with
the `--tag` parameter and then call `getUICoverageResults` with the matching
`runTags` argument for each run. This is how each run is uniquely identified so
the correct results are returned. Tags can also activate
[Profiles](/ui-coverage/configuration/profiles) that apply different
configuration to different runs.

For example, imagine that within a single CI build you call
`cypress run --record` twice, once against a `staging` environment and once
against `production`.

Pass a different `--tag` to each Cypress run:

<CypressCommandTabs
  command={'run --record --tag staging\nrun --record --tag production'}
/>

When calling `getUICoverageResults`, pass the same tags to get the results for
each run:

```javascript
getUICoverageResults({ runTags: ['staging'] })
getUICoverageResults({ runTags: ['production'] })
```

## Examples

Each example below assumes you have written a script that calls
`getUICoverageResults` and wired it into CI.

### Enforce coverage thresholds

Fail the build when overall coverage drops below a floor, and hold critical
flows like login and checkout to a higher standard:

```javascript title="scripts/verifyUICoverageResults.js"
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults({
  projectId: process.env.CYPRESS_PROJECT_ID, // optional if set from env
  recordKey: process.env.CYPRESS_RECORD_KEY, // optional if set from env
  runTags: ['production'], // required if recording multiple runs in one CI build
}).then((results) => {
  const { runNumber, uiCoverageReportUrl, summary, views } = results

  console.log(
    `Received ${summary.isPartialReport ? 'partial ' : ''}results for run #${runNumber}.`
  )
  console.log(`See the full report at ${uiCoverageReportUrl}`)

  // Fail the build if overall coverage is below 80%.
  if (summary.coverage < 80) {
    throw new Error(
      `Project coverage is ${summary.coverage}%, below the minimum threshold of 80%.`
    )
  }

  // Hold critical flows to a higher standard.
  const criticalViews = [/login/, /checkout/]

  views.forEach((view) => {
    const { displayName, coverage, uiCoverageReportUrl } = view

    if (
      criticalViews.some((pattern) => pattern.test(displayName)) &&
      coverage < 95
    ) {
      throw new Error(
        `Critical view "${displayName}" coverage is ${coverage}%, below the required 95%. See: ${uiCoverageReportUrl}`
      )
    }
  })

  console.log('UI Coverage meets all thresholds.')
})
```

### Report coverage on the pull request

Every result carries the coverage numbers and deep-link report URLs, so you can
surface a summary where your team reviews code instead of only passing or
failing. This example writes a Markdown summary that GitHub Actions renders on
the job:

```javascript title="scripts/reportUICoverage.js"
const fs = require('fs')
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults().then(({ summary, views, uiCoverageReportUrl }) => {
  const rows = views
    .map((view) => `| ${view.displayName} | ${view.coverage}% |`)
    .join('\n')

  const markdown = `## UI Coverage: ${summary.coverage}%

[View the full report](${uiCoverageReportUrl})

| View | Coverage |
| ---- | -------- |
${rows}`

  fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, markdown)
})
```

### Fail on untested navigation links

UI Coverage reports links (navigable anchors that point at another view)
separately from other interactive elements, though both count toward your score. Use the link counts to catch pages that have user-facing links rendered in Cypress tests, but are never visited:

```javascript title="scripts/checkUntestedLinks.js"
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults().then(({ summary, views }) => {
  if (summary.untestedLinksCount === 0) {
    return
  }

  console.log(
    `${summary.untestedLinksCount} linked page(s) were never visited:`
  )
  views
    .filter((view) => view.untestedLinksCount > 0)
    .forEach((view) => {
      console.log(
        `  ${view.displayName}: ${view.untestedLinksCount} untested link(s)`
      )
    })

  throw new Error(
    'New navigation paths are untested. Add tests that follow them.'
  )
})
```

### Track coverage trends over time

A baseline compares one run to one prior run. To trend coverage across many runs
and teams, push each run's numbers to a dashboard or data warehouse:

```javascript title="scripts/trackCoverageTrends.js"
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults().then(({ runNumber, summary }) => {
  const metrics = {
    runNumber,
    coverage: summary.coverage,
    testedElements: summary.testedElementsCount,
    untestedElements: summary.untestedElementsCount,
    viewCount: summary.viewCount,
  }

  // Send to your metrics service, warehouse, or observability tool.
  return fetch('https://metrics.example.com/ui-coverage', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(metrics),
  })
})
```

### Skip enforcement for partial or non-passing runs

A run can be cancelled, time out, or produce a partial report. Check the run
state first so an incomplete run warns instead of failing the build for the
wrong reason:

```javascript title="scripts/skipIncompleteRuns.js"
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

getUICoverageResults().then((results) => {
  const { runStatus, summary } = results

  if (runStatus !== 'passed' && runStatus !== 'failed') {
    console.warn(
      `Run status is "${runStatus}". Skipping UI Coverage enforcement.`
    )
    return
  }

  if (summary.isPartialReport) {
    console.warn('Report is partial. Skipping UI Coverage enforcement.')
    return
  }

  // ...enforce your thresholds here.
})
```

### Assert the configuration

The `config` property returns the App Quality Config that was used to process this run. You can assert that required rules are present so a configuration change doesn't
silently alter what's measured.

If you use config [profiles](/ui-coverage/configuration/profiles) to produce a different config based on run tags, resolve the effective config first: match the run's tags against profile names, then layer the matching profile's `config` over the base configuration, since a profile replaces only the properties it defines.

```javascript title="scripts/assertCoverageConfig.js"
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

// Tags this run was recorded with. CYPRESS_RUN_TAG holds a single tag only;
// pass runTags directly when a run carries more than one.
const RUN_TAGS = process.env.CYPRESS_RUN_TAG
  ? [process.env.CYPRESS_RUN_TAG]
  : []

getUICoverageResults({ runTags: RUN_TAGS }).then(({ config }) => {
  if (!config) {
    throw new Error('No App Quality Config was saved for this run.')
  }

  // The first profile whose name matches a run tag wins.
  const base = config.value
  const activeProfile = (base.profiles ?? []).find((profile) =>
    RUN_TAGS.includes(profile.name)
  )

  // A profile replaces only the properties it defines, and `uiCoverage` and
  // `accessibility` merge one level deep, so layer the profile over the base
  // config rather than reading it on its own.
  const overrides = activeProfile?.config ?? {}
  const effective = {
    ...base,
    ...overrides,
    uiCoverage: { ...base.uiCoverage, ...overrides.uiCoverage },
  }

  const elementFilters = effective.uiCoverage.elementFilters ?? []
  const hasCookieBannerFilter = elementFilters.some((filter) =>
    filter.selector?.includes('cookie-banner')
  )

  if (!hasCookieBannerFilter) {
    throw new Error('Expected the cookie-banner element filter to be applied.')
  }

  console.log(`Configuration last updated ${config.updatedAt}.`)
})
```

### Raise the threshold as coverage improves

Store the last run's coverage and require the next run to meet or beat it, so the
bar rises automatically as coverage improves. Commit the floor file so it travels
with your code:

```javascript title="scripts/raiseCoverageFloor.js"
const fs = require('fs')
const { getUICoverageResults } = require('@cypress/extract-cloud-results')

const FLOOR_FILE = 'ui-coverage-floor.json'
const floor = fs.existsSync(FLOOR_FILE)
  ? JSON.parse(fs.readFileSync(FLOOR_FILE, 'utf8')).coverage
  : 0

getUICoverageResults().then(({ summary }) => {
  if (summary.coverage < floor) {
    throw new Error(
      `Coverage dropped to ${summary.coverage}%, below the previous floor of ${floor}%.`
    )
  }

  fs.writeFileSync(FLOOR_FILE, JSON.stringify({ coverage: summary.coverage }))
})
```

### Compare against a baseline

Comparing untested-element counts against a stored baseline fails a build only
when **new** gaps are introduced, letting you pay down existing gaps over time
instead of blocking on them all at once. For complete code, the baseline
structure, and best practices, see the
[Block pull requests and set policies](/ui-coverage/guides/block-pull-requests#comparing-against-a-baseline)
guide.

## Required CI environment variables

<ResultsApiEnvVars />

## See also

- [Block pull requests and set policies](/ui-coverage/guides/block-pull-requests): set a coverage policy and fail a pull request when it isn't met.
- [Monitor changes](/ui-coverage/guides/monitor-changes): track coverage trends and catch regressions over time.
- [Results API FAQ](/ui-coverage/faq#Results-API-and-CI): quick answers to common Results API and CI questions.
- [Profiles](/ui-coverage/configuration/profiles): apply different configuration to different runs using run tags.

---

### Ui Coverage Troubleshooting (`docs/ui-coverage/troubleshooting.mdx`)

---
title: 'Troubleshooting: UI Coverage'
description: 'Fix common Cypress UI Coverage report problems: duplicate elements, mis-grouped elements, tested elements shown as untested, configuration that has no effect, and unexpected coverage scores.'
sidebar_label: Troubleshooting
sidebar_position: 150
---

<ProductHeading product="ui-coverage" />

# Troubleshooting UI Coverage

UI Coverage produces a report for every recorded run with no setup, and for most applications the defaults are accurate on their own. When a report doesn't match what you expect, the cause is usually one of a small, predictable set: an unstable attribute that splits one control into many, a generic identifier that merges distinct controls, an interaction UI Coverage doesn't recognize, or a configuration change that hasn't been applied to the run yet.

This page maps each symptom to its cause and the configuration that resolves it. Because you can [regenerate](/ui-coverage/configuration/overview#Setting-configuration) any past run with your current configuration, you can confirm every fix in minutes without re-running your Cypress tests, so the fastest path to a coverage score you trust is to make one change, regenerate a recent run, and check the result.

:::tip Start here: regenerate the run after changing configuration

Every run is processed with the configuration that was saved **at that moment**, so edits you make afterward don't change an existing report until you reprocess it. This timing is the single most common reason a rule "doesn't work."

After saving configuration in the **App Quality** tab of your project settings, open a run's **Properties** tab and use its "regenerate" button, or the "configuration updated" message shown on a report processed with older configuration. Every fix on this page assumes you regenerate the run after changing configuration. See [Setting configuration](/ui-coverage/configuration/overview#Setting-configuration).

:::

## One element is reported as many

A single control appears as several separate untested elements, inflating your element count and lowering your score.

**Cause.** UI Coverage recognizes the same element across [snapshots](/ui-coverage/core-concepts/element-identification#Snapshots) by building an [identity](/ui-coverage/core-concepts/element-identification) from its attributes and position in the DOM. When an identifying attribute changes on every render, such as a framework-generated `id`, a hashed class, or a per-request token, each snapshot looks like a new element and the one control is split apart.

UI Coverage already ignores the most common unstable values, including UUIDs and long hexadecimal hashes on any attribute, digit-only `id`, `name`, `for`, and `aria-*` values, and generated class names like `jss*` and `ng-tns-*`. Add configuration only when your application produces unstable identifiers these built-in filters don't cover.

**Fixes.**

- **Ignore the dynamic attribute** with [`attributeFilters`](/ui-coverage/configuration/attributefilters) so UI Coverage falls back to a stable attribute. When you filter a dynamic `id`, also filter the attributes that reference it, such as `for`, `aria-labelledby`, and `aria-describedby`, or the element can still be identified by those related values.

  ```json title="App Quality Config"
  {
    "attributeFilters": [
      {
        "attribute": "id|for|aria-labelledby|aria-describedby",
        "value": ":r.*",
        "include": false,
        "comment": "React useId() values like :r0: are regenerated on every render"
      }
    ]
  }
  ```

- **Pin one specific element's identity** with an [`elements`](/ui-coverage/configuration/elements) rule that identifies it by a selector that stays the same across snapshots. This is the right tool for a single control; if many elements share the same generated attribute, filter the attribute instead.

  ```json title="App Quality Config"
  {
    "uiCoverage": {
      "elements": [
        {
          "selector": "#checkout-form [id^='card-']",
          "name": "Card Number Field"
        }
      ]
    }
  }
  ```

Patterns in `attributeFilters` match the whole value (they're anchored as `^(...)$`, unless your pattern already starts with `^` or ends with `$`), and JSON requires backslashes to be doubled, so a token like `\d` must be written `\\d`. `attribute` is matched **case-insensitively** while `value` is matched **case-sensitively**. See [How rules are applied](/ui-coverage/configuration/attributefilters#How-rules-are-applied).

## Distinct elements are reported as one

Two or more controls that should each be tracked appear as a single element, so testing one marks all of them tested and real gaps are hidden.

**Cause.** The elements resolve to the same identity because their identifying attribute shares a generic value, such as several buttons that all carry `data-test="button"`, or because the attribute that would distinguish them isn't one UI Coverage uses by default.

**Fixes.**

- **Add distinct identifiers** in your application, giving each control its own `data-cy` or `data-test` value. This is the most durable fix.
- **Prefer a distinguishing attribute** your markup already has with [`significantAttributes`](/ui-coverage/configuration/significantattributes). Attributes you list are checked before the defaults, so an attribute whose value differs between the elements gives each a distinct identity. Icon-only controls, for example, are often distinguishable by their `aria-label`.

  ```json title="App Quality Config"
  {
    "significantAttributes": ["aria-label"]
  }
  ```

  Listing `aria-label` also turns the report into an inventory of your label text, where a vague label that passes automated accessibility checks (`aria-label="button"`) stands out next to a clear one (`aria-label="Close dialog"`).

## Similar elements aren't grouped together

Repeated components, such as a row action rendered for every record, appear as many separate untested elements instead of one [group](/ui-coverage/core-concepts/element-grouping), so a single table can dominate your untested list.

**Cause.** Each instance carries a per-instance value in its identifier, such as a database ID in an `id` attribute, so UI Coverage treats the instances as unrelated rather than as one repeated component.

**Fixes.**

- **Ignore the per-instance value** with [`attributeFilters`](/ui-coverage/configuration/attributefilters) so the otherwise-identical elements collapse into one group on their own.

  ```json title="App Quality Config"
  {
    "attributeFilters": [
      {
        "attribute": "id",
        "value": "delete-user-\\d+",
        "include": false,
        "comment": "Row action ids include the per-user database id"
      }
    ]
  }
  ```

- **Force the grouping** with an [`elementGroups`](/ui-coverage/configuration/elementgroups) rule that matches all the instances by a shared selector and names them, which also makes the report readable.

  ```json title="App Quality Config"
  {
    "uiCoverage": {
      "elementGroups": [
        {
          "selector": "[id^='delete-user-']",
          "name": "Delete User Button"
        }
      ]
    }
  }
  ```

- **Group in your markup** by adding the [`data-cy-ui-group` attribute](/ui-coverage/core-concepts/element-grouping#Grouping-with-markup-attributes) to the elements, or to a wrapper around them, when the team that owns the markup also owns the grouping decision. Groups defined this way take priority over `elementGroups` configuration.

## Unrelated elements are grouped together

Controls that do different things are combined into one group, so an interaction with one wrongly marks the others tested.

**Cause.** The elements share an overly generic selector or attribute value, so UI Coverage's automatic grouping or a shared identifying attribute treats them as instances of the same component.

**Fixes.**

- **Add distinct identifiers** so each control resolves to its own identity, which prevents the shared-attribute grouping in the first place.
- **Define the correct split** with [`elementGroups`](/ui-coverage/configuration/elementgroups). A custom group overrides the automatic grouping, so a rule for each action separates controls the heuristics lumped together. List specific rules before broad ones, because the **first** matching rule wins.

  ```json title="App Quality Config"
  {
    "uiCoverage": {
      "elementGroups": [
        {
          "selector": "[data-cy='quick-view']",
          "name": "Quick View Button"
        },
        {
          "selector": "[data-cy='add-to-cart']",
          "name": "Add to Cart Button"
        }
      ]
    }
  }
  ```

## An element you tested is shown as untested

Your test interacts with an element on every run, but the report still lists it as untested.

**Cause.** UI Coverage marks an element tested only when a recognized [interaction command](/ui-coverage/core-concepts/interactivity#Interaction-Commands) targets it. The built-in set is `blur`, `check`, `clear`, `click`, `dblclick`, `focus`, `rightclick`, `scrollIntoView`, `scrollTo`, `select`, `selectFile`, `submit`, `trigger`, `type`, and `uncheck`. Anything outside that set, including your own custom commands and plugin commands such as `cypress-real-events`' `realClick` and `realHover`, doesn't count until you declare it.

**Cause: you used `scrollIntoView`.** That command credits the element's nearest scrollable ancestor rather than the element you called it on, so it usually marks nothing tested. Use `click`, `focus`, or `trigger` on the element instead.

**Fixes.**

- **Count a custom or plugin command everywhere** by adding it to [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands).

  ```json title="App Quality Config"
  {
    "uiCoverage": {
      "additionalInteractionCommands": ["realClick", "realHover"]
    }
  }
  ```

- **Count a command for specific elements**, or **credit an interaction the defaults ignore** such as an `assert` on a read-only badge or total, with [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands).

  ```json title="App Quality Config"
  {
    "uiCoverage": {
      "allowedInteractionCommands": [
        {
          "selector": "[data-cy='order-total']",
          "commands": ["assert"],
          "comment": "This total is only ever validated, never interacted with"
        }
      ]
    }
  }
  ```

Two details often explain a command that still doesn't count. First, a custom command only produces coverage if it logs a [snapshot](/ui-coverage/core-concepts/element-identification#Snapshots) that references the element it acts on, so register it with [`prevSubject`](/api/cypress-api/custom-commands#Arguments) and log the subject as `$el` (see [Requirements for a custom command](/ui-coverage/configuration/additionalinteractioncommands#Requirements-for-a-custom-command)). Second, command names you add are matched **case-sensitively**, exactly as you registered them.

## An element stops counting after you add an allowedInteractionCommands rule

An element that was tested is now reported as untested, right after you added an [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) rule.

**Cause.** Once an element matches a rule, **only** the commands listed in the matching rules count for it, and the default commands no longer apply. If your test exercises the element with a command you didn't list, such as a plain `click`, it's now treated as untested.

**Fix.** Add the command your test actually uses to the rule's `commands` list, or tighten the `selector` so the rule matches only the elements you intended to restrict.

## A configuration rule has no effect

You saved a rule, but the report looks the same.

Work through these causes in order:

- **The run predates the change.** Reports use the configuration saved when they were processed. [Regenerate](/ui-coverage/configuration/overview#Setting-configuration) the run to apply your current configuration. This is by far the most common cause.
- **An earlier rule matched first.** For [`elementFilters`](/ui-coverage/configuration/elementfilters), [`viewFilters`](/ui-coverage/configuration/viewfilters), [`elementGroups`](/ui-coverage/configuration/elementgroups), and [`attributeFilters`](/ui-coverage/configuration/attributefilters), the **first** matching rule wins, so a broad rule above your specific one prevents it from applying. List specific rules first, and place `include: true` exceptions before the `include: false` rule they should override. ([`elements`](/ui-coverage/configuration/elements) is the exception: when several rules match one element, the **last** one wins.).
- **A nested list replaced a root one.** Nesting a shared property such as `elementFilters` or `attributeFilters` under a `uiCoverage` or `accessibility` key **completely replaces** the root-level list for that product; the two are never merged. Repeat any root rules you still want in the nested list. See [Configuration scope](/ui-coverage/configuration/overview#Configuration-scope).
- **The property is in the wrong place.** `elementGroups`, `elements`, `additionalInteractionCommands`, and `allowedInteractionCommands` are UI Coverage–only and must live under the `uiCoverage` key, while `views` is set at the root. A misplaced property is rejected by the schema.
- **The pattern or selector doesn't match.** `attributeFilters` patterns are anchored to the whole value, so `value: "user"` matches only the exact string `user`; use `value: "user-.*"` for a prefix. Selectors in `elementFilters`, `elements`, and `elementGroups` must match the interactive element itself, not a wrapper around it, so `footer` matches only the `<footer>`, while `footer *` matches the controls inside it.
- **The configuration didn't save.** Cypress Cloud validates against a strict schema and rejects any property it doesn't recognize, including a misspelled name, a value of the wrong type, or a freeform note on a field that doesn't accept one. Keep notes in a [`comment`](/ui-coverage/configuration/overview#Comments), and correct the flagged property so the configuration can save.

## The coverage score looks wrong

Your score is lower than the state of your tests suggests.

**Cause.** The score compares tested interactive elements to the total, and a few sources of untested elements commonly drag it down without pointing to a real gap in your suite:

- **Third-party widgets.** Chat launchers, cookie banners, and analytics overlays are interactive elements your team doesn't own, and each counts as untested.
- **Untested links.** A link to a page no test visits, including your own help center, marketing pages, and entirely external sites, counts against your score as an [untested link](/ui-coverage/core-concepts/interactivity#Untested-Links), even though no view exists for it.
- **Duplicated elements.** One control split into many by an unstable attribute (see [One element is reported as many](#One-element-is-reported-as-many)) adds untested elements that are really the same control.

**Fixes.**

- **Remove third-party elements** with [`elementFilters`](/ui-coverage/configuration/elementfilters), which drops them from the report and the score.

  ```json title="App Quality Config"
  {
    "elementFilters": [
      {
        "selector": ".intercom-launcher",
        "include": false,
        "comment": "Third-party chat widget, not part of our tested UI"
      }
    ]
  }
  ```

- **Exclude destinations you don't intend to test** with [`viewFilters`](/ui-coverage/configuration/viewfilters), which also removes the links that point to them.

  ```json title="App Quality Config"
  {
    "viewFilters": [
      {
        "pattern": "https://status.my-app.com/*",
        "include": false,
        "comment": "External status page, linked from the footer but out of scope"
      }
    ]
  }
  ```

To keep only your own application's URLs, list `include: true` rules for them followed by a catch-all `{ "pattern": "*", "include": false }`. Because the first matching rule wins, the catch-all must come last. See [Include only your application's URLs](/ui-coverage/configuration/viewfilters#Include-only-your-applications-URLs).

## Still stuck?

- The [UI Coverage FAQ](/ui-coverage/faq) answers focused questions about scores, views, grouping, identification, interaction commands, and profiles.
- Each configuration page has its own troubleshooting and "How rules are applied" section: [`attributeFilters`](/ui-coverage/configuration/attributefilters), [`elementFilters`](/ui-coverage/configuration/elementfilters), [`elementGroups`](/ui-coverage/configuration/elementgroups), [`elements`](/ui-coverage/configuration/elements), [`viewFilters`](/ui-coverage/configuration/viewfilters), [`views`](/ui-coverage/configuration/views), and [`profiles`](/ui-coverage/configuration/profiles).
- The [Configuration overview](/ui-coverage/configuration/overview) covers where configuration lives, how rules are applied, and how to regenerate reports.
- If a report still looks wrong after working through this page, reach out to your Cypress point of contact with a link to the run.

---

### Ui Coverage Work With Ai Agents (`docs/ui-coverage/work-with-ai-agents.mdx`)

---
title: Use AI agents with UI Coverage
description: 'Use AI agents with UI Coverage and Cypress Cloud MCP to pull coverage scores and untested elements from recorded runs and turn gaps into drafted tests.'
sidebar_label: Work with AI agents
sidebar_position: 110
---

<ProductHeading product="ui-coverage" />

# Work with AI agents

UI Coverage gives your AI agent the grounded context it needs to improve your tests. For every recorded Cypress run, it reports which interactive elements and links your tests exercised, assigns a coverage score to each view, and names the exact untested controls to go after. It's all built from what really ran in the browser during [Test Replay](/cloud/features/test-replay), and filtered through your configuration to focus on what already matters to you. Working from that report, an agent can find real coverage gaps and write tests that target them, rather than guessing at your app's structure.

## What an AI agent can do with UI Coverage

Connected to your UI Coverage report, an agent can turn coverage gaps into concrete testing work:

- **Turn "coverage dropped" into a work list**: which views regressed, which elements are newly untested, and where the risk is concentrated.
- **Prioritize missing scenarios**: comparing missing coverage with your currently-tested user journeys can put the gaps in context.
- **Draft tests for untested elements**, and suggest the existing spec file that's the best home for them.
- **Correlate gaps with ownership**: group untested areas by team, feature, or route so the right people get the right list.
- **Backfill incrementally**: sequence the work from highest-risk to lowest instead of dumping every control on every page.
- **Configure with intent**: generate the configuration needed to ignore or group elements to remove a gap.

Your team still decides what "enough coverage" means for each area. The agent handles the triage, drafting, and bookkeeping around that judgment.

## Quickstart

Three steps to your first useful result:

1. **Connect the MCP.** Add Cypress Cloud MCP to your AI client by following [Configuring the Cloud MCP](/cloud/integrations/cloud-mcp#Configuring-the-Cloud-MCP).
2. **Ask for the riskiest view.** Prompt: _"Using Cypress Cloud, pull the UI Coverage report for the latest run on this branch and list the untested elements on the riskiest view."_
3. **Act on one gap.** Have the agent [draft a test](#Prompts-to-plan-and-draft-tests) for one of those elements, review the diff, and run it.

The rest of this page deepens each step: better prompts, report tuning, and how to keep the score honest.

## Query UI Coverage with Cypress Cloud MCP

Prompt your agent in natural language, and it selects the right tool for you.

### UI Coverage MCP tools

An agent connected to Cloud MCP can call these UI Coverage tools, choosing them based on your prompt.

| Tool                               | What it returns                                                                                                                                              |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cypress_get_ui_coverage_report`   | A run's high-level report: overall coverage score, tested and untested element and link counts, and the top 5 riskiest views (most untested elements first). |
| `cypress_get_ui_coverage_views`    | Paginated views for a run, sorted by most untested elements and links. Use it to browse past the top 5 in the report summary.                                |
| `cypress_get_ui_coverage_elements` | Paginated interactive elements for a run. Filter by tested or untested, and optionally scope to a single view by name.                                       |

These tools are read-only: they retrieve data and can't change your configuration, tests, or runs. Access is scoped to the projects your Cypress Cloud user can already see. For availability, limits, and security details, see the [Cloud MCP reference](/cloud/integrations/cloud-mcp).

### How to prompt effectively

A few habits make every prompt land better:

- **Say "Cypress Cloud"** so the agent reaches for the MCP tools instead of guessing.
- **Name the run** with a branch, commit, or run URL, so the agent reads the report you mean.
- **Start with the riskiest view** and work one view at a time, rather than the whole app at once.
- **Ask for a plan or a diff** before any file changes, so you review intent before code lands.
- **Use your own view names and paths.** The examples below are patterns to adapt, not literal values; swap in the views, flows, and folders from your app.

## Prompts to summarize and triage coverage

Point the agent at a run and ask it to summarize where the risk is.

<CopyPrompt
  title="Summarize coverage for a run"
  subtext="Pull the UI Coverage report for the latest run and surface the riskiest view."
  prompt={`Using Cypress Cloud, pull the UI Coverage report for the latest run on this branch. Give me the overall coverage score, the views with the most untested elements, and the specific untested elements on the riskiest view.`}
>

### Summarize coverage for a run

</CopyPrompt>

<CopyPrompt
  title="Find where new tests belong"
  subtext="List the untested elements on a view and suggest which spec should cover them."
  prompt={`Get UI Coverage report for the latest run on this branch. Pick the riskiest view, list its untested interactive elements, and suggest which existing spec file is the best place to add a test that exercises them.`}
>

### Find where new tests belong

</CopyPrompt>

<CopyPrompt
  title="Assess release readiness"
  subtext="Get a go/no-go on your critical flows, with the exact gaps blocking each one."
  prompt={`Using Cypress Cloud MCP, get the UI Coverage report for the latest run on this branch. For the views behind our most critical user flows, give me each view's coverage score and its untested interactive elements. Then give me a go/no-go: flag any critical view below our threshold (say 80%) and list the specific gaps blocking it.`}
>

### Assess release readiness

</CopyPrompt>

<CopyPrompt
  title="Report coverage progress over a sprint"
  subtext="Summarize how coverage moved across recent runs into a shareable status update."
  prompt={`Using Cypress Cloud MCP, compare UI Coverage across the last 10 runs on main. Summarize how coverage moved over the sprint: the net score change, the views that improved the most, and the views that regressed. Format it as a short status update I can share with the team.`}
>

### Report coverage progress over a sprint

</CopyPrompt>

## Prompts to plan and draft tests

Once the agent can read the report, ask it to produce a plan or a change rather than a summary.

<CopyPrompt
  title="Plan the coverage backfill"
  subtext="Turn untested elements into a risk-ordered, incremental test plan."
  prompt={`Using Cypress Cloud MCP, get UI Coverage for the latest run on our main branch. Build a backfill plan that groups untested elements by view, orders the views from most to least risky, and proposes small, reviewable batches of tests, starting with the views most critical to our users.`}
>

### Plan the coverage backfill

</CopyPrompt>

<CopyPrompt
  title="Write a Markdown test plan"
  defaultCollapsed
  subtext="Turn untested elements, links, and views into a Markdown test plan, prioritized against your PRD."
  prompt={`Using Cypress Cloud MCP, get the untested interactive elements, untested links, and riskiest views for the latest run on this branch. Write a Markdown test plan grouped by view: for each untested element or link, add a row with the user action to perform and the expected result. Then cross-reference our product requirements document (PRD) and move the flows it marks as required to the top of the plan.`}
>

### Write a Markdown test plan

</CopyPrompt>

<CopyPrompt
  title="Open a ticket for each untested area"
  defaultCollapsed
  subtext="Turn each view's gaps into a ready-to-file ticket, grouped by view."
  prompt={`Using Cypress Cloud MCP, group the untested interactive elements by view for the latest run on main. For each view with meaningful gaps, draft a ticket with a title, the list of untested elements, the user-facing risk, and a suggested test approach. If you have access to our issue tracker, create one ticket per view and link them under an epic; otherwise output them as Markdown I can paste in.`}
>

### Open a ticket for each untested area

</CopyPrompt>

<CopyPrompt
  title="Diff coverage between two branches"
  defaultCollapsed
  subtext="Compare two branches' coverage scores and diff their untested elements to catch regressions or gains."
  prompt={`Using Cypress Cloud MCP, get the UI Coverage report for the latest run on this branch and for the latest run on main. Compare the overall coverage scores, then diff the untested interactive elements and links between the two runs: list what became untested on this branch (regressions) and what is now covered (gains), grouped by view. For each regression, point me to the spec or app change most likely responsible.`}
>

### Diff coverage between two branches

</CopyPrompt>

<CopyPrompt
  title="Draft tests for untested elements"
  subtext="Draft focused tests for untested elements on a view, diff-first."
  prompt={`You are a Cypress test author. Using Cypress Cloud, take the untested elements on the view I'm working on from the latest run. For each, draft a focused test using our existing data-cy selectors and add it to the closest matching spec in our e2e folder. Show me a diff before writing files.`}
>

### Draft tests for untested elements

</CopyPrompt>

<CopyPrompt
  title="Author tests in natural language with cy.prompt"
  defaultCollapsed
  subtext="Cover untested areas by describing each flow in plain language and letting cy.prompt write the Cypress commands."
  prompt={`Using Cypress Cloud, list the untested interactive elements on the riskiest view for the latest run. For each, add a test that uses cy.prompt to drive the flow in natural language: describe the user action to take and what to verify in plain English, and let cy.prompt generate the Cypress commands. Use the Cypress Author skill, if available, to create well-formed prompt steps following best practices. Put the tests in our e2e folder and show me a diff before writing files.`}
>

### Author tests in natural language with cy.prompt

</CopyPrompt>

:::tip

When the agent moves from finding gaps to authoring tests, pair it with [Cypress AI Skills](/app/tooling/ai-skills). The skills teach your AI tool to write Cypress tests the way an experienced Cypress engineer would, following best practices and matching your project's conventions.

:::

To align risk with real-world usage, combine coverage data with your own analytics:

<CopyPrompt
  title="Prioritize gaps by traffic and risk"
  subtext="Cross-reference page traffic with coverage to prioritize backfill."
  prompt={`Here is a CSV of our most-visited pages from analytics. Cross-reference it with the latest UI Coverage report from Cypress Cloud to build a risk matrix where high-traffic pages with low coverage rank highest. Turn the top of that matrix into an incremental backfill plan.`}
>

### Prioritize gaps by traffic and risk

</CopyPrompt>

Coverage data also points the other way, at tests you can safely trim:

<CopyPrompt
  title="Trim over-tested UI"
  defaultCollapsed
  subtext="Find elements your tests hit far more than needed and suggest redundant tests to cut."
  prompt={`Using Cypress Cloud MCP, list the tested interactive elements for the latest run on main, sorted by interaction count. Flag elements interacted with far more than their importance warrants (for example a nav link exercised by dozens of tests), and suggest which redundant tests we could consolidate or remove to speed up the suite without losing meaningful coverage.`}
>

### Trim over-tested UI

</CopyPrompt>

## Tune reports for better agent results

Agents produce better work from reports that already reflect what your team cares about. The same [configuration](/ui-coverage/configuration/overview) that sharpens reports for human review also sharpens the context an agent reads over MCP.

A few high-value changes make the report sharper for both people and agents:

- **Remove noise and stabilize identity** so the agent reads clean element names instead of third-party clutter or the same button counted many ways. Filter out widgets you don't own, [promote a stable attribute](/ui-coverage/configuration/significantattributes) your app already renders, and [group](/ui-coverage/configuration/elementgroups) repeated controls so they count once.
- **Count the interactions that reflect real usage** so coverage isn't understated where your suite drives the UI through plugin or [custom commands](/ui-coverage/configuration/additionalinteractioncommands).
- **Scope the report to the runs your agent triages** with [`profiles`](/ui-coverage/configuration/profiles), so a smoke run and a full regression run each read the configuration that fits them.

See the [configuration overview](/ui-coverage/configuration/overview) to get started. The goal is the same as for human review: a high-signal list of views and elements tied to ownership and critical flows, not an exhaustive list of every control on every page.

You can also let the agent draft that configuration for you. It reads the untested elements over MCP, spots the noise, and hands back rules to paste into your App Quality Config. To review the configuration a run actually used before changing it, open the run's **Properties** tab or read the `config` property from the [Results API](/ui-coverage/results-api).

<CopyPrompt
  title="Draft configuration to cut noise"
  defaultCollapsed
  subtext="Have the agent read the untested elements and propose App Quality Config rules that remove noise."
  prompt={`First read https://docs.cypress.io/ui-coverage/configuration/overview.md for the App Quality configuration reference. Then use Cypress Cloud MCP to list the untested interactive elements for the latest run on this branch, flag third-party widgets and controls split apart by dynamic attributes, and propose App Quality Config rules (elementFilters, attributeFilters, elementGroups) to remove that noise. Show the JSON I can paste into the App Quality tab.`}
>

### Draft configuration to cut noise

</CopyPrompt>

## Keep coverage honest

Coverage measures whether your tests _touch_ an element, not whether they confirm the desired behavior. An agent told to raise the score can write tests that click everything and assert nothing, so it's important to ground your coverage in the scenarios and outcomes that matter.

Ensure tests include assertions about the state of the application and the readiness of the DOM for the next step of the test.

:::info

For areas where assertions on non-interactive elements are critical to track, your code can use the [`data-cy-ui-interactive`](/ui-coverage/core-concepts/interactivity#Overriding-interactive-elements-with-data-cy-ui-interactive) attribute to bring those elements into your coverage report.

Combine this with [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) configuration to allow assertions to count as coverage for those elements. This adds an extra layer of guidance for your agent about what must be included in your tests.

:::

Keep a person in the loop wherever judgment matters:

- **Intent.** Confirm the drafted test verifies the right behavior, not just that an element was interacted with.
- **What's worth testing.** Agents target trivial controls as eagerly as critical ones. You decide which gaps matter.
- **Selectors.** When your app lacks stable `data-*` attributes, agent-written selectors can be brittle. Add `data-cy` attributes rather than accept fragile ones, or have the agent author the test with [`cy.prompt`](/api/commands/prompt), whose selectors self-heal as your app changes.
- **Intentional drops.** A coverage decrease after removing a test is correct. Don't let an agent "fix" it by re-adding the test; instead, filter out the elements you do not intend to cover with tests.

## Review and enforce coverage

Treat unexpected coverage movement as a quality gate, not noise to wave through, and wire that gate into your workflow so regressions surface before they merge:

- Use [Branch Review](/ui-coverage/guides/compare-reports) to see exactly what changed between two runs: new untested elements, new links, and newly interactive parts of the app.
- Use [monitoring and the Results API](/ui-coverage/guides/monitor-changes) to track trends and wire coverage checks into CI.
- Use [blocking flows](/ui-coverage/guides/block-pull-requests) when you need explicit thresholds or baselines before a merge.

An agent can draft tests, propose spec placement, and narrate diffs, but these gates keep a human in control of what merges. The signal that it is genuinely helping is your coverage score trending up across runs, which you can watch through [monitoring and analytics](/ui-coverage/guides/monitor-changes).

## Generate tests directly from the report

Prefer not to wire up an agent at all? Cypress Cloud can write the test for you. Select an untested element in a UI Coverage report and click **Generate test code**, and [UI Coverage Test Generation](/ui-coverage/guides/address-coverage-gaps#Generate-tests-from-UI-Coverage-reports) drafts a Cypress test that navigates to the element and interacts with it, following your existing patterns.

<DocsImage
  src="/img/ui-coverage/guides/cypress-ui-coverage-generate-test.png"
  alt="Cypress Cloud showing a generated Cypress test after clicking Generate test code for an untested link in a UI Coverage report."
/>

## Standardize across your team

These workflows pay off most when everyone gets the same results, not just one power user:

- **Save your best prompts.** Once a prompt works, store it as a reusable skill or custom instruction in your AI client so the whole team runs the same play.
- **Make it a habit in the repo.** Add a project rule to your agent's instructions file, such as "before adding tests, check UI Coverage for the affected view and cover the highest-risk gaps first."
- **Focus the report.** Cypress Cloud projects share one [App Quality configuration](/ui-coverage/configuration/overview) so every teammate's agent reads the same high-signal report. Use [`profiles`](/ui-coverage/configuration/profiles) to customize the config for different kinds of runs or different team ownership within a large project.

## See also

- [Cloud MCP: Agentic debugging](/cloud/integrations/cloud-mcp): setup, available tools, limits, and security.
- [UI Coverage FAQ](/ui-coverage/faq#Using-AI-agents-with-Cypress-UI-Coverage): answers to common questions about using agents with UI Coverage.
- [Configuration overview](/ui-coverage/configuration/overview): every option for shaping your reports.
- [Cypress AI Skills](/app/tooling/ai-skills): teach your AI tool to author Cypress tests following best practices.
- [UI Coverage Test Generation](/ui-coverage/guides/address-coverage-gaps#Generate-tests-from-UI-Coverage-reports): generate a Cypress test for an untested element directly from the report.

---

### Accessibility Configuration Attributefilters (`docs/accessibility/configuration/attributefilters.mdx`)

---
title: 'attributeFilters: control element identification in Cypress Accessibility'
description: 'Use attributeFilters to stop dynamic, auto-generated, or state-based attributes from splitting one element into many or mis-grouping violations in Cypress Accessibility reports.'
sidebar_label: 'attributeFilters'
sidebar_position: 80
---

<ProductHeading product="accessibility" />

# Ignore attributes for identification - `attributeFilters`

Cypress Accessibility [identifies elements](/ui-coverage/core-concepts/element-identification) from a combination of their attributes and the surrounding DOM structure. Use `attributeFilters` to keep unstable attributes out of that process so violations are grouped against stable targets.

{' '}

<AttributeFilters />

## See also

- [`significantAttributes`](/accessibility/configuration/significantattributes): prioritize the attributes Cypress should prefer as identifiers. This is the complement to filtering out the ones it should ignore.
- [Component attributes](/accessibility/configuration/components): an Accessibility-only option (`componentAttributes` and `componentAttributeFilters`) that shapes which attributes appear in stable violation-target selectors.
- [Element identification](/ui-coverage/core-concepts/element-identification): how elements are identified for both Cypress Accessibility and UI Coverage.
- [Configuration overview](/accessibility/configuration/overview): where to set configuration and regenerate reports.
- [Cypress Accessibility FAQ](/accessibility/faq): common questions and troubleshooting.

---

### Accessibility Configuration Axe Core Configuration (`docs/accessibility/configuration/axe-core-configuration.mdx`)

---
title: 'axeConfig: enable, disable, and scope Axe Core® rules in Cypress Accessibility'
description: 'Use accessibility.axeConfig in App Quality Config to enable or disable Axe Core® rules, or scope a report to WCAG tags.'
sidebar_label: 'axeConfig'
sidebar_position: 50
---

<ProductHeading product="accessibility" />

# Configure Axe Core® rules - `axeConfig`

Cypress Accessibility runs [Axe-Core®](https://github.com/dequelabs/axe-core)'s default ruleset against every snapshot captured during your test run, with no setup, assertions, or `cy.` commands to add to your specs. The ruleset favors high-confidence results, so the report you get out of the box is already the recommended configuration for most teams.

When you need a different ruleset for your project, set `axeConfig` under the `accessibility` key in App Quality Config. You can enable a rule that is off by default, turn off a rule that is a known false positive, or scope the report to the WCAG tags your team measures against. Changes apply the next time a run is processed, and you can [regenerate a past run](/accessibility/configuration/overview#Setting-Configuration) to preview the effect without rerunning your tests.

Because you decide what actually blocks a build with the [Accessibility Results API](/accessibility/connect-and-extend/results-api) or [webhook-driven workflows](/accessibility/connect-and-extend/webhooks), turning rules off only to keep CI green is unnecessary. Leaving a rule reported but non-blocking keeps full visibility into every finding while you control the gate in your pipeline.

## Why use axeConfig?

- **Enable a rule that is off by default**: The most common change is turning on [color contrast checking](#rules-that-are-off-by-default) for a project where you've confirmed it produces reliable results.
- **Turn off a rule that is a known false positive**: If a specific rule consistently misfires because of a third-party framework you can't change, disable it project-wide so it stops adding noise to your reports.
- **Scope the report to a conformance target**: Limit the run to the WCAG tags your team measures against, including rule groups that Axe-Core® keeps off by default, such as WCAG 2.2 or Level AAA.

### Customize included elements, pages, and CI-blocking behavior

To ignore a specific rule for individual elements, add the [`data-a11y-ignore`](/accessibility/configuration/ignoring-rules-per-element) attribute in your application code. To keep a rule enabled but stop a particular element or page from being reported, use [`elementFilters`](/accessibility/configuration/elementfilters) or [`viewFilters`](/accessibility/configuration/viewfilters). To decide which findings block a build in CI, parse your run's results with the [Results API](/accessibility/connect-and-extend/results-api).

## Scope

`axeConfig` is only valid under an `accessibility` key in your App Quality configuration. It can also be set inside a [`profiles`](/accessibility/configuration/profiles) entry to apply different rulesets to tagged runs.

## Setting axeConfig

To add or edit `axeConfig`, open the **App Quality** tab in your project settings in Cypress Cloud. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for details, including how to regenerate past reports with a new configuration without rerunning your tests.

<DocsImage
  src="/img/accessibility/configuration/cypress-accessibility-configuration-editor.png"
  alt="The App Quality tab of a project's settings in Cypress Cloud, showing the configuration editor with JSON configuration"
/>

## Syntax

```json title="App Quality Config"
{
  "accessibility": {
    "axeConfig": {
      "runOnly": {
        "type": "tag" | "tags" | "rule" | "rules",
        "values": [string]
      },
      "rules": {
        "<rule-id>": { "enabled": boolean }
      }
    }
  }
}
```

### Options

| Option    | Required | Default | Description                                                                                                                                                                                                                                           |
| --------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `runOnly` | Optional |         | Limits which Axe-Core® rules run to the listed tags or rule IDs. `type` is `tag` or `tags` for Axe-Core® tags such as `wcag2aa`, and `rule` or `rules` for individual rule IDs. `values` is the list of tags or rule IDs to include.                  |
| `rules`   | Optional |         | Per-rule overrides. Each key is an Axe-Core® [rule ID](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md), and `enabled` turns that rule on or off. Overrides apply on top of Cypress defaults and any `runOnly` selection. |

### How is axeConfig applied?

- **`rules` overrides win over Cypress defaults.** Cypress Accessibility starts from its [default disabled rules](#rules-that-are-off-by-default). Any rule you set in `axeConfig.rules` replaces that default for that rule, so `"color-contrast": { "enabled": true }` turns color contrast on for the project.
- **`runOnly` narrows the ruleset.** When you set `runOnly`, only rules that match the listed tags or IDs run. Rules outside that selection are reported as ignored by configuration.
- **Combine `runOnly` and `rules` when you need both.** A common pattern is scoping to WCAG tags with `runOnly`, then enabling or disabling individual rules inside that scope with `rules`.
- **Disabled rules stay visible in the report.** In the **Rules** view, rules turned off by configuration appear with an **Ignored by configuration** status, so it's clear which checks a run did and did not include.
- **Unknown properties are rejected.** Cypress Cloud validates `axeConfig` against a strict schema. Only `runOnly` and `rules` are accepted, and each `rules` entry accepts only `enabled`.

### Validation rules

Cypress Cloud rejects a configuration when:

- `axeConfig` is set at the root of the configuration instead of under `accessibility`.
- `axeConfig` contains a property other than `runOnly` or `rules`.
- `runOnly` is missing `type` or `values`, or uses an unsupported `type`.
- A `rules` entry is missing `enabled`, or contains a property other than `enabled`.

## Examples

### Enable color contrast checking

Color contrast is [off by default](#rules-that-are-off-by-default). Turn it on for the project.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "axeConfig": {
      "rules": {
        "color-contrast": { "enabled": true }
      }
    }
  }
}
```

#### Result

The `color-contrast` rule runs for the project. The other rules that are off by default stay off.

---

### Disable a noisy rule project-wide

Turn off a rule that's not relevant to your project or your current accessibility goals, to reduce noise for your team when parsing reports.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "axeConfig": {
      "rules": {
        "region": { "enabled": false }
      }
    }
  }
}
```

#### Result

The `region` rule is listed as **Ignored by configuration** and stops adding violations to the report.

---

### Scope the report to WCAG 2.1 A and AA

Limit the run to WCAG 2.0 and 2.1 Level A and AA tags, and leave Best Practices rules out of the report.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "axeConfig": {
      "runOnly": {
        "type": "tag",
        "values": ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]
      }
    }
  }
}
```

#### Result

Only rules tagged for those WCAG levels run. Best Practices rules, such as `region` and `landmark-one-main`, are ignored by configuration.

---

### Scope to WCAG tags and enable color contrast

Combine `runOnly` with a per-rule override so the report stays on your conformance target while color contrast still runs.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "axeConfig": {
      "runOnly": {
        "type": "tag",
        "values": ["wcag2a", "wcag21a"]
      },
      "rules": {
        "color-contrast": { "enabled": true }
      }
    }
  }
}
```

#### Result

The report includes WCAG 2.0 and 2.1 Level A rules, including `color-contrast`, and leaves Best Practices rules out.

---

### Apply a different ruleset on pull request runs

Use a [`profiles`](/accessibility/configuration/profiles) entry so tagged pull request runs scope to WCAG 2.0 and 2.1 Level A and AA tags while regression runs keep the broader base ruleset.

#### Config

```json title="App Quality Config"
{
  "profiles": [
    {
      "name": "aq-config-pr",
      "comment": "Pull request gate: WCAG A/AA only",
      "config": {
        "accessibility": {
          "axeConfig": {
            "runOnly": {
              "type": "tag",
              "values": ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]
            }
          }
        }
      }
    }
  ]
}
```

#### Usage

```shell
cypress run --record --tag "aq-config-pr"
```

#### Result

Runs recorded with the `aq-config-pr` tag use the scoped ruleset. Runs recorded without that tag keep the base configuration.

## What the default ruleset covers {#what-the-default-ruleset-covers}

Cypress applies no conformance filter of its own, so a run evaluates whatever Axe-Core® enables by default, minus the [three rules Cypress turns off by default](#rules-that-are-off-by-default):

| Axe-Core® rule group        | Runs by default | Notes                                                                                                       |
| --------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------- |
| WCAG 2.0 Level A and AA     | Yes             | Minus `color-contrast`, `no-autoplay-audio`, and `meta-refresh`, which are WCAG-tagged but off by default   |
| WCAG 2.1 Level A and AA     | Yes             |                                                                                                             |
| Best Practices              | Yes             | Deque's own recommendations, such as `region` and `landmark-one-main`. These are not WCAG success criteria. |
| WCAG 2.2 Level A and AA     | No              | Off by default in Axe-Core® itself. Enable these for your project with `runOnly` or per-rule `rules`.       |
| WCAG Level AAA              | No              | Off by default in Axe-Core® itself. Enable these for your project with `runOnly` or per-rule `rules`.       |
| Experimental and deprecated | No              | Off by default in Axe-Core® itself.                                                                         |

Keep these behaviors in mind if you're measuring against a formal standard:

- **The default report is broader than any single WCAG level.** Best Practices findings appear alongside WCAG ones, so a violation in your report is not automatically a WCAG failure. Use the **Rules** filter in a report to separate WCAG 2.1 A, WCAG 2.1 AA, and Best Practices results.
- **The default report is also not complete WCAG coverage.** The three rules that are off by default map to WCAG success criteria (1.4.3, 1.4.2, and 2.2.1), and no automated ruleset can evaluate every success criterion in the first place. See [accessibility automation principles](/accessibility/guides/accessibility-automation) for what conformance requires beyond automation.

## Rules that are off by default {#rules-that-are-off-by-default}

A small number of Axe-Core® rules are turned off in Cypress Accessibility by default. Color contrast can be enabled per project with `axeConfig`. The other two depend on live runtime behavior that isn't reproduced when Cypress re-renders a captured snapshot for analysis, so they can't be evaluated reliably even if you enable them.

| Rule                                                        | Why it's off by default                                                                                                                                                                                             |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Elements must meet minimum color contrast ratio thresholds  | This is the slowest rule in the Axe-Core® ruleset and the one most likely to produce false positives or incomplete results. It works well in many projects; enable it with `"color-contrast": { "enabled": true }`. |
| `<video>` or `<audio>` elements must not play automatically | Detecting a violation requires loading and playing the media to measure how long it plays. Cypress analyzes a reconstructed snapshot of the page without playable media, so this rule can't be evaluated.           |
| Delayed refresh under 20 hours must not be used             | This rule reads a page's meta refresh directive, which Cypress disables while it analyzes a run so the reconstructed page doesn't navigate away. With the directive disabled, the rule can't be evaluated.          |

In addition, the custom [Cypress rule](/accessibility/core-concepts/cypress-rules) _Interactive elements should be semantically correct_ is available in all projects but is not enabled by default. Reach out to Cypress if you'd like it turned on.

You can confirm which rules were turned off for any run in its Accessibility report. In the **Rules** view, disabled rules are listed with an **Ignored by configuration** status, so it's always clear which checks a run did and did not include.

## Component testing {#component-testing}

Cypress Accessibility works with [component testing](/app/component-testing/get-started) as well as end-to-end testing. Alongside the rules that are off by default above, **page-level rules do not run for component tests**. Because a component is usually a fragment of a page rather than a complete document, rules that assert on overall page structure would report failures that don't apply to a component in isolation.

Rules skipped for component tests include page-structure and document-level checks, such as whether the page has a main landmark, a single top-level heading, a language attribute, and a document title. Rules that evaluate the components themselves, such as color contrast (when enabled), button naming, and image alternative text, run as normal.

The exact set of skipped rules isn't a fixed list Cypress maintains. It's derived from which rules Axe-Core® classifies as page-level, so it can shift when Cypress updates its Axe-Core® version. In a component's report, these page-structure rules are reported as not applicable rather than as failures. An `axeConfig` rule override can't force a page-level rule to run for component tests.

## Axe-Core® library version and updates {#axe-core-library-version-and-updates}

Cypress pins a specific, tested version of the Axe-Core® library. New Axe-Core® versions are released several times a year. While Cypress doesn't commit to updating our internal version within a specific timeframe, we always wait at least 30 days before adopting a new release.

Because some updates introduce new rules or change how existing issues are detected, this buffer gives you time to adjust how you use the [Results API](/accessibility/connect-and-extend/results-api) if needed. You can track Axe-Core® releases [on GitHub](https://github.com/dequelabs/axe-core/releases).

The exact Axe-Core® version used for a given run is shown in the **Properties** tab for that run in Cypress Cloud, and is also included as `axeVersion` in the [Results API](/accessibility/connect-and-extend/results-api) response. To get a heads-up in CI when the version changes, see [how to detect a change in the axe-core version](/accessibility/connect-and-extend/results-api#how-to-detect-a-change-in-the-axe-core-version).

## See also

- [Configuration overview](/accessibility/configuration/overview) lists every App Quality Config option and how to apply and regenerate configuration.
- [Results API](/accessibility/connect-and-extend/results-api) is where you decide which rules block a build in CI.
- [Ignore rules per element - `data-a11y-ignore`](/accessibility/configuration/ignoring-rules-per-element) turns off specific rules for individual elements from your application code.
- [Profiles](/accessibility/configuration/profiles) apply a different `axeConfig` to tagged runs.
- [Cypress rules](/accessibility/core-concepts/cypress-rules) documents the custom rules Cypress layers on top of Axe-Core®.
- [Cypress Accessibility FAQ](/accessibility/faq) answers common questions about rules and configuration.

---

### Accessibility Configuration Components (`docs/accessibility/configuration/components.mdx`)

---
title: 'components: add component and team context to Cypress Accessibility selectors'
description: 'Make Cypress Accessibility append component-identifying attributes, such as data-component-name, data-team, or data-page-area, to violation target selectors so every finding shows which component, team, or region it belongs to.'
sidebar_label: 'components'
sidebar_position: 90
---

<ProductHeading product="accessibility" />

# Add component context - `components`

The components configuration adds context to the selectors in your accessibility reports. When an element has a violation, Cypress Accessibility shows a **violation target selector** that points to it. components lets you add your own component-identifying attributes, such as `data-component-name`, `data-team`, or `data-page-area`, to that selector, so a finding reads as `[data-cy="signup"][data-component="IconButton"]` instead of a bare `[data-cy="signup"]`.

That extra context tells whoever picks up the issue, whether a developer, a Jira ticket, or an [AI agent triaging through Cypress Cloud MCP](/accessibility/work-with-ai-agents), which component, team, or region the element belongs to, without having to open the page HTML or search the codebase to place it. Many teams already render attributes like these for testing or design-system tracing; when they exist, components puts them into your selectors in a predictable, consistent way.

## Why use components?

- **Place every finding in context**: A selector like `[data-cy="row-action"][data-component="DataGridDeleteButton"]` says exactly which component is responsible, where a bare identifier could be any button in your application.
- **Route issues to the right owner**: Append an attribute like `data-team` and you can assign accessibility findings, or group them in a report, by the team that owns the DOM.
- **Speed up handoffs to people and AI**: Selectors that carry component and page context can be dropped into a Jira ticket or handed to an LLM for triage without the surrounding page HTML.
- **Cross-reference your design system**: Attributes such as `data-design-system-version` in the selector let you correlate accessibility issues with the component library version that produced them.

## How component attributes appear in selectors

Cypress Accessibility identifies each element with a stable selector, replacing the default Axe-Core® target so results for the same element can be deduplicated across the many snapshots in a run. That identifier is chosen from a prioritized list of attributes ([`significantAttributes`](/accessibility/configuration/significantattributes) followed by defaults like `data-cy` and `id`) and is usually the shortest thing that uniquely identifies the element.

Every attribute you list in `componentAttributes` is treated as **required**: wherever it appears on the element or one of its ancestors, Cypress keeps it in the selector. Take this button, which fails an accessibility check because its label text is hidden:

```xml
<button data-cy="signup" data-component="IconButton">
  <span style="display:none">Sign up now!</span>
</button>
```

By default, the violation target selector is just the identifier:

```
[data-cy="signup"]
```

Viewed on its own, that could be any button. List `data-component` as a component attribute:

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-component", "includeInSelector": true }
      ]
    }
  }
}
```

Now the component name is appended, even though the selector was already unique:

```
[data-cy="signup"][data-component="IconButton"]
```

When a required attribute is on an **ancestor** instead of the element itself, Cypress adds it as context with a descendant combinator. Given a `data-page-area` on a wrapping section:

```xml
<section data-page-area="checkout">
  <button data-cy="pay"><span style="display:none">Pay</span></button>
</section>
```

listing `data-page-area` reports the button with that region in front:

```
[data-page-area="checkout"] [data-cy="pay"]
```

:::tip

components adds context on top of whatever already identifies an element. To change which attribute _identifies_ it, use [`significantAttributes`](/accessibility/configuration/significantattributes) instead.

:::

## Scope

The components object is only valid under an `accessibility` key in your App Quality configuration. Unlike [`significantAttributes`](/accessibility/configuration/significantattributes) or [`attributeFilters`](/accessibility/configuration/attributefilters), it has no root-level or UI Coverage form. It can also be set inside a [`profiles`](/accessibility/configuration/profiles) entry to apply to tagged runs.

## Setting components

To add or edit components, open the **App Quality** tab in your project settings in Cypress Cloud. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for details, including how to regenerate past reports with a new configuration without rerunning your tests.

<DocsImage
  src="/img/accessibility/configuration/cypress-accessibility-configuration-editor.png"
  alt="The App Quality tab of a project's settings in Cypress Cloud, showing the configuration editor with JSON configuration"
/>

## Syntax

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        {
          "attributeName": string,
          "includeInSelector": boolean,
          "comment": string
        }
      ],
      "componentAttributeFilters": [
        {
          "attribute": string,
          "value": string,
          "include": boolean,
          "comment": string
        }
      ],
      "comment": string
    }
  }
}
```

### `componentAttributes`

Each entry names an attribute to append to the selector when it's present on the element with the violation. Attribute names are stored in lowercase and **must be unique** in the list.

| Option              | Required | Default | Description                                                                                      |
| ------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------ |
| `attributeName`     | Yes      |         | The HTML attribute name to append, for example `data-component-name`. `class` is also supported. |
| `includeInSelector` | No       | `true`  | When `true`, the attribute is appended to the selector wherever the element has it.              |
| `comment`           | No       |         | A note for your team explaining why the entry exists. Comments never appear in reports.          |

When `includeInSelector` is `false`, the entry is kept for documentation or future use but doesn't change selector generation, the same as leaving it out.

### `componentAttributeFilters`

These filters fine-tune **which attribute values** are appended. They apply only to the attributes in `componentAttributes`, using the same regular-expression style as [`attributeFilters`](/accessibility/configuration/attributefilters): `attribute` and `value` are regex patterns. For a given attribute value, **the first rule whose `attribute` and `value` both match** decides whether it's appended. A filter with no matching `componentAttributes` entry does nothing.

| Option      | Required | Default | Description                                                     |
| ----------- | -------- | ------- | --------------------------------------------------------------- |
| `attribute` | Yes      |         | Regex matched against the component attribute's name.           |
| `value`     | No       | `.*`    | Regex matched against the attribute's value.                    |
| `include`   | No       | `true`  | When `false`, matching values are not appended to the selector. |
| `comment`   | No       |         | A note for your team. Comments never appear in reports.         |

Use `include: false` to keep a noisy or generic value out of your selectors, such as a layout primitive whose name adds no context, while still appending the meaningful ones.

You can also add a `comment` to the components object itself to document the whole block. Comments are for your team, never appear in reports, and are the supported place for notes because Cypress Cloud rejects properties it doesn't recognize. See [Comments](/accessibility/configuration/overview#Comments).

### How are components rules applied?

Keep these behaviors in mind when building your configuration:

- **Listed attributes are kept wherever they appear.** A component attribute on the element is appended to its selector; the same attribute on an ancestor is added in front as descendant-combinator context. An element whose ancestor chain has none of the listed attributes is unaffected.
- **They're added on top of the identifier, not instead of it.** The element is still identified by `significantAttributes` and the defaults; component attributes add context. They're added even when the selector is already unique.
- **They help with uniqueness and deduplication.** Because a required attribute is part of the selector, one that distinguishes the element can make the selector shorter and more stable than the positional fallback Cypress would use otherwise, which keeps the same element from splitting into several across snapshots.
- **On one element, appended attributes follow your list order.** Multiple attributes appended to the same element appear in the order you list them in `componentAttributes`. An attribute that already identifies the element isn't added a second time.
- **Default attribute filters don't apply here.** The [default filters](/accessibility/configuration/attributefilters) that keep dynamic, UUID-like values out of _identifying_ selectors don't touch component attributes. `componentAttributeFilters` are the only way to exclude component-attribute values, so list a rule if an attribute's value is sometimes noisy.
- **`class` is supported.** Listing `class` as a component attribute appends the element's class value; `componentAttributeFilters` apply to it the same way.

### Validation rules

Cypress Cloud validates the whole configuration before saving it and rejects a components block that breaks any of these:

- Each `attributeName` must be a valid HTML attribute name. Names are compared in lowercase and must be unique across `componentAttributes`.
- Each `componentAttributeFilters` `attribute` and `value` must be a valid regular expression.
- No two `componentAttributeFilters` rules may be identical across `attribute`, `value`, and `include`.
- Only the properties documented above are allowed. An unrecognized key is rejected rather than ignored.

## Examples

### Append the design-system component name

The button below fails `button-name` because its label is hidden. It carries a `data-cy` test id and a `data-component` name from the design system. Listing `data-component` appends the component name to the selector, so the finding names the component instead of a generic id.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-component", "includeInSelector": true }
      ]
    }
  }
}
```

#### HTML

```xml
<button data-cy="signup" data-component="IconButton">
  <span style="display:none">Sign up now!</span>
</button>
```

#### Result

The violation target selector displayed in the report:

```
[data-cy="signup"][data-component="IconButton"]
```

### Add component and team context together

`componentAttributes` is a list, so you can append more than one attribute. Here the design-system component name and the owning team are both added, so findings can be read, filtered, or assigned by either.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-component", "includeInSelector": true },
        { "attributeName": "data-team", "includeInSelector": true }
      ]
    }
  }
}
```

#### HTML

```xml
<img
  data-testid="hero-banner"
  data-component="HeroBanner"
  data-team="marketing"
  src="hero.png"
/>
```

#### Result

The image fails `image-alt`, and its selector now shows the component and the team that owns it:

```
[data-testid="hero-banner"][data-component="HeroBanner"][data-team="marketing"]
```

### Add the surrounding page region

Component attributes don't have to be on the element itself. When a listed attribute sits on an ancestor, such as a `data-page-area` on the wrapping landmark, Cypress adds it in front of the identifier as context, so a violation reads as belonging to a region of the page.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-page-area", "includeInSelector": true }
      ]
    }
  }
}
```

#### HTML

```xml
<nav data-page-area="global-header">
  <button data-cy="menu-toggle">
    <span style="display:none">Open menu</span>
  </button>
</nav>
```

#### Result

The button is identified by its own `data-cy`, with the region prepended as ancestor context:

```
[data-page-area="global-header"] [data-cy="menu-toggle"]
```

### Keep a generic component name out of selectors

Some component names add no context. A layout primitive like `Box` wraps elements all over the application, so appending it to every selector is noise. Keep `data-component` appended in general, but use a `componentAttributeFilters` rule to skip the values that don't help.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-component", "includeInSelector": true }
      ],
      "componentAttributeFilters": [
        {
          "attribute": "data-component",
          "value": "^(Box|Stack|Flex)$",
          "include": false,
          "comment": "Layout primitives add no useful context"
        }
      ]
    }
  }
}
```

#### HTML

```xml
<button data-cy="row-delete" data-component="DataGridDeleteButton">Delete</button>
<button data-cy="page-close" data-component="Box">Close</button>
```

#### Result

The meaningful component name is appended; the layout primitive is filtered out, leaving that element on its identifier alone:

```
[data-cy="row-delete"][data-component="DataGridDeleteButton"]
[data-cy="page-close"]
```

:::tip

After saving configuration changes, regenerate a recent run to preview the effect of your rules without rerunning your tests. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for how to regenerate a report.

:::

## How components compares to other options

Three configuration properties all work with attributes, but they do different jobs:

- [`significantAttributes`](/accessibility/configuration/significantattributes) chooses the single attribute that **identifies** the element and becomes its selector.
- [`attributeFilters`](/accessibility/configuration/attributefilters) **removes** dynamic or generated attribute values from identification, so they can't be used as selectors.
- components **adds context** to the selector, from the element or its ancestors, on top of whatever identifies the element, without changing which attribute identifies it.

For background on how Cypress picks identifiers, see [Element identification](/accessibility/core-concepts/element-identification).

## See also

- [Element identification](/accessibility/core-concepts/element-identification): how elements are identified across snapshots.
- [`significantAttributes`](/accessibility/configuration/significantattributes): choose which attribute identifies an element.
- [`attributeFilters`](/accessibility/configuration/attributefilters): stop dynamic or generated attribute values from identifying elements.
- [Inspecting violation details](/accessibility/reports/element-detail-view): where violation target selectors appear in reports.
- [Work with AI agents](/accessibility/work-with-ai-agents): triage findings through Cypress Cloud MCP.
- [Configuration overview](/accessibility/configuration/overview): where to set configuration and regenerate reports.
- [Cypress Accessibility FAQ](/accessibility/faq): common questions and troubleshooting.

---

### Accessibility Configuration Elementfilters (`docs/accessibility/configuration/elementfilters.mdx`)

---
title: 'elementFilters: ignore elements in Cypress Accessibility'
description: 'Ignore elements in Cypress Accessibility reports with elementFilters, so third-party widgets and out-of-scope elements stop counting against your accessibility score.'
sidebar_label: 'elementFilters'
sidebar_position: 40
---

<ProductHeading product="accessibility" />

# Exclude elements - `elementFilters`

The `elementFilters` configuration ignores elements in your Cypress Accessibility report. An ignored element's failed and incomplete checks stop counting against your views and your [accessibility score](/accessibility/core-concepts/accessibility-score), and the element appears under an **Ignored** status instead, so you can always audit what your configuration ignores.

By default, Cypress Accessibility reports on every element that Axe Core® checks in your application during your tests, including elements you can't fix: a third-party chat widget, an embedded cookie banner, content rendered by a library you don't control. Failures in those elements obscure the failures your team can act on. An `elementFilters` rule moves them out of the way, so your report and score reflect the accessibility of the application you own.

## Why use elementFilters?

- **Ignore third-party components**: Chat widgets, cookie banners, embedded media players, and other elements rendered by libraries or services you don't control can be ignored, since your team can't fix their violations.
- **Ignore out-of-scope elements**: Remove test-only controls or areas of the application that are outside the scope of your accessibility work.
- **Keep the score meaningful**: A score that only reflects elements you can fix makes progress and regressions easier to see and act on.

Ignoring an element ignores all accessibility results for that element. To keep an element in your report but ignore specific rules for it, use the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) instead. To ignore entire pages, use [`viewFilters`](/accessibility/configuration/viewfilters).

## Scope

:::info

**Note:** setting `elementFilters` at the root of your configuration impacts both Cypress Accessibility and UI Coverage reports. To configure the products separately, nest the property under an `accessibility` or `uiCoverage` key. A nested `elementFilters` completely replaces a root-level one for that product; the two lists are not merged.

:::

## Setting elementFilters

To add or edit `elementFilters`, open the **App Quality** tab in your project settings in Cypress Cloud. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for details, including how to regenerate past reports with a new configuration without rerunning your tests.

<DocsImage
  src="/img/accessibility/configuration/cypress-accessibility-configuration-editor.png"
  alt="The App Quality tab of a project's settings in Cypress Cloud, showing the configuration editor with JSON configuration"
/>

## Syntax

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": string,
      "include": boolean,
      "documentScope": [string],
      "comment": string
    }
  ]
}
```

To apply rules to Cypress Accessibility only, nest the property under the `accessibility` key:

```json title="App Quality Config"
{
  "accessibility": {
    "elementFilters": [
      {
        "selector": string,
        "include": boolean
      }
    ]
  }
}
```

### Options

| Option          | Required | Default | Description                                                                                                                                                                                                                                                                                                           |
| --------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `selector`      | Required |         | A CSS selector that matches the elements to ignore. Supports standard CSS selector syntax, including IDs, classes, attributes, combinators, and functional pseudo-classes like `:has()`. The selector must match the element with the accessibility result itself, not just a container around it.                    |
| `include`       | Required |         | Whether elements matched by this rule appear as normal results in the report. Use `false` to ignore the matched elements. In Cypress Accessibility, `true` has no additional effect, because every element is included unless an exclude rule matches it. See [When to use include: true](#When-to-use-include-true). |
| `documentScope` | Optional |         | An ordered array of CSS selectors that match document hosts (iframes or shadow DOM hosts) in the element's ancestor chain, from outermost to innermost. Use this to limit a rule to elements inside a specific iframe or shadow DOM. Hosts that aren't listed may appear between the ones that are.                   |
| `comment`       | Optional |         | A note about why this rule exists, for your team's benefit. Comments appear only in the configuration itself. They have no effect on filtering and are not displayed in reports.                                                                                                                                      |

### How are elementFilters rules applied?

- **Any matching exclude rule ignores the element.** An element is ignored when any rule with `include: false` matches it, regardless of where the rule appears in the list. Elements that no exclude rule matches stay in the report as normal results.
- **An `include: true` rule cannot protect or restore an element.** An include rule doesn't shield its elements from exclude rules elsewhere in the list.
- **The selector must match the element itself.** Accessibility results are reported per element, and each rule is evaluated against those elements using standard CSS matching. A rule with the selector `footer` ignores results on the `<footer>` element only, not on the elements inside it. To ignore a whole region, match the container and its descendants: `footer, footer *`.
- **Ignored elements stay visible in the report.** Elements with failed or incomplete checks that your configuration ignores appear under the **Ignored** [element status](/accessibility/reports/run-level-reports#Elements) rather than disappearing, so the report always shows what your configuration is hiding. They don't count as failed or incomplete elements, and they don't affect the accessibility score.
- **The score changes once every failing element of a rule is ignored.** The [accessibility score](/accessibility/core-concepts/accessibility-score) weighs each failed rule per snapshot, not each failing element. Ignoring some, but not all, of a rule's failing elements in a snapshot doesn't change that snapshot's score; the rule stops counting against the snapshot when all of its failing elements there are ignored.
- **Ignoring an element ignores all of its results.** An `elementFilters` rule applies to every accessibility rule for the matched element. To ignore only specific rules for an element, use the [`data-a11y-ignore` attribute](/accessibility/configuration/ignoring-rules-per-element) in your application code.
- **Rules match in any document unless scoped.** A rule without `documentScope` can match elements in the main document, in iframes, and in shadow DOMs. Add `documentScope` to restrict a rule to one of those documents.

If a rule doesn't seem to take effect, see [Why is an element still failing in Cypress Accessibility after I added an elementFilters rule?](/accessibility/faq#Why-is-an-element-still-failing-in-Cypress-Accessibility-after-I-added-an-elementFilters-rule) in the Cypress Accessibility FAQ.

### Validation rules

Cypress Cloud rejects a configuration when:

- Two rules have the same `selector` (with the same `documentScope`).
- A rule is missing `selector` or `include`.
- A `selector` or `documentScope` entry isn't valid CSS selector syntax.
- A rule contains a property other than the four listed above.

## Examples

### Ignore a third-party widget

The selector matches both the widget's container and everything inside it, so results on the container itself are ignored along with results on its contents.

#### Config

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "#chat-widget, #chat-widget *",
      "include": false,
      "comment": "Vendor chat widget, accessibility issues reported upstream"
    }
  ]
}
```

#### HTML

```xml
<body>
  <main>
    <button id="checkout">Check out</button>
  </main>
  <div id="chat-widget">
    <button class="chat-open">Chat with us</button>
  </div>
</body>
```

#### Result

Violations on `#checkout` are reported as failures. Violations on the chat widget and its contents appear under the **Ignored** status and don't affect the score.

---

### Ignore elements by attribute

#### Config

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "[data-vendor]",
      "include": false
    }
  ]
}
```

#### HTML

```xml
<body>
  <button id="save">Save</button>
  <button data-vendor="analytics">Feedback</button>
</body>
```

#### Result

Violations on `#save` are reported as failures. Violations on the `data-vendor` button appear under the **Ignored** status.

---

### Ignore dynamic elements by pattern

Attribute prefix, suffix, and substring selectors (`[class^='...']`, `[class$='...']`, `[class*='...']`) are useful when class names or IDs are partially generated.

#### Config

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "[class^='ext-embed']",
      "include": false
    }
  ]
}
```

#### HTML

```xml
<body>
  <button class="cancel">Cancel</button>
  <div class="ext-embed-90283" role="button">External content</div>
</body>
```

#### Result

Violations on `.cancel` are reported as failures. Violations on the embed appear under the **Ignored** status.

---

### Ignore elements inside a shadow DOM or iframe

Use `documentScope` to limit a rule to elements inside a specific shadow DOM host or iframe. Here, the button inside the `<custom-component>` shadow root shares its `id` with a button in the main document. The scope restricts the rule to the shadow DOM, so results on the button in the main document are still reported.

#### Config

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "#my-button",
      "include": false,
      "documentScope": ["custom-component"]
    }
  ]
}
```

#### HTML

```xml
<body>
  <button id="my-button">Button Outside Shadow DOM</button>
  <custom-component>
    #shadow-dom
      <button id="my-button">Button Inside Shadow DOM</button>
  </custom-component>
</body>
```

#### Result

Violations on the button in the main document are reported as failures. Violations on the button inside the shadow DOM appear under the **Ignored** status.

`documentScope` works the same way for content that renders inside an iframe. The scope selector matches the `iframe` element itself in its parent document, and a wildcard selector ignores everything the iframe contains:

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "*",
      "include": false,
      "documentScope": ["iframe[title='Support']"]
    }
  ]
}
```

For nested documents, list one selector per host from outermost to innermost. For example, `"documentScope": ["#my-iframe", "custom-component"]` scopes a rule to a shadow DOM component rendered inside an iframe.

---

### When to use include: true

For rules that only affect Cypress Accessibility, there's no reason to write `include: true`. Every element is included unless an exclude rule matches it, and an include rule can't override an exclusion.

The value exists for `elementFilters` lists defined at the root of your configuration, which are shared with UI Coverage. In UI Coverage, the first matching rule wins, so an `include: true` rule placed before a broader exclude rule keeps its elements in UI Coverage reports. Cypress Accessibility reads the same list but treats the include rule as inert.

#### Config

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "nav a",
      "include": true,
      "comment": "Keep nav links in UI Coverage despite the vendor exclude below"
    },
    {
      "selector": "[data-vendor] a",
      "include": false,
      "comment": "Ignore links rendered by the vendor toolbar"
    }
  ]
}
```

#### HTML

```xml
<body>
  <nav data-vendor="toolbar">
    <a href="/home">Home</a>
  </nav>
  <div data-vendor="promos">
    <a href="https://vendor.example">Sponsored</a>
  </div>
</body>
```

#### Result

The Home link matches both rules. In Cypress Accessibility, the exclude rule ignores it anyway, so results on both links appear under the **Ignored** status. In UI Coverage, the first matching rule wins, so the Home link stays in the report while the sponsored link is excluded.

To get different outcomes per product, nest a separate `elementFilters` list under each product key instead of sharing one root-level list.

:::tip

After saving configuration changes, regenerate a recent run to preview the effect of your rules without rerunning your tests. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for how to regenerate a report.

:::

## See also

- [`data-a11y-ignore`](/accessibility/configuration/ignoring-rules-per-element): ignore specific rules for an element instead of the whole element.
- [`viewFilters`](/accessibility/configuration/viewfilters): ignore entire pages.
- [Run-level reports](/accessibility/reports/run-level-reports): where ignored elements appear in your report.
- [Accessibility score](/accessibility/core-concepts/accessibility-score): how the score is calculated.
- [Configuration overview](/accessibility/configuration/overview): where to set configuration and regenerate reports.
- [Cypress Accessibility FAQ](/accessibility/faq): common questions and troubleshooting.

---

### Accessibility Configuration Ignoring Rules Per Element (`docs/accessibility/configuration/ignoring-rules-per-element.mdx`)

---
title: 'data-a11y-ignore: ignore accessibility rules per element'
description: 'Use the data-a11y-ignore attribute to exclude specific accessibility rules from elements in Cypress Accessibility.'
sidebar_label: 'data-a11y-ignore'
sidebar_position: 60
---

<ProductHeading product="accessibility" />

# Ignore rules per element - `data-a11y-ignore`

Cypress Accessibility configuration excludes [elements](/accessibility/configuration/elementfilters) or whole [pages](/accessibility/configuration/viewfilters) from the accessibility report, but sometimes there are situations where you may want to keep an element in your accessibility report, but ignore some accessibility rules for that element.

This can be accomplished in your application code using the `data-a11y-ignore` attribute, like this:

```html
<button data-a11y-ignore="color-contrast">Log In</button>
```

This would mean that if a color contrast violation was detected on this button, it would be tracked and flagged as an ignored violation in your accessibility report, instead of being listed as a failure. Any other violations detected would be flagged as normal failures.

## Ignore multiple rules

Multiple rules can be ignored by using commas to separate a list of rule IDs:

```html
<button data-a11y-ignore="color-contrast,button-name">Log In</button>
```

## Where to find rule IDs

The "Learn more" link in your accessibility reports will display the ID for each rule. They can also be looked up in the [Axe-Core® rule documentation](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md) directly.

## When to use this

### Handle false positives

This is most useful when there is a known false positive failure for a specific rule and you want to remove it from your report without losing all other insights about an element.

The `data-a11y-ignore` attribute pattern is used in some libraries like Adobe's React Spectrum, so those UI elements automatically have the defined rules ignored correctly in Cypress Accessibility.

### Avoid blocking a code change

A secondary use case is to avoid certain known issues becoming blocking for a pull request. `data-a11y-ignore` allows for a minimal scope of what to ignore, and creates a paper trail through version control which means these changes are obvious at code review, and comments can be added nearby to explain the reason for ignoring the rule.

---

### Accessibility Configuration Profiles (`docs/accessibility/configuration/profiles.mdx`)

---
title: 'profiles: apply config overrides by run tag'
description: 'Use the profiles property to apply different Cypress Accessibility configuration to different runs, whether a narrow pull request gate, a full regression run, or per-team reports, selected automatically by run tag, without changing your test code.'
sidebar_label: 'profiles'
sidebar_position: 100
---

<ProductHeading product="accessibility" />

# Override config by run tag - `profiles`

<Profiles />

## Examples

Each example shows the App Quality configuration and the `cypress run` command that selects the profile. Anything a profile doesn't mention is inherited from your base configuration.

### Scope a pull request gate to critical flows

The highest-value use of profiles in Cypress Accessibility is a fast, focused gate for pull requests. Your base configuration scans every view so regression runs track accessibility everywhere. A pull request run doesn't need that breadth; it needs a small, unambiguous report a developer can act on before merging. The `aq-config-pr` profile keeps only your most critical flows with [`viewFilters`](/accessibility/configuration/viewfilters), so the pull request report covers login and checkout and nothing else.

#### Config

```json title="App Quality Config"
{
  "profiles": [
    {
      "name": "aq-config-pr",
      "comment": "Pull request gate: report only on the flows that block a merge",
      "config": {
        "viewFilters": [
          { "pattern": "/login", "include": true },
          { "pattern": "/checkout/*", "include": true },
          {
            "pattern": "*",
            "include": false,
            "comment": "Ignore every other view on pull request runs"
          }
        ]
      }
    }
  ]
}
```

#### Usage

Tag pull request runs so they pick up the profile:

```shell
cypress run --record --tag "aq-config-pr"
```

`viewFilters` applies the first matching rule, so the two `include: true` rules keep login and checkout while the catch-all excludes everything else. Regression runs record without this tag and use the base configuration, scanning every view. Pair the narrow report with the [Results API](/accessibility/connect-and-extend/results-api) to fail the build when a critical flow regresses.

### Re-include a widget for a dedicated audit

Your base configuration excludes two third-party widgets with [`elementFilters`](/accessibility/configuration/elementfilters), a cookie banner and an embedded support chat, because another vendor owns them and their violations only add noise. One suite exists specifically to audit the support-chat integration's accessibility, recorded under the `aq-config-support-audit` tag. For that run, the chat widget should be scanned while the cookie banner stays excluded.

#### Config

```json title="App Quality Config"
{
  "elementFilters": [
    {
      "selector": "#onetrust-banner-sdk, #onetrust-banner-sdk *",
      "include": false,
      "comment": "Third-party cookie banner, reported upstream to the vendor"
    },
    {
      "selector": "#support-chat, #support-chat *",
      "include": false,
      "comment": "Vendor support-chat widget, excluded from everyday reports"
    }
  ],
  "profiles": [
    {
      "name": "aq-config-support-audit",
      "config": {
        "elementFilters": [
          {
            "selector": "#onetrust-banner-sdk, #onetrust-banner-sdk *",
            "include": false,
            "comment": "Still exclude the cookie banner during the support-chat audit"
          }
        ]
      }
    }
  ]
}
```

#### Usage

```shell
cypress run --record --tag "aq-config-support-audit"
```

A profile's `elementFilters` replaces the base list rather than adding to it, so the profile repeats the cookie-banner rule it still needs and omits the support-chat rule. In Cypress Accessibility an element is scanned unless an `include: false` rule matches it, so dropping the support-chat exclusion is all it takes to bring the widget back into this run's report; you don't add an `include: true` rule. On every other run, both widgets stay excluded.

### Apply an accessibility-only override for a labels audit

Profiles can override configuration nested under an `accessibility` key, and those objects merge one level deep, so a profile can replace a single accessibility setting while inheriting the rest. Here the base configuration identifies violation targets by their [`components`](/accessibility/configuration/components) context for everyday reports. A quarterly audit of accessible names, tagged `aq-config-label-audit`, wants each violation target shown by its `aria-label` instead, using [`significantAttributes`](/accessibility/configuration/significantattributes), so a reviewer can spot a vague label like `aria-label="button"` at a glance. The audit keeps the same component context.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-component-name", "includeInSelector": true }
      ]
    },
    "significantAttributes": ["data-cy"]
  },
  "profiles": [
    {
      "name": "aq-config-label-audit",
      "config": {
        "accessibility": {
          "significantAttributes": ["aria-label"]
        }
      }
    }
  ]
}
```

#### Usage

```shell
cypress run --record --tag "aq-config-label-audit"
```

Inside `accessibility`, the profile replaces only `significantAttributes`; the sibling `components` object is inherited, so violation targets still carry their component context and are now identified by their label text. On every other run, elements are identified by `data-cy` as usual.

### Choose between profiles when several tags match

Two teams share one Cypress Cloud project, and each has a profile that scopes the accessibility report to the views it owns with [`viewFilters`](/accessibility/configuration/viewfilters). A shared nightly job is tagged for both teams, so both profiles match and the array order decides which one applies.

#### Config

```json title="App Quality Config"
{
  "profiles": [
    {
      "name": "aq-config-team-checkout",
      "config": {
        "viewFilters": [
          { "pattern": "/checkout/*", "include": true },
          {
            "pattern": "*",
            "include": false,
            "comment": "Checkout team: report only on checkout views"
          }
        ]
      }
    },
    {
      "name": "aq-config-team-account",
      "config": {
        "viewFilters": [
          { "pattern": "/account/*", "include": true },
          {
            "pattern": "*",
            "include": false,
            "comment": "Account team: report only on account views"
          }
        ]
      }
    }
  ]
}
```

#### Usage

```shell
cypress run --record --tag "aq-config-team-account,aq-config-team-checkout"
```

The nightly run gets `aq-config-team-checkout`, the first of the two in the array, rather than `aq-config-team-account`, even though its tag is listed first on the command line. Reorder the `profiles` array to hand the shared run to the other team.

## Confirm which profile a run used

After you tag and record a run, check which configuration was actually applied so you know the profile took effect. Every run permanently records its resolved configuration: your base configuration with any matching profile already merged in.

- **In Cypress Cloud**, open the run's **Properties** tab to see the exact configuration that was applied.
- **In CI**, read it from the [Accessibility Results API](/accessibility/connect-and-extend/results-api), where `config.value` is the applied App Quality configuration and `config.updatedAt` is when it was last saved.

If the applied configuration matches your base rather than the profile you expected, the tag didn't select the profile; see [Troubleshooting](#Troubleshooting). For more on reading a run's configuration, see [Viewing configuration for a run](/accessibility/configuration/overview#Viewing-Configuration-for-a-Run).

## Troubleshooting

### A profile you tagged wasn't applied

- The run's tag doesn't exactly match the profile `name`. Matching is case-sensitive and exact.
- The tag never reached Cypress Cloud. A run recorded without `--record`, or without that `--tag`, uses the base configuration.
- Another profile earlier in the array also matches one of the run's tags and wins. Reorder the array to change precedence.
- The report was processed before you saved the configuration. Regenerate the run to apply your current profiles. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration).

## See also

- [Cypress run `--tag`](/app/references/command-line#cypress-run-tag-lt-tag-gt) is the flag that selects which profile a run uses.
- [Configuration overview](/accessibility/configuration/overview) lists every option a profile's `config` can override and how to regenerate reports after changing configuration.
- [`viewFilters`](/accessibility/configuration/viewfilters) and [`elementFilters`](/accessibility/configuration/elementfilters) are common properties for scoping a profile's report.
- [Block pull requests](/accessibility/guides/block-pull-requests) pairs a narrow pull request profile with the Results API to gate merges.
- [Cypress Accessibility FAQ](/accessibility/faq#Profiles) answers common questions about profiles, including merge behavior and tag matching.

---

### Accessibility Configuration Significantattributes (`docs/accessibility/configuration/significantattributes.mdx`)

---
title: 'significantAttributes: identify elements by your attributes in Cypress Accessibility'
description: 'Make Cypress Accessibility identify elements and build violation target selectors from your own HTML attributes, such as data-component, aria-label, or data-automation-id, by adding them to the priority list of significant attributes.'
sidebar_label: 'significantAttributes'
sidebar_position: 70
---

<ProductHeading product="accessibility" />

# Prioritize identifying attributes - `significantAttributes`

The `significantAttributes` configuration adds your own HTML attributes to the priority list Cypress Accessibility uses to identify elements. Attributes you list are checked before the default test attributes, in the order you list them.

Cypress Accessibility [identifies each element](/accessibility/core-concepts/element-identification) with a stable selector, replacing the default Axe-Core® target, so that results for the same element can be deduplicated across the many snapshots captured in a run. That selector is built from a prioritized list of attributes: test attributes like `data-cy` and `data-testid` first, then fallbacks like `id` and `name`. Your application may already have attributes that describe elements better than anything in that list, such as a `data-component` attribute from your design system or a `data-automation-id` your team maintains. Listing them in `significantAttributes` makes Cypress Accessibility prefer them, so violation targets read in your team's vocabulary when [reviewing violation details](/accessibility/reports/element-detail-view), creating Jira issues, or handing selectors to AI tools, and deduplication is driven by values that stay stable across snapshots.

## Why use significantAttributes?

- **Use attributes your application already has**: If your components render an attribute like `data-component`, Cypress Accessibility can identify elements by it. No new markup required.
- **Make violation targets easier to locate and fix**: A selector like `[data-component="SearchInput"]` tells whoever picks up the issue exactly which component to open, where a generated selector doesn't.
- **Promote one of the default attributes**: The defaults are checked in a fixed order (`data-cy` before `data-qa`, for example). If your application standardizes on `data-qa`, listing it moves it to the front of the line.
- **Improve deduplication**: When the highest-priority attribute an element has is dynamic, the same element can be counted more than once across snapshots. A stable attribute of yours, placed above the rest, keeps it one element.

`significantAttributes` changes which attributes are preferred. To stop a dynamic attribute from being used at all, use [`attributeFilters`](/accessibility/configuration/attributefilters). To require component-identifying attributes in every selector, in addition to the identifying attribute, see [`components`](/accessibility/configuration/components).

## Scope

:::info

**Note:** setting `significantAttributes` at the root of your configuration impacts both Cypress Accessibility and UI Coverage reports. To configure the products separately, nest the property under an `accessibility` or `uiCoverage` key. A nested `significantAttributes` completely replaces a root-level one for that product; the two lists are not merged.

:::

## Setting significantAttributes

To add or edit `significantAttributes`, open the **App Quality** tab in your project settings in Cypress Cloud. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for details, including how to regenerate past reports with a new configuration without rerunning your tests.

<DocsImage
  src="/img/accessibility/configuration/cypress-accessibility-configuration-editor.png"
  alt="The App Quality tab of a project's settings in Cypress Cloud, showing the configuration editor with JSON configuration"
/>

## Syntax

```json title="App Quality Config"
{
  "significantAttributes": [string]
}
```

To apply the list to Cypress Accessibility only, nest the property under the `accessibility` key:

```json title="App Quality Config"
{
  "accessibility": {
    "significantAttributes": [string]
  }
}
```

Each entry is the name of an HTML attribute, such as `"data-component"` or `"aria-label"`. Any valid HTML attribute qualifies, not only `data-*` attributes. Entries are attribute names only: not CSS selectors, not regular expressions, and not attribute values.

### How are significant attributes applied?

For each element with accessibility results, Cypress Accessibility builds a selector from one combined list of attributes, in priority order:

1. Your `significantAttributes`, in the order you list them
2. The default significant attributes, in order: `data-cy`, `data-test`, `data-testid`, `data-test-id`, `data-qa`, and `row-id`
3. Fallbacks, in order: `id`, `name`, `class`, the element's tag name, other attributes, and finally its position in the DOM

The first attribute that uniquely identifies the element, with a value that isn't excluded by your [`attributeFilters`](/accessibility/configuration/attributefilters), becomes the element's selector. That selector is displayed as the violation target throughout your reports and drives how results are deduplicated across snapshots.

Keep these behaviors in mind when building your list:

- **Your list is added to the defaults, not a replacement for them.** An element that has none of your attributes is still identified by `data-testid`, `id`, or whatever else it has, exactly as it would be without configuration. To stop an attribute from being used entirely, use [`attributeFilters`](/accessibility/configuration/attributefilters); listing other attributes in `significantAttributes` doesn't disable it.
- **To reorder the defaults, list them.** Your entries outrank every default, so `"significantAttributes": ["data-qa"]` is all it takes to check `data-qa` before `data-cy`.
- **The attribute must identify the element uniquely.** When several elements share the same attribute value, that attribute alone can't distinguish them, so the selector is built from the next candidates in the list.
- **Filtered values are skipped, not final.** When an [`attributeFilters`](/accessibility/configuration/attributefilters) rule excludes the value of a higher-priority attribute, Cypress Accessibility moves on to the next attribute in the list. The two properties work together: `significantAttributes` sets the preference order, and `attributeFilters` removes unusable values from consideration.

### Validation rules

<SignificantAttributesValidation />

## Examples

### Identify violation targets by a component attribute

Your configured attribute outranks the defaults, so the image with a missing `alt` attribute is reported under `data-component` even though `data-testid` is also present, and the issue reads as "the ProductImage component" instead of a test ID.

#### Config

```json title="App Quality Config"
{
  "significantAttributes": ["data-component"]
}
```

#### HTML

```xml
<body>
  <img data-component="ProductImage" data-testid="product-42-img" src="product.png" />
</body>
```

#### Result

The violation target selector displayed in the report:

```
[data-component="ProductImage"]
```

---

### List several attributes in priority order

`significantAttributes` is a list, so you can prioritize more than one attribute. They're checked in the order you write them, and each element is identified by the first attribute it has. This helps when different parts of your application use different conventions.

#### Config

```json title="App Quality Config"
{
  "significantAttributes": ["data-qa", "data-component"]
}
```

#### HTML

```xml
<body>
  <button data-qa="save" data-component="SaveButton">Save</button>
  <button data-component="CancelButton">Cancel</button>
</body>
```

#### Result

The Save button has both attributes, so `data-qa`, listed first, identifies it. The Cancel button has only `data-component`, so that identifies it instead:

```
[data-qa="save"]
[data-component="CancelButton"]
```

---

### Review `aria-label` wording while you triage

Significant attributes aren't limited to `data-*` attributes; any HTML attribute qualifies, including `aria-label`. Listing it identifies elements by their label text throughout the report.

This adds a manual check on top of the automated one. Cypress Accessibility can confirm that a control _has_ an accessible name, but not that the name is understandable, so `aria-label="button"` satisfies the name-presence rules exactly like `aria-label="Close dialog"`. When `aria-label` is a significant attribute, the elements you review are shown by their label text, so an unclear label is visible as you triage rather than hidden behind a generated selector. To read the wording of every labeled control, not only those with accessibility results, set `aria-label` at the root of your configuration so [UI Coverage](/ui-coverage/configuration/significantattributes) lists them all.

#### Config

```json title="App Quality Config"
{
  "significantAttributes": ["aria-label"]
}
```

#### HTML

```xml
<body>
  <button aria-label="Close dialog"><i class="icon-x"></i></button>
  <button aria-label="button"><i class="icon-x"></i></button>
</body>
```

#### Result

Both labels satisfy the automated name-presence check, and the elements are shown in the report by their label text, where the vague second label is easy to catch:

```
[aria-label="Close dialog"]
[aria-label="button"]
```

Because the label text becomes the identifier, `aria-label` values that are localized or include dynamic content, such as an unread count, change between snapshots and split one element into several. Choose it when the labels you want to review are stable.

---

### Promote a default attribute

Both defaults are present, and by default `data-cy` would win. Listing `data-qa` moves it above every default, so it identifies the element instead.

#### Config

```json title="App Quality Config"
{
  "significantAttributes": ["data-qa"]
}
```

#### HTML

```xml
<body>
  <input data-cy="widget-4172" data-qa="search-input" />
</body>
```

#### Result

The violation target selector displayed in the report:

```
[data-qa="search-input"]
```

---

### Deduplicate an element with a dynamic ID

This button's `id` is regenerated on every page load, and it has no test attribute, so by default each snapshot produces a different selector and the same violation is counted against what looks like a new element. The `data-automation-id` your team maintains is stable, and listing it makes every snapshot resolve to one element.

#### Config

```json title="App Quality Config"
{
  "significantAttributes": ["data-automation-id"]
}
```

#### HTML

```xml

<button id="btn-829142" data-automation-id="checkout-submit"></button>


<button id="btn-107563" data-automation-id="checkout-submit"></button>
```

#### Result

Without the configuration, the report can show the same empty button twice, as `#btn-829142` and `#btn-107563`. With it, one element is reported:

```
[data-automation-id="checkout-submit"]
```

Since the dynamic `id` values still exist, also consider an [`attributeFilters`](/accessibility/configuration/attributefilters) rule that excludes them, so they can't identify any element, including elements without your attribute.

:::tip

After saving configuration changes, regenerate a recent run to preview the effect of your rules without rerunning your tests. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for how to regenerate a report.

:::

## See also

- [Element identification](/accessibility/core-concepts/element-identification): how elements are identified across snapshots.
- [`attributeFilters`](/accessibility/configuration/attributefilters): stop dynamic or generated attribute values from identifying elements.
- [`components`](/accessibility/configuration/components): require component-identifying attributes in violation target selectors.
- [`elementFilters`](/accessibility/configuration/elementfilters): ignore elements in reports entirely.
- [Configuration overview](/accessibility/configuration/overview): where to set configuration and regenerate reports.
- [Cypress Accessibility FAQ](/accessibility/faq): common questions and troubleshooting.

---

### Accessibility Configuration Viewfilters (`docs/accessibility/configuration/viewfilters.mdx`)

---
title: 'viewFilters: exclude URLs from scans'
description: 'The viewFilters configuration excludes URLs from Cypress Accessibility, so third-party pages and other URLs outside your control are left out of your accessibility reports.'
sidebar_label: 'viewFilters'
sidebar_position: 30
---

<ProductHeading product="accessibility" />

# Exclude views - `viewFilters`

The `viewFilters` configuration excludes URLs from Cypress Accessibility. By default, every URL your tests visit is included. A `viewFilters` rule with `include: false` removes matching URLs before any analysis happens: their snapshots are not scanned for accessibility violations and don't appear in your report. The result is a report and [accessibility score](/accessibility/core-concepts/accessibility-score) that reflect the parts of your application you own and can remediate.

## Why use viewFilters?

- **Exclude third-party pages**: Your tests may pass through pages you don't control, such as an OAuth provider's login page or a payment processor's checkout. Violations on those pages aren't yours to fix, so excluding them keeps your report actionable.
- **Exclude pages outside your remediation scope**: Remove sections that aren't part of your accessibility goals yet, such as internal admin tools or legacy areas, so your score tracks the pages you're actively improving.
- **Reduce noise**: URLs that tests visit incidentally, such as error pages or intermediate redirect URLs, don't represent meaningful user flows. Excluding them keeps reports clean.

To remove individual elements from scans rather than whole pages, use [`elementFilters`](/accessibility/configuration/elementfilters) instead. To organize URLs into views rather than removing them, use [`views`](/accessibility/configuration/views).

## Scope

:::info

A root-level `viewFilters` property applies to both Cypress Accessibility and UI Coverage. To configure Cypress Accessibility separately, nest `viewFilters` under an `accessibility` key. A nested `viewFilters` completely replaces the root-level one for Cypress Accessibility; the two lists are not merged.

:::

<ViewFiltersSyntax />

To add or edit `viewFilters`, open the **App Quality** tab in your project settings in Cypress Cloud. After saving, regenerate a recent run to see the effect of your filters without rerunning your tests. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration) for details.

<ViewFiltersOptions />

### How are viewFilters rules applied?

- Every URL visited during a run is compared against your rules in order. The **first** rule whose `pattern` matches decides whether that URL is included or excluded, so place specific rules before broad ones.
- URLs that match no rule are **included** by default. To include only specific URLs, list `include: true` rules for them followed by a catch-all `{ "pattern": "*", "include": false }` rule.

<ViewFiltersMatchingAndValidation />

## Examples

### Exclude a third-party page

Tests that sign in through an external identity provider capture snapshots of its pages, and any violations found there appear in your report even though you can't fix them. One rule removes those pages, while every other URL stays included by default.

<ViewFiltersExampleThirdParty />

---

<ViewFiltersSharedExamples />

---

### Exclude URLs from Cypress Accessibility only

Nesting `viewFilters` under `accessibility` applies the rules to Cypress Accessibility alone. Here, a legacy admin area that isn't in remediation scope yet is excluded from accessibility scans while UI Coverage continues to track it.

#### Config

```json title="App Quality Config"
{
  "accessibility": {
    "viewFilters": [
      {
        "pattern": "https://admin.my-app.com/*",
        "include": false,
        "comment": "Legacy admin area, not yet in accessibility remediation scope"
      }
    ]
  }
}
```

A nested `viewFilters` replaces any root-level `viewFilters` for Cypress Accessibility, so include every rule the product needs in the nested list.

## Troubleshooting

### A URL you excluded still appears in the report

- Rules apply in order, and the first match wins. Check whether an earlier rule with `include: true` matches the URL.
- A pattern that starts with a hostname, like `my-app.com/admin`, is interpreted as a path rather than a hostname and never matches the URLs you intend. Include the protocol, as in `https://my-app.com/admin/*`, or use the path-only form `/admin/*`.
- Hostnames must match exactly. `https://my-app.com/*` doesn't match URLs on `www.my-app.com`; add a wildcard such as `https://*.my-app.com/*` to span subdomains.
- Reports use the configuration saved at the time they were processed. Regenerate the run to apply your current configuration. See [Setting configuration](/accessibility/configuration/overview#Setting-Configuration).

<ViewFiltersTroubleshootingValidationErrors />

## See also

- [`views` configuration](/accessibility/configuration/views) groups and names URLs instead of removing them.
- [`elementFilters` configuration](/accessibility/configuration/elementfilters) removes individual elements from scans rather than whole pages.
- [Accessibility score](/accessibility/core-concepts/accessibility-score) explains how the score your filters affect is calculated.
- [Configuration overview](/accessibility/configuration/overview) covers where configuration lives and how to regenerate reports after changing it.
- [Cypress Accessibility FAQ](/accessibility/faq) answers common questions about excluding URLs and configuration.

---

### Accessibility Configuration Views (`docs/accessibility/configuration/views.mdx`)

---
title: 'views: group URLs with URL patterns in Cypress Accessibility'
description: 'The views configuration groups related URLs into a single view in Cypress Accessibility using URL patterns, so accessibility reports and scores are organized around the real pages of your application instead of the shape of your test data.'
sidebar_label: 'views'
sidebar_position: 20
---

import { toc as viewsToc } from '@site/docs/partials/_views.mdx'

export const toc = [
  ...viewsToc,
  { value: 'See also', id: 'See-also', level: 2 },
]

<ProductHeading product="accessibility" />

# Group & name views - `views`

Cypress Accessibility organizes every report around **views**, the distinct pages and components of your application. Each view collects the [snapshots](/accessibility/reports/run-level-reports#Snapshots) captured on that page and reports the accessibility violations found there, so you review, score, and track each part of your app as a unit.

The `views` configuration controls that grouping. Without it, URLs that differ only by a username, slug, or other non-numeric value each become their own view, so a single violation on a shared page template is reported once per URL and one issue is split across many rows. A `views` pattern rolls those URLs into one view, so you triage the violation once for the whole page and your report reflects the structure of your application, not the shape of your test data.

The reference below covers the full `views` syntax, including how URLs are matched, the `groupBy` option, and worked examples.

<Views />

## See also

- [Views in accessibility reports](/accessibility/reports/run-level-reports#Views): how views organize your report and per-view score
- [`viewFilters` configuration](/accessibility/configuration/viewfilters): exclude URLs from your reports instead of grouping them
- [Configuration overview](/accessibility/configuration/overview): how to set configuration for your project
- [Cypress Accessibility FAQ](/accessibility/faq#Grouping-and-naming-views): common questions about grouping and naming views

---

### Accessibility Connect And Extend Download Reports (`docs/accessibility/connect-and-extend/download-reports.mdx`)

---
title: 'Download an Accessibility report'
description: "Export a Cypress run's accessibility violations as a CSV or JSON file for offline analysis, sharing, or handing to an AI agent."
sidebar_label: Download reports
sidebar_position: 20
---

<ProductHeading product="accessibility" />

# Download reports

The download button at the top of a run's Accessibility report exports the run's violations as a file you can keep, share, or hand to an AI agent for analysis. It sits beside the **Documentation** link as a download icon; select it to choose either `.csv` or `.json`.

<DocsImage
  src="/img/accessibility/connect-and-extend/download-report.png"
  alt="The Accessibility tab of a Cypress Cloud run. A toolbar at the top of the report shows Compare to previous run, Submit feedback, and Documentation controls, followed by a download icon button. The download button has been selected, opening a small menu with two options: .csv and .json."
  width="80%"
/>

The export is a portable snapshot of a single run. Unlike the [Results API](/accessibility/connect-and-extend/results-api) (built for CI assertions) and [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) (built for live querying), a downloaded report needs no Cloud connection to work with after the fact. This makes it a good fit for:

- offline analysis
- custom spreadsheets and charts
- sharing with people who don't use Cypress Cloud
- comparing multiple runs in detail by downloading a file for each

For other ways to get results out of Cypress Cloud, see the [Connect & extend overview](/accessibility/connect-and-extend/overview).

## What's in the file {#Whats-in-the-file}

Each row represents a single failed element for a single rule on a single view. Because an element can fail the same rule on more than one view, that element appears once per view. Both formats contain the same fields:

| Column            | Description                                                                                   |
| ----------------- | --------------------------------------------------------------------------------------------- |
| Rule ID           | The Axe Core® or [Cypress rule](/accessibility/core-concepts/cypress-rules) identifier.       |
| Description       | A summary of what the rule checks.                                                            |
| Impact            | The severity level: critical, serious, moderate, or minor.                                    |
| Help              | A short description of how to fix the issue.                                                  |
| Help URL          | A link to the rule's documentation.                                                           |
| Tags              | The standards and categories associated with the rule, such as `wcag2aa`.                     |
| Element           | The selector identifying the failing element.                                                 |
| Element URL       | A deep link into the Cloud report, filtered to this element.                                  |
| Status            | The element's status: `fail`, `incomplete`, or `ignore` (only `fail` is currently supported). |
| Failure Summaries | The specific reasons the element failed, as reported during the run.                          |
| View              | The name of the page or component where the element was found.                                |
| View URL          | A deep link into the Cloud report for this view.                                              |

The **Element URL** and **View URL** columns link back to the live report in Cypress Cloud, so you (or an agent) can always jump from a row to the full DOM snapshot and context.

The `.json` export wraps the rows in an object with `rows`, `rowCount`, `truncated`, and `columns` fields. The `truncated` flag is `true` only if a run is large enough to exceed the export's row limit; typical runs are well within it. In the `.csv` export, multi-value fields such as **Tags** and **Failure Summaries** are JSON-encoded within their cell so they parse back cleanly.

### Map the results to your components

If you configure [component identification](/accessibility/configuration/components), the **Element** selector in each row reflects a true hierarchy of your components rather than a raw DOM path. This makes patterns easy to spot—such as one component being responsible for a large share of a run's violations—and lets an AI agent trace an issue to its source without re-parsing full-page HTML or crawling your codebase. See [Work with AI agents](/accessibility/work-with-ai-agents#Map-violations-to-your-components) for how this pays off.

## Work with the downloaded file

A downloaded report is designed to be handed straight to an AI agent to interpret, chart, or compare against another run. For concrete prompts and workflows, see [Work with a downloaded report](/accessibility/work-with-ai-agents#Work-with-a-downloaded-report).

---

### Accessibility Connect And Extend Results Api (`docs/accessibility/connect-and-extend/results-api.mdx`)

---
title: 'Accessibility Results API: enforce standards in CI'
description: 'Programmatically fetch Accessibility results in a CI environment and fail your pipeline if your standards are not met.'
sidebar_label: Results API
sidebar_position: 30
---

<ProductHeading product="accessibility" />

# Results API

The `@cypress/extract-cloud-results` module provides the `getAccessibilityResults` utility which enables you to programmatically fetch your run's Accessibility results in a CI environment. It determines the Cypress run created for the given CI workflow and will return the Accessibility results associated with that run. The results will be returned once the Cypress run has finished and the Accessibility report has been processed.

This brings the results into CI, where you review them and determine if they are acceptable or need to be addressed before code changes can merge. It provides overall accessibility scores and violation details for the runs, as well as page- or component-level feedback. This supports a wide variety of needs related to alerting about failures in specific focus areas of the application or creating fine-grained regression monitoring according to the current standards being met by each page.

:::info

<CalloutLabel icon="question-circle" color="#0097A8">
  Examples and use cases
</CalloutLabel>

This page focuses on how the Results API works and what kinds of information can be accessed. For examples of how this can be used, see our higher-level guides:

- The [pull requests and policies guide](/accessibility/guides/block-pull-requests) shows what it looks like to use the Results API to set a policy and fail a pull request.
- The guide for [catching accessibility regressions](/accessibility/guides/detect-changes#enforce-a-standard-in-ci) shows some other common use cases.

:::

## Supported CI Providers

Fetching Accessibility results for a run supports fetching results for the following CI providers. See the docs below for information on general setup.

- [Azure](/app/continuous-integration/overview#Azure-Pipelines) (requires Cypress v13.13.1)
- [CircleCI ](/app/continuous-integration/circleci)
- [GitHub Actions](/app/continuous-integration/github-actions)
- [GitLab](/app/continuous-integration/gitlab-ci)
- [Jenkins](/app/continuous-integration/overview#Jenkins)
- [AWS CodeBuild](/app/continuous-integration/aws-codebuild)
- Drone
- [Bitbucket](/app/continuous-integration/bitbucket-pipelines)
- Buildkite

Reach out to Cypress Support to request support for a different provider.

## Installation

Install the `@cypress/extract-cloud-results` module in your install step in CI.

```shell
npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
```

:::caution

Do not check this module in as a dependency. You should install it separately outside of your normal module installation. Use `--force` to get the latest version.

If you check this in as a dependency, your installation will fail when we update the package.

:::

## Usage

### **1. Get the Results**

Write a script using the `getAccessibilityResults` utility to retrieve the results and perform one or more assertions to verify if the changes are acceptable. This script will be executed in CI.

#### Basic example

This snippet uses the `getAccessibilityResults()` helper to log out the results. It assumes your Project ID and Record Key variable are set. The following should work in any of the supported CI Providers out of the box:

```javascript title="scripts/verifyAccessibilityResults.js"
// Assuming these environment variables are set:
// CYPRESS_PROJECT_ID=your-id
// CYPRESS_RECORD_KEY=your-record-key

const { getAccessibilityResults } = require('@cypress/extract-cloud-results')

getAccessibilityResults().then((results) => {
  // use `console.dir` instead of `console.log` because the data is nested
  console.dir(results, { depth: Infinity })
})
```

#### How to assert that only known rules are failing in the run

The Cypress App [repository](https://github.com/cypress-io/cypress) uses the Results API to ensure no new violations have been introduced. You can reference [this script](https://github.com/cypress-io/cypress/blob/develop/scripts/verify-accessibility-results.js) as a real example.

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### How to detect a change in the axe-core version {#how-to-detect-a-change-in-the-axe-core-version}

Each result includes the `axeVersion` used to generate the report. Cypress updates its internal Axe-Core® version periodically, and a new version can add rules or change how issues are detected. You can pin the version your team has reviewed and get a heads-up when it changes, so you can reconcile any new results before they surprise you. See [Axe Core® library version and updates](/accessibility/configuration/axe-core-configuration#axe-core-library-version-and-updates) for the update policy.

```javascript title="scripts/checkAxeVersion.js"
const { getAccessibilityResults } = require('@cypress/extract-cloud-results')

// The Axe-Core® version your team has last reviewed and calibrated against.
// Bump this deliberately, after reconciling a new Axe-Core® release.
const EXPECTED_AXE_VERSION = '4.12.1'

getAccessibilityResults().then((results) => {
  if (!results) {
    console.warn('No Accessibility report was found for this run.')
    return
  }

  const { axeVersion, runNumber, accessibilityReportUrl } = results

  if (axeVersion === EXPECTED_AXE_VERSION) {
    console.log(
      `Accessibility report used the expected Axe-Core® ${axeVersion}.`
    )
    return
  }

  console.warn(
    `Cypress Accessibility used Axe-Core® ${axeVersion} for run #${runNumber}, but this project is calibrated against ${EXPECTED_AXE_VERSION}.`
  )
  console.warn(
    `Review the release notes at https://github.com/dequelabs/axe-core/releases, reconcile any new results, then update EXPECTED_AXE_VERSION. Report: ${accessibilityReportUrl}`
  )

  // Opt in to a hard failure so the pipeline blocks until the bump is reviewed:
  if (process.env.FAIL_ON_AXE_VERSION_CHANGE === 'true') {
    throw new Error(
      `Axe-Core® version changed from ${EXPECTED_AXE_VERSION} to ${axeVersion}. Review the changes and update the expected version.`
    )
  }
})
```

Warning by default is usually the right posture, since a version change isn't a failure on its own. Set `FAIL_ON_AXE_VERSION_CHANGE=true` when you want CI to stop until someone reviews the bump.

### `getAccessibilityResults` Arguments

`getAccessibilityResults` uses the following attributes to identify the Cypress run and return the Accessibility results:

```javascript
getAccessibilityResults({
  // The Cypress project ID.
  // Optional if the CYPRESS_PROJECT_ID env is set
  // Can be explicitly passed to override the env var
  projectId: string

  // The project's record key.
  // Optional if the CYPRESS_RECORD_KEY env is set
  // Can be explicitly passed to override the env var
  recordKey: string

  // The run tags associated with the run.
  // Required IF you are recording multiple Cypress runs from a single CI build.
  // Pass the run tags you used when recording in each run
  // See below for more information
  runTags: string[]
})
```

#### Result Types

The Accessibility results for the run are returned as an object containing the following data:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Comparing against a baseline

For comprehensive examples of comparing results against a baseline, including complete code examples, baseline structure, and best practices, see the [Block pull requests and set policies](/accessibility/guides/block-pull-requests#comparing-against-a-baseline) guide.

### **2. Add to CI Workflow**

In your CI workflow that runs your Cypress tests,

1. Update your install job to install the `@cypress/extract-cloud-results` module.
2. Pass in the necessary arguments to `getAccessibilityResults`.
3. Add a new step to the job that runs your Cypress tests to verify the Accessibility results.

:::info

If you record multiple runs in a single CI build, you must record these runs using the `--tag` parameter and then call `getAccessibilityResults` with the `runTags` argument for each run.

This is necessary to identify each unique run and return a corresponding set of results. The tags are how each run is uniquely identified. Tags can also be used to activate [Profiles](/accessibility/configuration/profiles) that apply different configuration settings to your runs.

**Example**

- Let's imagine that within a single CI build you call `cypress run --record` multiple times because you're running one set of tests against a `staging` environment, followed by a `production` environment.
- In this scenario, you pass a different `--tag` to each cypress run.
  - `cypress run --record --tag staging`
  - `cypress run --record --tag production`
- When calling `getAccessibilityResults` you would then pass these same tags to get the unique set of results for each run.
  - `getAccessibilityResults({ runTags: ['staging']})`
  - `getAccessibilityResults({ runTags: ['production']})`

:::

#### Example Job Workflow Update:

<Tabs groupId="a11y-results-api">
<TabItem value="GitHub Actions" active>

```diff title="test_cypress.yaml"
name: My Workflow
on: push

env:
  CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}

jobs:
  run-cypress:
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout
        uses: actions/checkout@v7
      - name: install
        run: npm install
      - name: Run
        run: npx cypress run --record
+     - name: Verify Accessibility Results
+       run: |
+          npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+          node ./scripts/verifyAccessibilityResults.js
```

</TabItem>

<TabItem value="GitLab">

```diff title=".git-ci.yml"
name: Run Cypress Tests

image: node:latest

stages:
  - test

run-cypress:
  stage: test
  secrets:
    CYPRESS_RECORD_KEY:
      vault: vault/cypressRecordKey
  script:
    - npm install
    - npx cypress run --record
+   - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+   - node ./scripts/verifyAccessibilityResults.js
```

</TabItem>

<TabItem value="Jenkins">

```diff
pipeline {
  agent {
    docker {
      image 'cypress/base:22.15.0'
    }
  }

  environment {
    CYPRESS_PROJECT_ID: 'xxxx'
    CYPRESS_RECORD_KEY = credentials('cypress-record-key')
  }

  stages {
    stage('build and test') {
      steps {
        sh 'npm ci'
        sh 'npx cypress run --record'
      }
    }

+   stage('Verify Accessibility Results') {
+     steps {
+       sh 'npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz'
+       sh 'node ./scripts/verifyAccessibilityResults.js'
+     }
+   }
  }
}
```

</TabItem>

<TabItem value="Azure">

```diff
jobs:
  - job: run_tests
    pool:
      vmImage: 'ubuntu-latest'
    steps:
      - task: NodeTool@0
        inputs:
          versionSpec: '22.x'
          displayName: 'Install Node.js'

      - script: npm i
        displayName: 'Install npm dependencies'

      - script: npx cypress run --record
        displayName: 'Run Cypress tests'
        env:
          # avoid warnings about terminal
          TERM: xterm
          CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY)

+     - script: |
+           npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+           node ./scripts/verifyAccessibilityResults.js
+       displayName: 'Verify Accessibility Results'
+       env:
+         CYPRESS_PROJECT_ID: $(CYPRESS_PROJECT_ID)
+         CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY)
```

</TabItem>

<TabItem value="CircleCI">

```diff
version: 2.1

jobs:
  linux-test:
    docker:
      - image: cypress/base:22.15.0

    working_directory: ~/repo
    steps:
      - checkout
      - run: npm install
      - run: npx run cypress:run --record
+     - run: npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+     - run: node ./scripts/verifyAccessibilityResults.js

workflows:
  version: 2
  tests:
    jobs:
      - run-cypress
```

</TabItem>

<TabItem value="AWS CodeBuild" >

```diff title="buildspec.yaml"
phases:
  install:
    runtime-versions:
      nodejs: latest
    commands:
      # Set COMMIT_INFO variables to send Git specifics to Cypress Cloud when recording
      # https://docs.cypress.io/app/continuous-integration/overview#Git-information
      - export COMMIT_INFO_BRANCH="$(git rev-parse HEAD | xargs git name-rev |
        cut -d' ' -f2 | sed 's/remotes\/origin\///g')"
      - export COMMIT_INFO_MESSAGE="$(git log -1 --pretty=%B)"
      - export COMMIT_INFO_EMAIL="$(git log -1 --pretty=%ae)"
      - export COMMIT_INFO_AUTHOR="$(git log -1 --pretty=%an)"
      - export COMMIT_INFO_SHA="$(git log -1 --pretty=%H)"
      - export COMMIT_INFO_REMOTE="$(git config --get remote.origin.url)"
      - npm ci
  pre_build:
    commands:
      - npm run cypress:verify
      - npm run cypress:info
  build:
    commands:
      - CYPRESS_INTERNAL_ENV=staging CYPRESS_PROJECT_ID=[slug] npx cypress run --record --key [KEY]
+  post_build:
+    commands:
+      - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+      - CYPRESS_INTERNAL_ENV=staging CYPRESS_PROJECT_ID=[slug] CYPRESS_RECORD_KEY=[KEY] node ./scripts/verifyAccessibilityResults.js
```

</TabItem>

<TabItem value="Drone" >
```diff title=".drone.yaml"
  kind: pipeline
  name: default

environment:
CYPRESS_PROJECT_ID: example_project_slug
CYPRESS_RECORD_KEY:
from_secret: example_record_key_secret

steps:

- name: test
  image: node:latest
  commands:
  - npm install
  - npx cypress run --record

* - name: validate
* image: node:latest
* commands:
* - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
* - node ./scripts/verifyAccessibilityResults.js

````
</TabItem>

<TabItem value="Bitbucket" >

```diff title="bitbucket-pipelines.yml"
image: node:latest

pipelines:
  default:
    - step:
        name: Run Cypress tests
        script:
          - npm install
          - npx cypress run --record
+         - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+         - node ./scripts/verifyAccessibilityResults.js
````

</TabItem>

<TabItem value="Buildkite" >

```diff title="pipeline.yml"
steps:
  - label: "Run Cypress tests"
    command:
      - npm install
      - npx cypress run --record
+     - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
+     - node ./scripts/verifyAccessibilityResults.js
```

</TabItem>
</Tabs>

## Required CI environment variables

<ResultsApiEnvVars />

```

```

---

### Accessibility Connect And Extend Webhooks (`docs/accessibility/connect-and-extend/webhooks.mdx`)

---
title: 'Send Cypress Accessibility results with webhooks'
description: 'Use the run.accessibility.completed webhook to post Accessibility results to Google Chat, triage reports before AI analysis, and send scores to dashboards.'
sidebar_label: Webhooks
sidebar_position: 25
---

<ProductHeading product="accessibility" />

# Accessibility webhooks

Cypress Accessibility webhooks move a finished report into the systems where your team already works. Cypress Cloud sends the [`run.accessibility.completed` event](/cloud/integrations/webhooks#Events) when the report finishes processing, so a workflow can start from that report without polling Cypress Cloud or waiting on a CI job.

## Example use cases for Cypress Accessibility webhook events

### Send Accessibility results to Google Chat

Keep the team informed in a channel that Cypress Cloud doesn't have a built-in integration for. The payload includes the project name, branch, Accessibility score, violation counts by impact, and a direct `reportUrl`. A receiver such as a Google Apps Script web app can turn those fields into a Google Chat message that links back to the report.

### Triage Accessibility reports before AI analysis

Reserve AI analysis and token usage for reports that need attention. Cypress Cloud sends the event after Accessibility processing finishes, and the payload identifies processing failures and partial reports while summarizing the score and violations. Your receiver can use those fields to decide whether to investigate, then pass the run URL to the [Cypress Cloud CLI](/cloud/integrations/cloud-cli) or [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) for detailed analysis.

### Add Accessibility scores to engineering dashboards

Put accessibility alongside the quality and ownership signals your team already tracks in Cortex, Datadog, or another internal system. The payload provides stable project and run identifiers, branch and commit data, timestamps, the score, violation counts, and the Axe Core® version. Your receiver can transform those fields into metrics or events for dashboards, alerts, and service scorecards.

Setup, payload fields, test events, signature verification, and retry behavior are in the [Cypress Cloud webhooks documentation](/cloud/integrations/webhooks).

## See also

- [Connect & extend](/accessibility/connect-and-extend/overview) lists the other ways to get Cypress Accessibility results out of Cypress Cloud.
- [Webhooks integration](/cloud/integrations/webhooks) documents events, payloads, headers, security, and retries.
- [Build custom integrations with webhooks](/cloud/guides/webhooks) walks through a Slack message for a completed run.
- [Cypress Cloud CLI](/cloud/integrations/cloud-cli) inspects a specific run from the terminal.
- [Cypress Cloud MCP](/cloud/integrations/cloud-mcp) queries a specific run from an AI client.

---

### Accessibility Core Concepts Accessibility Score (`docs/accessibility/core-concepts/accessibility-score.mdx`)

---
title: How the accessibility score is calculated
description: 'Cypress produces a top-line percentage score that indicates a general sense of accessibility for a project.'
sidebar_label: Accessibility score
sidebar_position: 30
---

<ProductHeading product="accessibility" />

# Accessibility score

Cypress provides a top-line percentage score to give a general sense of accessibility for your project. This score, calculated for a run, reflects the **average score** of **all application snapshots** captured during the run. It is based on the ratio of passing versus failing accessibility checks for each snapshot, with results weighted by the severity of the issues.

## Severity levels

Severity levels in Cypress Accessibility align with the Axe Core® impact classification. Developed by Deque Systems, this classification helps prioritize accessibility issues by highlighting those likely to create the most substantial barriers for users (such as missing label text) so they can be addressed first. You can learn more about the Axe Core® impact classification in the [Axe Core® documentation](https://github.com/dequelabs/axe-core/blob/develop/doc/issue_impact.md).

_Note: WCAG standards do not categorize Success Criteria by severity; all failures require resolution for compliance. However, Axe Core® impact levels are helpful for prioritizing fixes to maximize usability improvements quickly._

## Scoring algorithm

The accessibility score calculation applies the following weights to failed accessibility checks in a snapshot.

| Severity of Issue | Weight |
| ----------------- | ------ |
| Critical          | 10     |
| Serious           | 7      |
| Moderate          | 3      |
| Minor             | 1      |

### Score Calculation Process

1. **Snapshot Score:**

- Calculate the total weight of passed checks.
- Calculate the total weight of failed checks.
- Compute the score as: `Score = (Passed Weights) / (Passed Weights + Failed Weights)`.

**Note**: Incomplete and Ignored element statuses do not have any effect on your score. Only clear failures of a rule are counted.

2. **View Score:**

- Average the scores of all snapshots within the View.

3. **Run Score:**

- Average the scores of all snapshots in the run.

## Interpreting your scores

Accessibility scores should be viewed in the context of your specific project and your goals. There is no single number that can tell you the accessibility of your application. For example:

- A score of 99% may indicate progress if the previous score was lower, but a single failure could represent a significant barrier (e.g., an inaccessible login page).
- Even a 100% score does not guarantee full compliance or user-friendliness but indicates that Axe Core® detected no violations in the tested scope.

The key value of the score is that the calculation is repeated consistently across runs - Cypress is not trying to catch anything "in the moment" during test execution. This means that changes in the score reliably reflect accessibility improvements or regressions.

In general, the ideal state is a clean 100% score in your Cypress Accessibility report, which you can achieve with a combination of fixing existing issues and ignoring things you know you won't fix.

## What a 100% score means

A 100% score with Cypress Accessibility means:

- No Axe Core® violations were detected in the tested scope.
- Up to 57% of issues typically identified in manual audits have been addressed ([source](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/)).
- While not a guarantee of full compliance, it reflects that the team has actively considered accessibility and is well-positioned to address user-reported issues or findings from manual audits.

Reaching a 100% score, also known as "Axe-clean," signals that the application likely meets basic usability needs for disabled users, providing a foundation for further usability enhancements.

## Improving Accessibility scores

### Address Violations

Most accessibility violations can be resolved through HTML and CSS adjustments. Each violation in Cypress Accessibility includes a "Learn More" link to understand the impact of the issue on users and get step-by-step guidance to fix it.

Refer to the [Inspecting Violation Details section](/accessibility/reports/element-detail-view) for more information on understanding and addressing violations.

When you have more violations than you can act on at once, [Fix accessibility violations](/accessibility/guides/improve-accessibility) covers how to narrow the report to the code you own, choose a first rule your team can finish, and verify the fix before it merges.

### Ignore Non-relevant Issues

For issues you decide not to fix, update your [configuration](/accessibility/configuration/overview) to ignore them. This keeps the score focused on actionable issues while maintaining visibility into ignored elements for transparency.

By actively addressing violations and maintaining a clean score, your team can ensure consistent progress towards a more accessible application.

---

### Accessibility Core Concepts Cypress Rules (`docs/accessibility/core-concepts/cypress-rules.mdx`)

---
title: 'Cypress accessibility rules'
description: 'The custom accessibility rules Cypress layers on top of Axe Core® and how each one is evaluated.'
sidebar_label: Cypress rules
sidebar_position: 40
---

<ProductHeading product="accessibility" />

# Cypress rules

In addition to running the default ruleset of the Axe-Core® library, Cypress develops custom rules that take advantage of the additional layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set.

The first custom rule that we have implemented is called "Interactive elements should be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass if no issues are found, or return an inconclusive state.

## Why do we need custom accessibility rules?

Conventional accessibility checks work by scanning the DOM of a web page to discover errors and inconsistencies that would affect the accessibility of the content. These checks use signals based on the nature of the content itself to determine what the correct accessible experience should be. Buttons, links, and form fields without labels can all be detected this way - if they are written correctly.

This form of "passive" accessibility scan is limited to what can be learned from the page itself, because there is no other source of input about the purpose of the elements on the screen. The tools used are typically general-purpose scanners that can be called in many different contexts, not always in a test automation pipeline.

In Cypress Accessibility, we can build rules that move beyond a passive scan and offer more insights about the accessibility of what you are testing based on your existing test activities, which already describe how a user is supposed to move through the application and what elements they use.

This helps provide early detection of issues that might later appear in manual testing or in bug reports from users, increasing the total range of issues detectable in an automated scan without custom assertions or setup.

## Interactive elements should be semantically correct

- **ID**: `cy-semantic-html-warning`
- **Tag**: `cypress-rule`
- **Severity**: `serious`

:::caution
This rule requires that runs be recorded using Cypress version 13.14.0 or above.
:::

<DocsImage
  src="/img/accessibility/core-concepts/cypress-rule.png"
  width="60%"
  alt="A custom Cypress accessibility rule called 'Interactive elements should be semantically correct' has two failed elements displayed. One element is open and message reads 'This element should use semantic HTML or ARIA to support the interactions that take place during tests. Detected interactions: mousedown, mouseup, click."
/>

This custom rule is intended to surface potential usability problems with the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, such as div, span, SVG, and image elements.

This works based on the interactions that take place during testing. Often an inaccessible custom component will have Cypress tests that perform interactions the way a user does, and that allows us to detect a mismatch between the underlying purpose of the element in code, and the usage of the element in the context of a test.

### How to pass this rule

You should look at the purpose and nature of the specific elements flagged by this rule and decide what interactive element is appropriate.

For example:

- If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be to instead use a standard HTML button element. This communicates the expected action and is activated with the space bar or enter key.

- If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution would be to instead use a link element with a `href` attribute.

In each case, the solution is to choose the element that provides the best information to the user, so they can independently understand what the action does, and activate it.

After you have updated to a suitable HTML solution, elements will then be able to be correctly parsed and analyzed by the standard Axe-Core® checks.

:::info
**Tip**: Follow the [first rule of ARIA use](https://www.w3.org/TR/using-aria/#firstrule) and implement interactive controls with standard semantic HTML where possible, relying on ARIA `role` attributes only when no suitable HTML element is available.
:::

### Why this matters

In the Web Content Accessibility Guidelines (WCAG), interactive elements are required to meet a wide range of Success Criteria (SCs) to follow the POUR principles, which stands for Perceivable, Operable, Understandable, and Robust.

Interactive elements that are not semantically correct often don't appear in automated scans, but do appear in manual testing, because they are usually not operable with a keyboard or correctly understandable when described by a screen reader.

Custom components implemented this way have a direct impact on the independence of disabled users.

### Related WCAG Success Criteria

An incorrectly implemented interactive element may be failing multiple Success Criteria from WCAG, for example:

- [SC 1.3.1 Info and Relationships](https://www.w3.org/TR/WCAG21/#info-and-relationships)
  - Elements may incorrectly appear to be non-interactive generic elements
- [SC 2.1.1 Keyboard](https://www.w3.org/TR/WCAG21/#keyboard)
  - Non-interactive elements require custom implementations for keyboard accessibility and focus states
- [SC 4.1.2 Name, Role, Value](https://www.w3.org/TR/WCAG21/#name-role-value)
  - Non-interactive elements require explicit ARIA roles to have their function and name correctly described by assistive technology such as screen readers

### Status

This rule is available in all Cypress Accessibility projects, though it is not enabled by default. Reach out to Cypress if you would like to have this rule enabled for you.

### Possible outcomes

For each run, this rule can be in one of four states. Most importantly, it will never fail, which means it will not affect your accessibility score.

| Outcome                      | Description                                                                                                                           |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Pass**                     | No interactive elements with semantic issues were detected during the test run.                                                       |
| **Inconclusive**             | Interactive elements with potential semantic issues were detected. You should review each element and determine the correct solution. |
| **Not Applicable**           | The test run did not interact with any elements, or the version of Cypress was below 13.14.0, so interaction data was not gathered.   |
| **Ignored by configuration** | The rule was not executed during this test run because it was intentionally turned off.                                               |

### False positives

Use the "Submit Feedback" button in the product to let us know if you see something that you think is a false positive. Our goal with any new rules is to follow the general Axe-Core® philosophy that minimizes false positives, so we will make adjustments for specific situations that are not already known as we learn about them.

#### Shadow DOM false positives

There is a known issue related to interactions that take place within some shadow DOM nodes and how they are reported in this rule. If this issue affects your reports, reach out to your Cypress point-of-contact.

---

### Accessibility Core Concepts Element Identification (`docs/accessibility/core-concepts/element-identification.mdx`)

---
title: How Cypress Accessibility identifies elements
description: 'How Cypress Accessibility uniquely identifies elements across views and snapshots using HTML attributes, location, and other DOM signals.'
sidebar_label: Element identification
sidebar_position: 20
---

<ProductHeading product="accessibility" />

# Element Identification

Cypress Accessibility identifies elements across views and snapshots using a combination of HTML attributes, location, and other signals in the DOM. Stable and unique identifiers are crucial for accurately tracking and de-duplicating elements throughout the various snapshots captured in your tests.

If your HTML uses attributes about things like component structure, design system versioning, or team ownership of certain DOM areas, Cypress Accessibility can be configured to include those as well. Configuration can also be used to avoid noisy locators that artificially inflate the count of issues, or to declare preferred identifiers that should be used.

Good element identification makes element selectors more readable and meaningful when [reviewing violation details](/accessibility/reports/element-detail-view), and when [creating tickets](/accessibility/reports/element-detail-view#Create-Jira-issue), or having the selectors interpreted by AI tools (see the we [Work with AI agents](/accessibility/work-with-ai-agents))

## Significant attributes for identification

Cypress Accessibility checks a prioritized list of attributes on each element to find its identifier. The defaults, in priority order, are:

- `data-cy`
- `data-test`
- `data-testid`
- `data-test-id`
- `data-qa`
- `row-id`

When an element has none of these, `id`, `name`, and other DOM signals are used as fallbacks. If you already have Test IDs or similar attributes in your application, Cypress Accessibility will pick these up and use them to recognize the same element in a new place for improved deduplication. This behavior itself is configurable as well, so that highly-dynamic Test IDs can be avoided, for example.

## Configuring element identification

Using these configuration properties helps you adjust the amount of deduplication Cypress will do to match what makes sense in your application. For example, a component-based Test ID might make a great identifier if the component renders static content, but the same exact test ID would be a poor identifier if the component renders different things everywhere - you might rather treat those instances as unique for accessibility purposes.

### Attribute filters

Exclude irrelevant or dynamically generated attributes to reduce noise in Cypress Accessibility reports. For example, this would avoid certain IDs that are commonly generated in React applications from being used as element references in Cypress Accessibility.

```json title="App Quality Config"
{
  "attributeFilters": [
    {
      "attribute": "id",
      "value": ":r.*:",
      "include": false
    }
  ]
}
```

Elements with these IDs will still be included in your accessibility report, but they will be identified in a different way.

Learn more about attribute filtering in the [Attribute Filters guide](/accessibility/configuration/attributefilters).

### Significant attributes

Define custom significant attributes to prioritize specific selectors that align with your application’s structure. For example:

```json title="App Quality Config"
{
  "significantAttributes": ["data-custom-id"]
}
```

Refer to the [Significant Attributes](/accessibility/configuration/significantattributes) guide for detailed instructions.

### Component attributes

Require extra attributes (such as a component or team identifier) in the **violation target selectors** shown in reports, to provide consistency and readability in your selectors:

```json title="App Quality Config"
{
  "accessibility": {
    "components": {
      "componentAttributes": [
        { "attributeName": "data-component-name", "includeInSelector": true }
      ]
    }
  }
}
```

See the [components](/accessibility/configuration/components) configuration guide for `componentAttributeFilters`, defaults, and examples.

## Differences compared to Axe-Core® element identification

The Cypress Cloud process replaces the underlying Axe-Core® library's default mechanism for identifying elements.

Axe-Core® captures a unique identifier for a given element in a specific DOM context, focused on one single state. This default behavior does not account for merging thousands of Axe-Core® scans into a single report or for comparing scans of the application as the application changes.

Taking control over how elements are tracked in your reports helps you get the right level of de-duplication across elements when they are truly the same, and track similar elements individually when they are different.

---

### Accessibility Core Concepts How It Works (`docs/accessibility/core-concepts/how-it-works.mdx`)

---
title: How Cypress Accessibility works
description: 'Accessibility checks are powered by Axe Core® from Deque Systems based on common accessibility standards.'
sidebar_label: 'How it works'
sidebar_position: 10
---

<ProductHeading product="accessibility" />

# How it works

Cypress Accessibility seamlessly integrates accessibility testing into your development pipeline. Below are the stages of the Cypress Accessibility process:

1. **Recording and uploading**: As your test run is recorded, specs are uploaded to Cypress Cloud. Accessibility checks begin based on incoming [Test Replay](/cloud/features/test-replay) data on Cypress Cloud servers.
1. **Processing**: When your run completes, the final specs are processed for accessibility checks. Earlier specs have already entered processing and are likely completed by the end of the run.
1. **Organizing Views**: Cypress Cloud groups Views (pages and components) rendered during the run, merging and deduplicating across tests. This ensures page-level results and live DOM snapshots are organized effectively.
1. **Generating reports**: A combined "rule-level" report is created, summarizing all detected accessibility violations.
1. **Displaying results**: Results are displayed in Cypress Cloud in the run details area as well as in [Branch Review](/accessibility/guides/compare-reports) for comparing runs.
1. **Retreiving results**: Results are accessible via the [Results API](/accessibility/connect-and-extend/results-api) for optional CI pipeline actions (e.g., failing builds based on unmet standards) and via Cloud MCP for agentic triage.

## About Axe Core®

Axe Core® is an open-source library by Deque Systems, widely recognized for detecting accessibility violations. With over a billion downloads on npm, it is used in numerous tools at multiple stages of the software development cycle. If you are already using other Axe Core®-based tools, Cypress Accessibility's configuration can be easily aligned with your existing accessibility standards across different teams and platforms.

Axe Core® checks for accessibility violations in your website's user interface, based on common accessibility standards. A violation detected by Axe usually indicates that some users with disabilities would have a problem using or perceiving a feature. An example of a violation would be an image without alternative text provided in the markup, which means the content is not perceivable to visually-impaired users. [Learn more about Axe.](https://github.com/dequelabs/axe-core)

While this process reaches a high standard for automated testing, it cannot test every possible aspect of compliance, especially for heavily custom interfaces or aspects requiring human judgment.

This means that a 100% axe score does not mean all possible accessibility errors have been ruled out. Deque reports that [Axe Core® can detect up to 57% of the issues that would appear in a manual accessibility audit](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/).

The value of this form of testing in Cypress Accessibility is to give you fast, reliable, easy-to-understand feedback about common accessibility mistakes that are found in most projects. Providing these results automatically as part of your test run means that you can find and fix these issues with minimal friction, shifting accessibility left in your software development lifecycle.

## Axe Core® updates

Axe Core® is regularly updated, with Cypress following a controlled adoption process:

- Update Policy: Cypress Cloud integrates new Axe Core® versions at least 30 days after their release. This provides teams time to review the Axe Core® [changelog](https://github.com/dequelabs/axe-core/blob/develop/CHANGELOG.md) so you can make any necessary adjustments to your process in advance of Cypress Cloud bumping the version.
- Changelog Tracking: Updates are documented in the Cypress Accessibility [changelog](https://github.com/dequelabs/axe-core/blob/develop/CHANGELOG.md), starting December 1, 2024.
- Critical Exceptions: In cases like critical security patches, updates may occur sooner, with notifications provided to affected customers.

## Powered by Test Replay

Cypress Accessibility uses data captured through Test Replay, ensuring comprehensive analysis while being subject to its limitations. Read [How Test Replay Works](/cloud/features/test-replay#How-Test-Replay-Works) to discover which data is captured and which browsers are supported.

---

### Accessibility Get Started Introduction (`docs/accessibility/get-started/introduction.mdx`)

---
title: What is Cypress Accessibility?
description: 'Cypress Accessibility provides organized, visual, and actionable accessibility reports, based completely on the tests you record to Cypress Cloud, and powered by Axe Core® by Deque Systems.'
sidebar_label: Introduction
sidebar_position: 10
---

<ProductHeading product="accessibility" />

# Automated accessibility checks on every test

Cypress Accessibility adds detailed accessibility checks to Cypress Cloud. Checks run against every step of every test, with zero impact on test execution.

- Visualize, triage, and fix accessibility violations without any additional code or configuration.
- Debug each violation with interactive DOM snapshots from.
- Filter to newly-introduced issues related to specific commits.
- Track your team's progress over time with historical scores to monitor improvements and identify regressions.

<Btn
  label="Request trial ➜"
  variant="indigo-dark"
  className="!mb-2 mr-1"
  href="https://www.cypress.io/accessibility?utm_medium=intro-cta&utm_source=docs.cypress.io&utm_content=Request%20trial"
/>
<Btn
  label="See a demo"
  icon="action-play-small"
  className="!mb-2 mr-1"
  href="https://on.cypress.io/accessibility-demo-video"
/>
<Btn
  label=" Explore an example project"
  icon="cypress-accessibility-outline"
  className="!mb-2 mr-1"
  href="https://on.cypress.io/rwa-accessibility-views?utm_source=docs.cypress.io&utm_medium=intro-cta&utm_content=Explore%20an%20example%20project"
/>

<DocsImage
  src="/img/accessibility/get-started/cypress-accessibility-overview.png"
  alt="A graphic showing the Cypress Accessibility dashboard including list of rules, views, and the user interface showing how devtools can be used"
  noBorder={true}
/>

Looking for a general guide for accessibility testing concepts in Cypress App? Go to the [accessibility testing guide](/app/guides/accessibility-testing).

## Get Started

You don't need to make any changes to your code or your test setup. If you record test runs to Cypress Cloud with Test Replay, you're ready to start using Cypress Accessibility.
You'll start your [free trial](https://www.cypress.io/accessibility?utm_medium=intro-cta&utm_source=docs.cypress.io&utm_content=Request%20trial) with personalized support
from our sales team and your existing test data to instantly see full accessibility reports for all your Cypress projects.
From there, you can integrate with CI to set your own standards for handling the results.

[Get started with Cypress Accessibility ➜](/accessibility/get-started/setup)

## Top Guides

{

<ul class="guidesList">
  <li class="card">
    <a
      href="/accessibility/guides/improve-accessibility"
      aria-labelledby="card-title-1"
    >
      <Icon name="chart-line" />
      <div class="card__title" id="card-title-1">
        Fix accessibility violations
      </div>
      <p>
        Turn a large accessibility report into work your team can finish: scope
        the report to the code you own, pick a first rule, fix it, and prove the
        fix landed before the code merges.
      </p>
    </a>
  </li>
  <li class="card">
    <a
      href="/accessibility/guides/detect-changes"
      aria-labelledby="card-title-8"
    >
      <Icon name="shield-halved" />
      <div class="card__title" id="card-title-8">Catch accessibility regressions</div>
      <p>
        Compare reports in detail to review only <i>new</i> accessibility issues, use
        our API to react to runs that don't meet your standards, and spot trends
        with analytics.
      </p>
    </a>
  </li>
  <li class="card">
    <a
      href="/accessibility/work-with-ai-agents"
      aria-labelledby="card-title-9"
    >
      <Icon
        useCypressIcon
        name="general-sparkle-triple"
        size="24"
        fillColor="teal-600"
      />
      <div class="card__title" id="card-title-9">Work with AI agents</div>
      <p>
        Use AI coding assistants with Cypress Cloud MCP to pull accessibility
        summaries, browse failing views and rules, and debug violations with
        structured context from your recorded runs.
      </p>
    </a>
  </li>
  <li class="card">
    <a
      href="/accessibility/guides/block-pull-requests"
      aria-labelledby="card-title-3"
    >
      <Icon name="bug-slash" />
      <div class="card__title" id="card-title-3">Block pull requests and set policies</div>
      <p>
        Set policies and block pull requests automatically with Cypress
        Accessibility's Results API, enabling custom CI workflows to enforce
        accessibility standards and prevent regressions.
      </p>
    </a>
  </li>
  <li class="card">
    <a
      href="/accessibility/guides/production-monitoring"
      aria-labelledby="card-title-5"
    >
      <Icon name="user-shield" />
      <div class="card__title" id="card-title-5">Production monitoring</div>
      <p>
        Monitor accessibility issues in production by running scheduled Cypress
        tests against live environments, capturing dynamic content changes, and
        generating automated reports for a comprehensive accessibility overview.
      </p>
    </a>
  </li>
  <li class="card">
    <a
      href="/accessibility/guides/accessibility-automation"
      aria-labelledby="card-title-7"
    >
      <Icon name="book-open-reader" />
      <div class="card__title" id="card-title-7">Accessibility automation principles</div>
      <p>
        Apply these core principles to maximize the impact of Cypress
        Accessibility's automation: complement automation with human judgment
        for deeper insights, manage false positives effectively, and ensure
        robust assistive technology support.
      </p>
    </a>
  </li>
</ul>
}
## What to expect

Cypress Accessibility delivers detailed, actionable accessibility reports directly from your tests, powered by the industry-leading Axe Core® library by Deque Systems. These reports require no extra setup and are automatically generated for every unique state reached during your Cypress tests, whether in end-to-end or component testing.

- **No setup**: Cypress Accessibility uses the same capture protocol as [Test Replay](/cloud/features/test-replay) (requires Cypress v13+), so no additional code or configuration is needed.
- **No test slowdown or flakiness**: Server-side execution ensures no impact on test performance or existing code.
- **Comprehensive reporting**: During test execution, unique states—defined by distinct DOM structures—are recorded for end-to-end views and components.
- **DOM snapshots**: Each detected violation is accompanied by a [full-page, inspectable DOM snapshot](/accessibility/reports/element-detail-view), highlighting the exact location and context of the violation.
- **Report generation**: [Detailed reports](/accessibility/reports/run-level-reports) are generated, offering sortable and filterable views by page, component, or the entire test run. Rule-based summaries for an aggregated view of accessibility outcomes for the entire run are also available.
- **Run comparison**: [Compare the results](/accessibility/guides/compare-reports) from two runs and see only the new issues. Know before you merge if a code change is going to cause new accessibility problems.
- **Deep linking and sharing**: Easily share whatever you are looking at with your team at any time by copying the link, or using built-in sharing functionality and [Jira issue creation](/accessibility/reports/element-detail-view#Create-Jira-issue).
- **Selective element handling**: Elements marked as "ignored" in tests are excluded from scoring but remain visible for manual review, ensuring flexibility via [configuration](/accessibility/configuration/overview).
- **Flexible pipeline integration**: The [Results API](/accessibility/connect-and-extend/results-api) delivers accessibility outcomes to your CI pipeline, so your workflow can branch on them and enforce accessibility policies programmatically.
- **Run-specific configuration**: Use [Profiles](/accessibility/configuration/profiles) to apply different configuration settings based on run tags, enabling team-specific reporting and optimized settings for pull requests versus regression runs.

Learn more about [how it works](/accessibility/core-concepts/how-it-works).

_Note: DEQUE, DEQUELABS, AXE®, and AXE-CORE® are trademarks of Deque Systems, Inc. in the US and other countries. These terms are used throughout our documentation to refer to the accessibility testing library used by Cypress Accessibility._

---

### Accessibility Get Started Setup (`docs/accessibility/get-started/setup.mdx`)

---
title: Set up Cypress Accessibility by recording a run in Cypress
description: 'Set up Cypress Accessibility by recording a run. No code changes or configuration required.'
sidebar_label: Set up
sidebar_position: 20
---

<ProductHeading product="accessibility" />

# Get Started

You don't need to make any changes to your code or your test setup. If you record test runs to the Cypress Cloud with Test Replay, you're ready to start using Cypress Accessibility.
You'll start your free trial with personalized support from our sales team and your existing test data to instantly see full accessibility reports for all your Cypress projects.
From there, you can integrate with CI to set your own standards for handling the results.

## 1. Request a trial

Get started with a free trial of Cypress Accessibility. You'll receive a personalized demo using your existing test data to see where testing gaps exist for all of your Cypress projects.

<Btn
  label="Request trial ➜"
  className="!mb-0"
  variant="indigo-dark"
  href="https://www.cypress.io/accessibility?utm_medium=get-started-page&utm_source=docs.cypress.io&utm_content=Request%20trial"
/>

## 2. Record a run

Cypress Accessibility generates reports using [Test Replay](/cloud/features/test-replay) data and requires Cypress v13+. No additional configuration or instrumentation is required to get started.

[Record a run](/cloud/get-started/setup) to Cypress Cloud with Test Replay to start using Cypress Accessibility.

## 3. View your Accessibility results

After recording a test run, you can view your Accessibility results in Cypress Cloud via the **Accessibility** tab.

<DocsImage
  src="/img/accessibility/core-concepts/cypress-accessibility-views-dashboard.png"
  alt="The Cypress Accessibility Views List, in context in Cypress Cloud, reflecting a run of the Cypress Realworld App where violations of accessibility rules were detected on multiple pages."
/>

## 4. Customize your results

Cypress Accessibility provides flexible configuration options to customize your reports. You can configure:

- [Element filters](/accessibility/configuration/elementfilters): specify selectors for elements that should be excluded from Accessibility scans.
- [View filters](/accessibility/configuration/viewfilters): specify URL patterns for URLs that should be excluded from Accessibility scans. Excluding a URL also excludes all links to that URL.
- [Views](/accessibility/configuration/views): specify URL patterns that represent views.
- [significantAttributes](/accessibility/configuration/significantattributes): specify which attributes should be considered significant when identifying elements in Cypress Accessibility.
- [attributeFilters](/accessibility/configuration/attributefilters): exclude specific attributes or patterns that should not be used for element tracking.
- [Profiles](/accessibility/configuration/profiles): use different configuration settings for different runs based on run tags.

To add or modify the configuration for your project, navigate to the **App Quality** tab in your project settings.

<DocsImage
  src="/img/accessibility/configuration/cypress-accessibility-configuration-editor.png"
  alt="The Cypress Cloud UI showing the configuration editor"
/>

## 5. Check out our detailed guides

Cypress Accessibility supports many different accessibility automation workflows that might not be obvious at first glance, such as production monitoring of large content-managed websites. There is also an API for programmatic access to the results from each run, and a report comparison feature in Branch Review that allows for reviewing only the new violations discovered in a certain run. The guides walk you through many of the scenarios and use cases supported by Cypress Accessibility in detail so you can see how you might apply the results in your own team.

If you're looking at your first report and deciding what to do with it, start with [Fix accessibility violations](/accessibility/guides/improve-accessibility), which turns a large report into work your team can finish.

Learn more about [how to maximize the impact of Cypress Accessibility](/accessibility/guides/introduction) for your organization.

---

### Accessibility Guides Accessibility Automation (`docs/accessibility/guides/accessibility-automation.mdx`)

---
title: 'Accessibility automation principles'
description: "Apply these core principles to maximize the impact of Cypress Accessibility's automation: complement automation with human judgment for deeper insights, manage false positives effectively, and ensure robust assistive technology support."
sidebar_label: Accessibility automation principles
sidebar_position: 110
---

<ProductHeading product="accessibility" />

# Accessibility automation principles

This guide outlines foundational concepts for using Cypress Accessibility, which also apply to accessibility automation tools in general.

## Levels of Accessibility

Cypress Accessibility runs Axe Core® checks on every significant state and variation of the applications you test with Cypress. This kind of automation can catch up to [57% of issues that would appear in a manual audit](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/), but it does not replace the human judgment that is applied during an audit. Auditors test a wide variety of scenarios and technologies in a way that would be impossible to fully automate.

Accessibility can be thought of as three progressive levels:

- **Basic Usability**: This is the threshold at which a disabled user is likely to be able to make substantial progress through the application, but may still hit major barriers or usability issues. If your contact forms and issue reporting systems are accessible, you will be able to learn about these problems from actual users. Paying attention to issues reported by Cypress and Axe Core® should help you to this point.
- **WCAG Conformance**: Automated tools like Axe Core® detect many significant accessibility barriers, but human assessment is essential for validating conformance with the Web Content Accessibility Guidelines (WCAG). This is often the standard set by legislation and regulation related to web accessibility. If your goal is regulatory compliance, this is the bar. No generic automation tool can "prove" compliance with this standard, it **requires** human assessment.
- **Good User Experience**: This needs to be validated by actual disabled users who are daily users of assistive technology. It's entirely possible to have a website that passes the first two levels, and still offers a poor user experience.

Accessibility is about communicating the nature and structure of the application, and the available actions and information, in a way that allows disabled users to independently understand the interface and complete all tasks. The [POUR principles](https://www.24a11y.com/2019/pour-the-foundation-first/) (Perceivable, Operable, Understandable, Robust) form the foundation for effective accessibility beyond specific tests or checks. While Axe Core® tells us about many genuine accessibility barriers, it's important to turn that information into good decisions about accessibility and a truly equal experience.

## False positives

Cypress Accessibility and Axe Core® attempt to minimize false positives, but they can still occur. Some example of false positives include:

- **Invalid States**: False positives may arise from testing a partially hydrated DOM or other states users would never encounter. You can report invalid states by using the 'Provide Feedback' button in the Cypress UI and we'll continuously improve the product to account for these scenarios.
- **Incorrect Violations**: Axe Core® may report violations due to bugs or limitations in its rules. Since Axe Core® is an open-source product, if and when we encounter bugs, we can open issues in the project and even make pull requests if needed.

## Commonly mistaken as false positives

Some issues that are not false positives, but may seem like them, include:

- **Loading States**: Legitimate user-facing loading states can present as potential false positives. They inform users about pending data and provide fallback functionality if data is slow to load. It's a good idea in front-end development to "make impossible states impossible", and in doing so you can follow the accessibility principle of Robustness.
- **Assistive Technology Support**: Certain accessibility techniques are not fully supported by all assistive technologies like screen readers or voice control software. Axe Core® accounts for this. The software and operating systems tested against are listed in their [Accessibility Supported document](https://github.com/dequelabs/axe-core/blob/develop/doc/accessibility-supported.md). For example: it can seem like a false positive from Axe Core® if a failing technique used in your code appears to work correctly in a certain screen reader, browser, and operating system combination that you test with. But if it does not have sufficient accessibility support in commonly used technology configurations, Axe Core® will intentionally fail that technique, pointing you toward an approach with better support.

## Summary

Accessibility automation is a crucial part of an accessibility strategy in any fast-moving, modern codebase. When multiple code changes are merged on a daily or weekly basis, there is no possibility to run manual checks on every state and variation of the application prior to merge. Understanding some of the details of an "always on" set of accessibility checks in your test pipeline, where a lot of states are automatically detected, will help you develop a feel for how Cypress Accessibility behaves and what kinds of things it is best at finding, as well as what might be left over for other forms of testing.

---

### Accessibility Guides Block Pull Requests (`docs/accessibility/guides/block-pull-requests.mdx`)

---
title: Block pull requests and set policies in Cypress Accessibility
description: "Set policies and block pull requests automatically with Cypress Accessibility's Results API, enabling custom CI workflows to enforce accessibility standards and prevent regressions."
sidebar_label: Block pull requests
sidebar_position: 120
---

<ProductHeading product="accessibility" />

# Block pull requests and set policies

Cypress Accessibility reports are generated server-side in Cypress Cloud, based on test artifacts uploaded during execution. This ensures there is no performance impact on your Cypress test runs, but also means that nothing in your Cypress pipeline will fail due to accessibility issues that are detected. Failing a build is a fully opt-in step based on your handling of the results in your CI process.

## Using the Results API

The [Cypress Accessibility Results API](/accessibility/connect-and-extend/results-api) returns accessibility results after a test run, enabling workflows like blocking pull requests or triggering alerts based on specific accessibility criteria. This involves adding a dedicated accessibility verification step to your CI pipeline. With a Cypress helper function, you can automatically fetch the report for the relevant test run within the CI build context. Below is an example of how to block a pull request in GitHub Actions if accessibility violations occur:

<DocsImage
  src="/img/accessibility/guides/github-actions-a11y-block.png"
  width="75%"
  alt="On the left hand side, a list of GitHub Actions jobs is presented related to building, testing, and deploying a website. Everything has a green checkmark except the `verify-accessibility-results` job, and the 'test' job that is its parents. On the right hand side we see the terminal output for that job which warns us that the 'button-name' rule has been broken, and that it was previously passing."
  noBorder={true}
/>

## Implementing a status check

The Results API offers full flexibility to analyze results and take tailored actions. It can also integrate with status checks on pull requests. Below is an example of a passing accessibility verification step:

<DocsImage
  src="/img/accessibility/guides/status-check.png"
  width="75%"
  alt="An example list of GitHub Status Checks including a passing `verify-accessibility-results` check"
  noBorder={true}
/>

## Defining policies in the verification step

The [Results API Documentation](/accessibility/connect-and-extend/results-api) provides detailed guidance on the API's capabilities. Two rule-level policies cover most teams, and they're mirror images of each other. Both read `results.rules`, which lists only the rules that failed in the run.

| Policy                                                                       | Blocks when                                         | Best for                                                                       |
| ---------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------ |
| [Allowlist known failures](#Policy-block-any-rule-that-isnt-already-failing) | Any rule fails that isn't on your known-issues list | Reports that are close to clean, where anything unexpected should stop a merge |
| [Protect what you've fixed](#Policy-block-regressions-in-rules-youve-fixed)  | A rule you already remediated fails again           | A large backlog you're working through, where most rules still fail            |

For a policy that tracks violations per view rather than per rule, see [comparing against a baseline](#comparing-against-a-baseline).

### Policy: block any rule that isn't already failing {#Policy-block-any-rule-that-isnt-already-failing}

This enforces "no new failing accessibility rules". You keep a list of the rules you already know about, and anything outside it fails the build:

```js
const { getAccessibilityResults } = require('@cypress/extract-cloud-results')

// List of known failing rules
const rulesWithExistingViolations = [
  'button-name',
  // Add more rules as needed
]

// Fetch accessibility results
getAccessibilityResults().then((results) => {
  // Identify new rule violations
  const newRuleViolations = results.rules.filter((rule) => {
    return !rulesWithExistingViolations.includes(rule.name)
  })

  if (newRuleViolations.length > 0) {
    // Trigger appropriate action if new violations are detected
    throw new Error(
      `${newRuleViolations.length} new rule violations detected. These must be resolved.`
    )
  }
})
```

The list shrinks as you fix things, and every entry you remove raises the standard the build enforces.

### Policy: block regressions in rules you've fixed {#Policy-block-regressions-in-rules-youve-fixed}

This is the inverse, and it suits a project still working through a large backlog. Rather than listing what's broken, you list what you've finished, and only a reappearance of those rules fails the build:

```javascript title="scripts/verifyAccessibilityResults.js"
const { getAccessibilityResults } = require('@cypress/extract-cloud-results')

// Rules this team has remediated. Add a rule here the day it reaches zero
// violations, so any reappearance is treated as a regression.
const remediatedRules = ['button-name', 'image-alt', 'label']

getAccessibilityResults().then((results) => {
  const regressions = results.rules.filter((rule) =>
    remediatedRules.includes(rule.name)
  )

  if (regressions.length === 0) {
    console.log(`No regressions in ${remediatedRules.length} remediated rules.`)
    return
  }

  console.error('Previously remediated accessibility rules are failing again:')
  regressions.forEach((rule) => {
    console.error(
      `  - ${rule.name} (${rule.severity}): ${rule.accessibilityReportUrl}`
    )
  })

  throw new Error(
    `${regressions.length} remediated rule(s) regressed and must be fixed before merging.`
  )
})
```

Here the list grows as you work. It never blocks a merge for a rule you haven't gotten to yet, which keeps the gate credible while the backlog is still large. See [Fix accessibility violations](/accessibility/guides/improve-accessibility) for how to work through that backlog one rule at a time.

By examining the results and customizing your response, you gain maximum control over how to handle accessibility violations. Use CI environment context, such as tags, to fine-tune responses to specific accessibility outcomes.

## Using Profiles for PR-specific configuration

You can use [Profiles](/accessibility/configuration/profiles) to apply different configuration settings for pull request runs versus regression runs. This approach supports several patterns:

- Use a narrow, focused configuration for PR runs that blocks merges based on critical accessibility issues
- Maintain a broader configuration for regression runs that tracks all issues for long-term monitoring
- Apply team-specific configurations when multiple teams share the same Cypress Cloud project

For example, a profile named `aq-config-pr` can narrow pull request reports to a single flow that's under active remediation, while your base configuration keeps every page for regression tracking. The first rule includes the flow and the catch-all `*` rule excludes everything else, because [`viewFilters`](/accessibility/configuration/viewfilters) apply in order and the first match wins:

```json title="App Quality Config"
{
  "profiles": [
    {
      "name": "aq-config-pr",
      "comment": "Pull request runs report only on the checkout flow while we remediate it",
      "config": {
        "viewFilters": [
          {
            "pattern": "/checkout/*",
            "include": true
          },
          {
            "pattern": "*",
            "include": false
          }
        ]
      }
    }
  ]
}
```

Record pull request runs with the matching tag to select the profile:

```shell
cypress run --record --tag "aq-config-pr"
```

This approach ensures that PR checks are fast and focused, while still maintaining comprehensive reporting for your full test suite. A profile can also set [`axeConfig`](/accessibility/configuration/axe-core-configuration) under `accessibility` if you want pull request runs to use a different Axe-Core® ruleset than regression runs. Which findings block a merge still stays a decision you make in the verification step above.

## Comparing against a baseline {#comparing-against-a-baseline}

Comparing current results against a stored baseline surfaces only the new violations that have been introduced, while ignoring existing known issues. This approach is more sophisticated than simply maintaining a list of known failing rules, as it tracks violations at the view level and can detect both regressions (new violations) and improvements (resolved violations).

This is particularly useful in CI/CD pipelines where you want to fail builds only when new accessibility violations are introduced, so existing issues can be addressed incrementally without blocking deployments.

### Baseline structure

You can use any format you like as baseline for comparing reports. In the example code below we generate a baseline in a simplified format, which captures the state of accessibility violations from a specific run. The Results API handler code logs this for every run so that it can be copied as a new reference point.

It includes:

- **runNumber**: The run number used as the baseline reference
- **severityLevels**: The severity levels to track (e.g., `['critical', 'serious', 'moderate', 'minor']`)
- **views**: An object mapping view display names to arrays of failed rule names for that view

```javascript
{
  "runNumber": "111",
  "severityLevels": [
    "critical",
    "serious",
    "moderate",
    "minor"
  ],
  "views": {
    "/": [
      "aria-dialog-name",
      "heading-order",
      "scrollable-region-focusable"
    ],
    "/authorizations": [
      "heading-order",
      "listitem",
      "region"
    ]
  }
}
```

### Complete example

The following example demonstrates how to compare current results against a baseline, detect new violations, identify resolved violations, and generate a new baseline when changes are detected.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Key concepts in the example script

#### New failing rules

A **new failing rule** is a rule that has violations on a View in the current run that were not present in the baseline. These represent regressions that need to be addressed. The script will fail the build if any new failing rules are detected.

#### Resolved rules

A **resolved rule** is a rule that was present in the baseline but no longer has violations in the current run. These represent improvements in accessibility. The script reports these but does not fail the build, tracking your progress and printing out an updated baseline to copy over when things are fixed.

#### Severity filtering

The baseline comparison only tracks rules at the severity levels you specify in `TARGET_SEVERITY_LEVELS`. This keeps the comparison focused on the severity levels that matter most to your team. Rules at other severity levels are ignored during comparison.

#### View-level comparison

Violations are tracked per view (URL pattern or component), pinpointing exactly which pages or components have regressed or improved. This granular tracking makes it easier to identify the source of changes and assign fixes to the appropriate teams.

### Best practices

#### When to update the baseline

Update your baseline when:

- You've fixed accessibility violations and want to prevent regressions
- You've accepted certain violations as known issues that won't block deployments

We recommend storing the baseline in version control so it's versioned alongside your code and accessible in CI environments, but some users prefer updating the baseline automatically based on the newest results from a full passing test run on the main branch of the project. This means any PRs will be compared against the reference run that makes sense at the time the results are analyzed, and avoids needing to manually own the standard.

#### Handling partial reports

If a run is cancelled or incomplete, the Results API may return a partial report. Consider checking `summary.isPartialReport` before comparing against the baseline, as partial reports may not include all views and could produce false positives.

#### Managing baseline across branches

You may want different baselines for different branches (e.g., `main` vs feature branches). Consider storing baselines in branch-specific files or using environment variables to specify which baseline to use.

#### Storing the baseline

Common approaches for storing baselines:

- **Version control**: Commit the baseline JSON file to your repository
- **CI artifacts**: Store baselines as build artifacts that can be retrieved in subsequent runs

---

### Accessibility Guides Compare Reports (`docs/accessibility/guides/compare-reports.mdx`)

---
title: Compare accessibility reports in Cypress Accessibility
description: 'Compare accessibility reports between two Cypress runs to spot new violations, regressions, and fixes before they merge.'
sidebar_label: Compare reports
sidebar_position: 80
---

<ProductHeading product="accessibility" />

# Compare reports

Accessibility reports from different runs can be compared in the [Branch Review](/cloud/features/branch-review#Get-started) area of Cypress Cloud. The comparison instantly surfaces any new issues that have been introduced, and drills in to full-page HTML and CSS snapshots showing only those new issues.

See the video below for an example of using Branch Review in a Pull Request:

<DocsVideo
  src="https://www.youtube.com/embed/k3vq57O4P4M"
  title="Accessibility branch review demo"
/>

Comparing two accessibility reports manually is usually a challenge:

- each report may test thousands of application snapshots for a single Cypress run
- 80+ accessibility rules are tested for each snapshot
- many different pages or components are tested and may have changes
- elements might be identified differently in each run

Branch Review for Cypress Accessibility is set up to help you browse this nested set of changes and find what's important. You can review any accessibility violation increases found for specific rules, and drill into the Views where those changes happened.

## Use cases

Comparing the results from different runs is useful in multiple scenarios.

**Key use cases:**

- **Pre-merge checks**: Know if any net-new issues are introduced by UI code changes.
- **Monitoring changes**: Compare nightly monitoring runs and track down the introduction of new problems caused by underlying changes in the application.
- **Detecting content issues**: Sometimes content editors can introduce accessibility issues unrelated to code changes. Seeing the example issues presented visually, in context, helps you quickly triage whether you are dealing with a recent code change issue, or a content authorship problem.
- **Reviewing AI-generated code changes**: The increased use of AI to generate and/or review front-end code creates some increased risks of accessibility regressions making it to production. The increase or decrease of accessibility issues when reviewing a pull request helps you understand the impact of the change.
- **Tracing the introduction of issues**: With dropdowns for each run, you can rapidly compare different A and B runs to find the exact commit that introduced a problem.
- **Demonstrating the resolution of issues**: Confirm the effect of your improvements, and share the overview with your team to more quickly review code changes.

## Content of the report

<DocsImage
  src="/img/accessibility/core-concepts/branch-review-example-diff.png"
  alt="Cypress Accessibility Branch Review showing two main sections - New Failed Elements and Resolved Elements"
/>

The key to understanding the run comparison report is that the Changed run is the focal point for all data that will be displayed, and the Base run is used as a reference point for comparison. So everywhere that you see an element, or drill in for more details, you will only see data from the Changed run.

The Branch Review report is divided into two sections:

- **New failed elements**: Counts of elements that have failures in the Changed run, where matching failures were not found on the Base run. These are listed by View, for each accessibility rule where new failures were detected.
- **Resolved elements**: Counts of elements that had failures detected in the Base run which are no longer detected in the Changed run. These are also listed as improvements in each View, under the accessibility rules that had improvements.

If the Changed run is associated with a Pull Request and runs the same overall test suite as the Base run, the changes in the report are likely due to code changes in the pull request.

## How to compare runs

The first step is to get to the [Branch Review](/cloud/features/branch-review) area of Cypress Cloud, which will let you compare one branch against another - or different runs on the same branch, if needed.
You can access this area by clicking the branch name associated with a run, or in several other ways. [Learn more about how to compare runs](/cloud/features/branch-review).

## Details of each section

### New failed elements

A **new failed element** is any failed element which either did not exist in the Base run at all, or existed in the Base run but was passing its accessibility checks.

<DocsImage
  src="/img/accessibility/core-concepts/branch-review-a11y-new-failed.png"
  alt="Cypress Accessibility Branch Review showing two main sections - New Failed Elements and Resolved Elements"
/>

Any rules with new failed elements will appear here. There are two ways to explore this list. You can open each rule and choose from he list of Views where a new failed element was detected, or if you click the "View All" link, you will see a full report containing all of the net-new failures in the run, across all rules and views.

Either path will take you to the detailed report, either for a single View or for all View combined. This report works exactly like the main Cypress Accessibility report, with full-page snapshot examples for every violation. The only difference is that all issues that are the same on both runs have been removed, leaving just what's new - either for the specific View you've chosen, or across all views.

<DocsImage
  src="/img/accessibility/core-concepts/branch-review-a11y-detail-view.png"
  alt="Cypress Accessibility Branch Review showing the detailed diff for a demo contact form. A 'name' field in the contact form is highlighted in red because it is missing a label."
/>

#### Single-View diff vs whole-run diff

Each rule has an "All Views" comparison as the first item, and then lists individual Views below that. Depending on the level of detail you are looking for, you can drill into a specific page or component and see the changes in accessibility there, or just look at the combined report.

The combined "All Views" report for a single rule is especially useful if violations tend to move around between pages over time. For example, if there is a popup with an accessibility problem that appears on a random page in every run, it may appear "new" for a View in the Changed run, and "resolved" for the View where it was in the Base run, but in reality your accessibility score is the same and the problem is the same. "All Views" sidesteps noise of this kind.

### Resolved elements

A **resolved element** is an element that had a failed accessibility rule in the Base Run, where a matching failure is not found in the Changed run.

<DocsImage
  src="/img/accessibility/core-concepts/branch-review-a11y-resolved-elements.png"
  alt="A list of accessibility rules with resolved elements in the new run"
/>

Resolved elements are calculated for every rule and View, but are not displayed individually. This is because, as far as the Changed report is concerned, the failures do not exists, so there is not a guarantee the element is still present in the "new" report.

If you have a use case for seeing the specific elements that are no longer detected to have failures, reach out to your Cypress representative for further discussion. For the time being the focus of Branch Review is on **new problems** - we avoid mixing old and new data in the same report to minimize the chances of confusion.

### What if there are no changes?

If there are no changes, the Accessibility Branch Review report still displays all the sections, and explains that there are no elements that appear to be new or resolved in Changed run:

<DocsImage
  src="/img/accessibility/core-concepts/branch-review-a11y-empty-state.png"
  alt="The new and resolved elements sections each showing a message to explain that there are no findings"
/>

This means the reports are identical, and that the Changed run has not had any impact on accessibility.

## Ensuring a good comparison

The easiest subjects to compare are **passing runs** that ran **similar tests** on the **similar content**. This means that each run visited roughly the same pages and completed the same kinds of workflows. In this situation, any diff in the results is likely the result of changes present in the newer run. This is usually what happens out-of-the box when comparing a pull-request branch with your main branch, for example - assuming the same tests run on both branches.

That said, it still possible and valid to compare runs from different points in time with different sets of test results, as long as you bear in mind all the potential sources of difference between the two runs, which you can evaluate for yourself as you explore the results.

To see unified changes for your entire test suite, you need to group all the tests together under a single Cypress run, for each report. Learn more about this in the [Branch Review Best Practices documentation](/cloud/features/branch-review#Best-Practices).

### Stabilizing the comparison

On most projects, comparing accessibility reports will work nicely out of the box. But in some cases, configuration is useful to handle dynamic values that might be present in page URLs or element locator. You may also want to take steps to improve the consistency of the elements under test.

### Stable Views

URLs with dynamic slugs in them can appear as "new" pages in some situations. This behavior can be adjusted with [View configuration](/accessibility/configuration/views) to make sure page names will match across runs by wildcarding parts of the URL as needed.

Cypress performs this process automatically for certain known patterns. For example, the default behavior is to track a URL like `https://example.com/products/123` as `https://example.com/products/*` so that the underlying product pages are grouped together as one View, and then between runs that View is recognized in a stable way.

If a View appears to be "new", it is identified with a green plus icon, and a tooltip explaining that this View was seen on the Changed run but not on the base run, as seen here in the New Failed Elements section:

<DocsImage
  src="/img/accessibility/core-concepts/added-views.png"
  alt="Cypress Accessibility Branch Review showing several added views in a report, with a plus sign beside each one and a tooltip explaining that the view was seen in one report, but not the other."
/>

Likewise, if a rule appears to have resolved elements on Views that are simply no longer captured on the Changed run, this is identified in the Resolved Elements section:

<DocsImage
  src="/img/accessibility/core-concepts/removed-views.png"
  alt="Cypress Accessibility Branch Review showing several added views in a report, with a plus sign beside each one and a tooltip explaining that the view was seen in one report, but not the other."
/>

These changes in Views may be because a new page was actually added to the application, or a new page was reached by testing that wasn't reached before. It will be clear to you if configuration is needed to improve View stability across runs, as you will see unexpected added and removed URLs.

### Stable Elements

Cypress stores a string that represents each failed element in a report, determined using a standardized [element identification process](/accessibility/core-concepts/element-identification). This operates in a different way to the standard Axe-Core® element identification algorithm, to support the comparison of runs from different builds of the application, and make use of the testing-related attributes you may already have created in the DOM.

Where possible, we prioritize known stable locators like `data-cy` or `data-testid`. In some cases the identification strings will contain dynamic values that change on every build of your application, introducing noise in a diff. The element identification behavior is flexible and can be configured to meet your needs and fully avoid dynamic values as identifiers.

For example, if an element's default locator includes a class like `.css-21kj23` in Build A, and a slightly different class like `.css-2309kj` in Build B, it will appear as though there was a "resolved element" and "new violation".

This behavior is highly customizable so that you can avoid depending on values that don't matter to you, but also you can choose specific attributes that _do_ matter for element recognition and get sensible deduplication and matching behavior based on your own goals.

Learn more about the [`attributeFilters`](/accessibility/configuration/attributefilters) and [`significantAttributes`](/accessibility/configuration/significantattributes) configuration available, or reach out to us for any assistance on dialing in the behavior.

### Stable underlying reporting area

It's likely that your tests have never been used for always-on accessibility tests before, and while most codebases produce stable results, some projects have inherent differences between runs due to the performance of specific processes during testing.

For example, sometimes the test may spend enough time on a page to see a confirmation message after a form is submitted, unless the server response is slow, then the test may finish without rendering the state.

There are different solutions depending on the nature of the issue. If you want to ensure the state is always picked up in Cypress Accessibility, you can add some assertion about that state to your tests. On the other hand, if you do not want to account for this state at all, it can be ignored with [`elementFilters`](/accessibility/configuration/elementfilters) configuration. Either approach will lead to a more stable branch comparison.

## Optimizing for Pull Request reviews

If you plan to use branch comparison for investigating Pull Requests that have been blocked through the Results API for not meeting your standard, it's useful to implement this in a gradual way, prioritizing the developer experience at first.

Choose a scope of rules, page, and elements that reduces ambiguity. A good starting point is something like "We will fail a build if it introduces new critical issues on the login or checkout page."

If your application is unstable between runs in terms of content, pages, or different states reached, fine tune your configuration to ignore the unstable parts of the DOM that have issues already. These can be documented and dealt with on their own.

When everything is dialled in correctly, the Branch Review diff will be 100% clean, unless something has actually changed in an area you didn't already know about. This gives you the highest confidence that if an issue is blocking a merge, it is genuinely a new problem introduced by the incoming Pull Request.

If the team is not already familiar with accessibility, it's useful to consider which rules to start with. See [Fix accessibility violations](/accessibility/guides/improve-accessibility) for how to choose a first rule and scope the report around it.

If multiple teams are working on the same project and need accessibility results to be isolated from each other, consider splitting runs into dedicated Cypress projects or using [configuration profiles](/accessibility/configuration/profiles) so that each team can have a customized report for the areas they are responsible for.

---

--- METRICS ---
- Files Extracted: 94
- Estimated Token Budget: ~177454 tokens
- Canonical Reference: https://codewiki.google/github.com/cypress-io/cypress-documentation
