Technical Documentation: cypress-io/cypress-documentation
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (README.md)
Cypress Documentation [](https://on.cypress.io/discord) [](https://github.com/cypress-io/cypress-documentation/labels/good-first-issue)
CI status
Our docs are built using Docusaurus.
Installation
$ npm iLocal Development
$ npm run startThis 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 buildThis 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 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 guide for details.
License
This project is licensed under the terms of the MIT license.
Partials Intercept Alias Index (`docs/partials/_intercept-alias-index.mdx`)
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.
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(). Use cy.get('@alias.all')
instead of cy.wait('@alias.all').
:::
Accessibility Configuration Overview (`docs/accessibility/configuration/overview.mdx`)
title: Configure Cypress Accessibility sidebar_label: Overview sidebar_position: 10
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 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 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
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.
Regenerating reports in this way lets you iterate on configuration and see the effects immediately, without running your Cypress tests again.
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 |
| Remove entire pages or URLs from reports | viewFilters |
| Remove elements from reports and the score entirely | elementFilters |
| Enable, disable, or scope Axe Core® rules | axeConfig |
| Keep an element but ignore specific rules for it | data-a11y-ignore attribute |
| Identify violation targets by your own attributes | significantAttributes |
| Stop dynamic or generated attributes from identifying elements | attributeFilters |
| Add component context to violation-target selectors | components |
| Apply different configuration to runs based on run tags | 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, 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.
{
"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 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:
viewFilters: first match wins. URLs are compared against your rules top to bottom, and the first rule whosepatternmatches 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 anyinclude: falserule matches it, regardless of where the rule sits in the list, and aninclude: truerule 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.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.
Configuration scope
Some properties are shared across App Quality products, and some belong to Cypress Accessibility alone.
- Shared properties:
viewFilters,elementFilters,significantAttributes, andattributeFiltersapply 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 anaccessibilitykey. 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:
viewsapplies to both Cypress Accessibility and UI Coverage and can only be set at the root. - Accessibility only:
componentsandaxeConfigbelong to Cypress Accessibility alone and are always set under theaccessibilitykey.componentsshapes violation-target selectors;axeConfigenables, disables, and scopes Axe Core® rules. UI Coverage has its own product-only options (elements,elementGroups, and interaction commands) set under auiCoveragekey. See the 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 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 the run to reprocess it with the current configuration.
From the Results API
The Accessibility Results API exposes the applied configuration on the config property of its result, so you can read it in a CI workflow:
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
- Exclude views
- Exclude elements
- Ignore rules per element
- Configure Axe Core® rules -
axeConfig - Prioritize identifying attributes
- Ignore attributes for identification
- Define components
- Override config by run tag
- Cypress Accessibility FAQ
Accessibility Connect And Extend Overview (`docs/accessibility/connect-and-extend/overview.mdx`)
title: 'Connect & extend Cypress Accessibility' sidebar_label: Overview sidebar_position: 10
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 | A one-off, manual export of a single run's violations for offline analysis, sharing, or AI agents. | .csv or .json file |
| Webhooks | Push Cypress Accessibility results to your own endpoint when the report finishes processing. | run.accessibility.completed |
| 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 | Live, interactive querying by AI agents while you work in your editor. | MCP tools |
| 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 button. The file works offline with any tool or AI agent.
- To enforce a standard in CI, use the Results API to assert on a run's results and block pull requests that don't meet it.
- To work with an AI agent, use a downloaded report for the full dataset or Cypress Cloud MCP to query results live. See Work with AI agents.
- To push results when a report finishes, use Webhooks. The
run.accessibility.completedevent 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.
- To track trends across runs and projects, use the Data Extract API and Enterprise Reporting.
Api Node Events Overview (`docs/api/node-events/overview.mdx`)
title: 'Overview of Node Events in Cypress' sidebar_label: Overview sidebar_position: 10
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 for others to consume.
setupNodeEventsenables 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
function receives 2
arguments: on and 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
// 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
on('<event>', (arg1, arg2) => {
// plugin stuff here
}):::
List of events
Each event documents its own argument signature.
| Event | Description |
|---|---|
after:run |
Occurs after the run is finished. |
after:screenshot |
Occurs after a screenshot is taken. |
after:spec |
Occurs after a spec is finished running. |
before:browser:launch |
Occurs immediately before launching a browser. |
before:run |
Occurs before the run starts. |
before:spec |
Occurs when a spec is about to be run. |
file:preprocessor |
Occurs when a spec or spec-related file needs to be transpiled for the browser. |
task |
Occurs in conjunction with the cy.task command. |
config
config is the resolved
Cypress 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. See the
--config-file and
configFile 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.
Use Cases
Configuration
Hooking into node events programmatically alters the resolved configuration and
environment variables that come from the
Cypress configuration file,cypress.env.json,
the 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
fslib - Change the list of browsers used for testing
- Write your configuration in
yml
Check out our Configuration API docs 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 which
describe how to use this event.
Run Lifecycle
The events before:run andafter:run occur before and after a run,
respectively.
You can use before:run 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 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 andafter:spec run before and after a single spec
is run, respectively.
You can use before:spec 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 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 and
After Spec API doc 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
Loading extensions in Chrome 137 and above
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 or
Chromium, which still support extension loading.
:::
Check out our Browser Launch API docs 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
which describe how to use this event.
cy.task
The event task is used in conjunction with thecy.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
function is invoked
when Cypress opens a project.
Cypress does this by spawning an independent child_process which thenrequires the Cypress configuration file.
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 thesetupNodeEvents function
it will execute withprocess.cwd() set to your project's path. Additionally - you will be able torequire any node module you have installed, including local files inside
your project.
For example, if your package.json looked like this:
{
"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
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 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
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 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.
Real World Example
The uses
tasks to re-seed its database, and to filter/find test
data for various testing scenarios.
:::cypress-config-plugin-example
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
_ Source:
Real World App > cypress.config.ts_
:::
Check out the
Real World App test suites
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' sidebar_label: AI in Cypress sidebar_position: 10 slug: /app/ai/overview
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 andcy.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 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.promptturns
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.
- Cypress skills for AI agents teach your coding
agent to write, review, and explain tests the way an experienced Cypress
engineer would. Install them once per project. cypress tapattaches 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.
Thecypress-tapskill packages this
workflow so your agent drives it correctly.- Cloud MCP connects your agent to Cypress
Cloud so it can read real run results, failures, and
Test Replay data while you work, rather than
guessing at why something failed. - 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. Thecypress-cloud-cliskill 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 explains failures and
summarizes test intent across recorded runs in Cypress Cloud. - Work with AI agents in Cypress Accessibility
and Work with AI agents in UI Coverage
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,
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 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?
Organization admins and owners can turn AI capabilities on or off for everyone
in the organization. See
Disabling AI features.
See also
cy.prompt()- the command reference- Cypress Studio
- Cypress skills for AI agents
cypress tap- Cloud MCP
- Cloud CLI
- Cypress AI - 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 sidebar_label: Overview sidebar_position: 10
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 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.
Setting 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 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.
Configuration options
:::info
For a quick overview of the practical
application of the most common UI Coverage configuration properties, you can
read this blog
post.
:::
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 |
| Remove entire views from reports | viewFilters |
| Remove elements from reports and scores entirely | elementFilters |
| Rename or stabilize the identity of a single element | elements |
| Combine repeated or related elements so they count as one | elementGroups |
| Define groups in your application's markup instead of configuration | data-cy-ui-group attribute |
| Prioritize your own attributes for identifying and naming elements | significantAttributes |
| Stop dynamic or generated attributes from identifying elements | attributeFilters |
| Count your custom commands as interactions | additionalInteractionCommands |
| Limit which interaction commands count for specific elements | allowedInteractionCommands |
| Apply different configuration to runs based on run tags | 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 and 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.
{
"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,viewFilters,elementFilters,elementGroups,attributeFilters, andprofiles: 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 aninclude: trueexception above theinclude: falserule it should override. Two properties differ: forelementsthe last matching rule wins, and forallowedInteractionCommands, 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.
Configuration scope
Some properties are shared across App Quality products, and some belong to UI Coverage alone.
- Shared properties:
elementFilters,viewFilters,attributeFilters, andsignificantAttributesapply 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 auiCoverageoraccessibilitykey. 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 thannull, which falls back to the root value. - Shared, but not nestable:
viewsapplies to both UI Coverage and Cypress Accessibility and can only be set at the root. - UI Coverage only:
elementGroups,elements,additionalInteractionCommands, andallowedInteractionCommandsare specific to UI Coverage and are always set under theuiCoveragekey.
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 the run to reprocess it with the current configuration.
From the Results API
The UI Coverage Results API exposes the applied configuration on the config property of its result, so you can read it in a CI workflow:
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
- View Filters
- Element Filters
- Elements
- Element Groups
- Significant Attributes
- Attribute Filters
- Additional Interaction Commands
- Allowed Interaction Commands
- Profiles
App Run Tests Continuous Integration Overview (`docs/app/run-tests/continuous-integration/overview.mdx`)
title: 'Continuous Integration with Cypress: Run Tests in CI' sidebar_label: CI overview sidebar_position: 10 slug: /app/continuous-integration/overview
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.
Setting up CI
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:
- Install Cypress
- Run Cypress
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.
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:
npm start & npx cypress run # don't do thisThere 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, itsstart and wait-on options boot and wait for your server without any extra
packages. See our
GitHub Actions guide.
:::
`start-server-and-test` module
The 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.
In your package.json scripts, pass the command that boots your server, the
URL your server is hosted on, and your Cypress test command.
{
"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 URLhttp://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
or another server that does not respond to HEAD requests, use an explicitGET method to ping the server like this:
{
"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:
{
"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 module blocks until a URL
responds. Background the server, wait for it, then run Cypress:
npm start & npx wait-on http://localhost:8080npx 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 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).
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, 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, 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 so it can debug the
failing run for you. - View screenshots taken when tests fail and when using
cy.screenshot(). - Detect and manage flaky tests that
pass and fail across recorded runs. - Analyze trends in your test suite with
Analytics, like run duration,
most common errors, and slowest tests. - Generate UI Coverage and
Cypress Accessibility reports
from your recorded runs with no additional test code or configuration
(premium solutions). - See which machines ran each test when
parallelized.
To record tests:
- Set up your project to record and copy
your record key. - Pass the
--recordflag tocypress run
within CI, along with the record key, either inline with the--keyflag
or via theCYPRESS_RECORD_KEYenvironment variable.
Read the full guide on Cypress Cloud.
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 flag to
have your tests run in parallel. Parallelization requires recording to
Cypress Cloud, which load-balances specs
across your machines.
Read the full guide on parallelization.
Cypress Docker Images
CI providers, such as GitHub Actions and
CircleCI, allow workflows to run using
Docker container images.
Cypress supports the use of Docker
through the provisioning of official 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:
Cypress Docker variants
cypress/base is the entry-level Cypress Docker image. To test in an installed browser such as Chrome or Firefox, use the
cypress/browsersimage described below.
It contains a complete Linux (Debian) operating system, together with the
prerequisite operating system packages for Cypress,
Node.js, npm, and Yarn v1 Classic.
An image<tag>gives you the choice of Node.js version.cypress/browsers builds on the
cypress/base image.
ForLinux/amd64images it adds Chrome, Firefox, and Edge browsers.
ForLinux/arm64images it adds Firefox browsers from version136and above, and
Chrome browsers from version151and above.
Edge browsers are currently not available forLinux/arm64.
A corresponding image<tag>allows selection of the combined Node.js and browser versions.
The version tag for the unavailable Edge browser on theLinux/arm64platform is an empty place-holder only,
required for multi-platform support compatibility.cypress/included builds on the
cypress/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
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
- cypress-example-kitchensink
- Real World App - CircleCI
- Real World App - GitHub Actions
- cypress-docker-images - GitHub Actions
CI Examples
We maintain in-depth setup guides for the most popular CI providers, and
working example configurations for many others.
AWS Amplify Console
AWS CodeBuild
Read our extensive guide on how to set up Cypress in AWS CodeBuild.
Azure Pipelines
Bitbucket Pipelines
Read our extensive guide on how to set up Cypress in Bitbucket Pipelines.
Buildkite
CircleCI
Read our extensive guide on how to set up Cypress in CircleCI.
GitHub Actions
Read our extensive guide on how to set up Cypress in GitHub Actions.
GitLab
Read our extensive guide on how to set up Cypress in GitLab.
Jenkins
Netlify
Use our official
netlify-plugin-cypress
to execute end-to-end tests before and after deployment to the Netlify
platform.
Semaphore
TravisCI
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
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
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
command.
npx cypress info
...
Cypress Version: 15.18.1 (stable)
System Platform: linux (Debian - 12)
System Memory: 73.6 GB free 48.6 GBYou can see the CPU parameters on the CI machines by executing the command
below.
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
project runs tests on a CircleCI machine using the
Docker executor withresource_class: large
providing 4 vCPUs and 8 GB of RAM.cypress inforeportsSystem Memory: 73.6 GB free 48.6 GB. - The Real World App project also
executes its tests on
GitHub Actions using the
Cypress GitHub Action with the
standard Ubuntu GitHub-hosted runner for Public repositories
providing 4 vCPUs and 16 GB of RAM.cypress inforeportsSystem Memory: 16.8 GB free 15.5 GBwith CPUs reported asAMD 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 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
~/.cachefolder after runningnpm install,yarn,npm cior equivalents as demonstrated in
the configs below.Do not cache
node_modulesacross builds. Instead, cache the package
manager's own cache directory (~/.npmfor npm or~/.cache/yarnfor yarn).
These tools maintain package-level caches that track installed versions,
validate integrity, and only re-download packages that have changed. Cachingnode_modulesdirectly bypasses these built-in mechanisms and can cause
issues such as Cypress not downloading the Cypress binary onnpm install.If you are using
npm installin your build process, consider
switching tonpm ci
and caching the~/.npmdirectory for a faster and more reliable build.If you are using
yarn, caching~/.cachewill include both theyarnand
Cypress caches. Consider usingyarn install --frozen-lockfileas annpm ciequivalent.If you need to override the binary location for some reason, use the
CYPRESS_CACHE_FOLDER
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
repository.
Environment variables
You can set various environment variables to modify how Cypress runs.
Configuration Values
You can set any configuration value 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 deploymentCYPRESS_REPORTER- switch to a CI-friendly reporter likejunitCYPRESS_DEFAULT_COMMAND_TIMEOUT- allow more time on slower CI machinesCYPRESS_VIEWPORT_WIDTHandCYPRESS_VIEWPORT_HEIGHT- vary the screen
size per CI job
The install-time variableCYPRESS_INSTALL_BINARY
is also commonly set in CI, to skip or redirect the binary download.
Refer to the
Environment Variables recipe
for more examples.
Record Key
If you are recording your runs on a public project, you'll want
to protect your Record Key.
Learn why.
Instead of hard coding it into your run command like this:
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.
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.
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 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.
DEBUG=cypress:server:recordSource 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:
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 withCYPRESS_ using your CI provider's secret or masked variable settings:
export CYPRESS_SERVICE_API_TOKEN=secret-token-123Cypress strips the prefix, and your tests read the value withcy.env(), which retrieves only the values you request
without serializing them into browser state:
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:
and read them synchronously withCypress.expose():
const apiVersion = Cypress.expose('apiVersion') // => 'v2'Refer to the dedicated
Environment Variables & Secrets guide 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 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.
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()
})()node scripts/run-cypress-tests.jsCommon 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
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:
- Clean your CI's cache using your CI's settings to force a clean
npm install
on the next build. - 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,
the tools below should be available.
Xvfb :99 &Second, set the X11 address in a system environment variable
export DISPLAY=:99Start Cypress as usual
After all tests across all Cypress instances finish, kill the Xvfb background
process using pkill
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:
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.
NO_COLOR=1 cypress runSee also
- Cypress Real World App
runs parallelized CI jobs across multiple operating systems, browsers, and
viewport sizes - cypress-example-kitchensink
is set up to run on multiple CI providers - Command Line - all
cypress runflags and
options - Test Replay
- Cross Browser Testing Guide
Cloud Features Analytics Overview (`docs/cloud/features/analytics/overview.mdx`)
title: Types of analytics in Cypress Cloud sidebar_label: Overview sidebar_position: 10
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: Analytics is provided
for each project in your organization so that you can understand trends and details for an
individual project. - 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: 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 sidebar_label: Overview sidebar_position: 10
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: Reduce
test duration by running multiple test spec files simultaneously across
available CI machines. - Load Balancing: Optimize
CI resources and minimize test duration by intelligently prioritizing running
of test spec files during parallelization. - Spec Prioritization:
Quickly verify that your latest changes fixed a build by prioritizing the
specs that failed in the previous Cypress run. - Auto 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
(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
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' sidebar_label: Angular overview sidebar_position: 10 slug: /app/component-testing/angular/overview
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 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:
Open Cypress:
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 guide.
For usage and examples, visit the
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.
The examples below are for quick reference.
Angular CLI Configuration
:::cypress-config-example
{
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 anoptions property:
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
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 ownprojectConfig, 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 understylePreprocessorOptions.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
{
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
and load that compiled file through buildOptions.styles.
Install the CLI:
npm install -D @tailwindcss/cliyarn add -D @tailwindcss/clipnpm add -D @tailwindcss/clibun add -d @tailwindcss/cliCompile your stylesheet before opening or running Cypress, then pointbuildOptions.styles at the compiled output:
{
"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
{
component: {
devServer: {
framework: 'angular',
bundler: 'webpack',
options: {
projectConfig: {
buildOptions: {
styles: ['cypress/support/compiled-styles.css'],
},
},
},
},
specPattern: '**/*.cy.ts',
},
}:::
See also
App Write Tests Component Testing React Overview (`docs/app/write-tests/component-testing/react/overview.mdx`)
title: 'React component testing' sidebar_label: React overview sidebar_position: 10 slug: /app/component-testing/react/overview
React Component Testing
Cypress Component Testing currently supports React 18 and 19 with the following
frameworks:
Tutorial
Visit the
Getting Started Guide 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:
Open Cypress:
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 guide.
For usage and examples, visit the
React Examples guide.
:::
Framework Configuration
Cypress Component Testing works out of the box with Vite, Next.js, and a custom
Webpack 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.
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
import customViteConfig from './customConfig'{
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 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, orwebpack-dev-server separately. All three ship inside the cypress package, soimport { mount } from 'cypress/react' and bundler: 'webpack' work as soon as
Cypress is installed.
:::
Webpack Configuration
:::cypress-config-example
import webpackConfig from './webpack.config'{
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
Next.js
Cypress Component Testing works with Next.js 15 and 16.
Next.js Configuration
:::cypress-config-example
{
component: {
devServer: {
framework: 'next',
bundler: 'webpack',
},
},
}:::
Next.js Caveats
There are some specific caveats to consider when testing Next.js
Pages in component testing.
A page component could have additional logic in its getServerSideProps orgetStaticProps 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
Community Resources
See also
App Write Tests Component Testing Svelte Overview (`docs/app/write-tests/component-testing/svelte/overview.mdx`)
title: 'Svelte component testing' sidebar_label: Svelte overview sidebar_position: 10 slug: /app/component-testing/svelte/overview
Svelte Component Testing
Cypress Component Testing supports Svelte 5 in a variety of different
frameworks:
:::caution
Svelte is currently in alpha support for component testing.
:::
Tutorial
Visit the
Getting Started Guide 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:
Open Cypress:
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 guide.
For usage and examples, visit the
Svelte Examples guide.
:::
Framework Configuration
Cypress Component Testing works out of the box with Vite,
and a custom Webpack 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.
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
{
component: {
devServer: {
framework: 'svelte',
bundler: 'vite',
},
},
}:::
Svelte Vite Sample Apps
Svelte with Webpack
Cypress Component Testing works with Svelte apps that use Webpack 5+ as the
bundler.
Webpack Configuration
:::cypress-config-example
import webpackConfig from './webpack.config'{
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
See also
App Write Tests Component Testing Vue Overview (`docs/app/write-tests/component-testing/vue/overview.mdx`)
title: 'Vue component testing' sidebar_label: Vue overview sidebar_position: 10 slug: /app/component-testing/vue/overview
Vue Component Testing
Cypress Component Testing supports Vue 3+ with the following frameworks:
Tutorial
Visit the
Getting Started Guide 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:
Open Cypress:
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 guide.
For usage and examples, visit the
Vue Examples guide.
:::
Framework Configuration
Cypress Component Testing works out of the box with
Vite, and a custom Webpack
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.
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
{
component: {
devServer: {
framework: 'vue',
bundler: 'vite',
},
},
}:::
Vue Vite Sample Apps
Vue with Webpack
Cypress Component Testing works with Vue apps that use Webpack 5+ as the
bundler.
Webpack Configuration
:::cypress-config-example
import webpackConfig from './webpack.config'{
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
Using Cypress with Nuxt
Cypress does not ship a dedicated Nuxt 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 thevite bundler:
:::cypress-config-example
{
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 viaviteConfig. See
Meta-frameworks that own the bundler config. - Auto-imports — Nuxt auto-imports components and composables (such as
ref,useRoute, anduseRuntimeConfig). 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 yourviteConfig.
See also
Accessibility Changelog (`docs/accessibility/changelog.mdx`)
title: 'Cypress Accessibility Release Notes' sidebar_label: Changelog sidebar_position: 200
Changelog
Week of Oct 5, 2026
- Configure Axe Core® rules yourself with
axeConfig: Setaccessibility.axeConfigin the App Quality editor to enable or disable individual Axe-Core® rules, or scope a report withrunOnlytags such as WCAG 2.1 A and AA. SeeaxeConfig.
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
.csvor.jsonfile, 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 and working with AI agents.
Week of Apr 13, 2026
- The
accessibility.componentsconfiguration object addscomponentAttributesandcomponentAttributeFilters. See the components guide. - Cypress Accessibility analytics have been expanded in Enterprise Reporting, surfacing trends in rule failure counts, severity level of issues, and more. Get all the details in our guide, Catch accessibility regressions.
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, 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 for example prompts and setup.
Week of Feb 06, 2026
- We now support fetching Accessibility results from Buildkite CI with the Results API.
Week of Jan 16, 2026
- We've upgraded our axe-core version to 4.11.0.
- We now support fetching Accessibility results from Bitbucket CI with the Results API.
Week of Dec 19, 2025
- The
elementFiltersconfiguration property now supports an optionaldocumentScopefield 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 withdocumentScope. See the Element Filters 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.
Week of Dec 01, 2025
- The
profilesconfiguration property applies different configuration settings to different runs based on run tags. This enables you to customize accessibility testing behavior for different environments, branches, or test scenarios. See the Profiles guide for more details. - All configuration objects now support an optional
commentproperty 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-ignoreattribute.
Week of Oct 06, 2025
- False positives in "Interactive elements should be semantically correct" related to elements using the
contenteditableattribute have been addressed.
Week of Jul 07, 2025
- A new custom accessibility rule, "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.
Week of May 26, 2025
- A new 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 -
significantAttributesandattributeFilters. 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.
Week of May 12, 2025
- We now support fetching Accessibility results from AWS CodeBuild with the Results API.
Week of Mar 24, 2025
- Cypress Accessibility results are now included in the Data Extract API so that you can retrieve data over time.
Week of Mar 10, 2025
- The Cypress Accessibility 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.
- 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 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 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.
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 Elements section.
- 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, GitLab, and 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.
Week of Jul 29, 2024
- Fetching results in Azure and Jenkins is now supported in the new 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, 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 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 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' sidebar_label: FAQ sidebar_position: 160
Cypress Accessibility FAQ
Fixing violations
Where do I start when Cypress Accessibility reports hundreds of violations?
Start by narrowing the report to the code you own with viewFilters and 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 for the full process.
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 to decide whether it blocks a build, which keeps full visibility into the issue.
Why didn't my Cypress Accessibility score change after I fixed some violations?
The 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.
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 for how the comparison works.
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.
How do I fix Cypress Accessibility violations with an AI agent?
Configure Cypress 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 attributes to violation selectors helps it locate the source file without crawling your markup.
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. 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
How do I see which element failed an accessibility rule in Cypress?
Open the rule in a run's accessibility report and it expands into the violation 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.
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.
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.
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.
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.
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.
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 to be installed for your organization; without it, the button doesn't appear.
Can I file issues for a whole accessibility report at once?
Yes, with an AI agent connected to both Cypress 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 walks through the prompts, how to group violations into tickets, and the guardrails to keep on an agent that can write.
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 to make it the identifier, or use 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.
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.
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 and data-a11y-ignore rules are hiding.
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 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
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 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.
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.
Which browser should I use to record a local run for Cypress Accessibility?
Chrome, Edge, Chromium, or Electron. Reports are built from 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 for the other requirements.
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: 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.
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.
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 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.
Why does my local Cypress Accessibility report include pages my CI report excludes?
Your 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 entry for local runs and tag them with --tag. See Make your configuration match localhost.
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, 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 or close the run with the Run Completion API.
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 from your plan regardless of where it ran, which is another reason to keep local runs scoped with --spec.
Detecting changes
How do I find which pull request introduced a Cypress Accessibility violation?
Open Branch Review 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.
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, which fetches the run's results in CI so you can decide what should fail. See Block pull requests and set policies.
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.
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 to give each team's runs its own configuration inside one project, which keeps comparisons working.
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, 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. Views can drift the same way when URLs contain IDs or slugs, which views rules resolve. See Make the comparison trustworthy.
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.
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.
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. 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, its Cypress Accessibility report is marked partial and Branch Review says so, because a diff built on partial data can be misleading.
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.
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.
Can Cypress notify my team when accessibility results are ready?
Yes. The Slack and 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 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 and subscribe to run.accessibility.completed.
How do I track Cypress Accessibility trends across projects over time?
Use the Cypress Accessibility tab of 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 with the accessibility-per-project-summary, accessibility-per-project-over-time, and accessibility-details reports. See Track trends over time.
Ignoring elements
How do I exclude elements from Cypress Accessibility?
Add an 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. 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 instead, and to ignore entire pages, use viewFilters.
Do ignored elements affect my Cypress Accessibility score?
No. An element ignored by 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.
Why didn't my Cypress Accessibility score improve after ignoring an element?
The 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.
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
footermatches only the<footer>element. Match the container and its descendants, likefooter, footer *, to ignore a whole region. - The rule has a
documentScopethat 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.
Why do ignored elements still appear in my Cypress Accessibility report?
This is by design. Ignored elements appear under the Ignored element status 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.
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.
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.
Grouping and naming views
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 pattern to group them into one view and triage the issue once.
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 pattern with groupBy on that parameter to report on each value separately.
How do I create a separate Cypress Accessibility view for each value of a URL parameter?
Write a 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.
Does grouping URLs into a view change my Cypress Accessibility score?
Not your run-level score. The run 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.
What's the difference between views and viewFilters in Cypress Accessibility?
They do opposite things. 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 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.
Can I configure views for Cypress Accessibility without affecting UI Coverage?
No. Unlike viewFilters and 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.
Ignoring views and URLs
How do I exclude URLs from Cypress Accessibility?
Add a 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.
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.
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: truerule 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 matchwww.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 for details.
Element identification
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 for how identification works across snapshots.
How do I make Cypress Accessibility use my own attribute in violation selectors?
Add the attribute name to 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.
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 instead.
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 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.
How do I add component or team context to my Cypress Accessibility violation selectors?
Use 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, can see which component or team it belongs to without opening the page HTML. This differs from significantAttributes, which chooses the single attribute that identifies the element, whereas components adds context on top of that identifier.
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 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 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.
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.
componentskeeps a listed attribute wherever it appears on the element or an ancestor, but it can't add one that isn't in the DOM. includeInSelectorisfalse, which keeps the entry for documentation but doesn't change selectors.- A
componentAttributeFiltersrule withinclude: falsematches the value, so it's skipped. - The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.
Can I keep certain component attribute values out of my Cypress Accessibility selectors?
Yes. Add a 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
Where do I set Cypress Accessibility configuration?
In the App Quality tab of your project settings in Cypress Cloud. See Setting configuration.
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.
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.
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 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.
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 standards
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 for where automated checks stop.
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. 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.
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 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.
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 exposes per-rule and per-view results you can archive alongside your own assessment notes.
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. 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.
Axe Core® rules
Which accessibility rules does Cypress Accessibility run?
Cypress Accessibility runs Axe-Core®'s default ruleset against every captured snapshot, plus a few custom 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. Three further rules 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.
Can I change which Axe-Core® rules Cypress Accessibility runs?
Yes. Set axeConfig 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 in your application code.
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": {
"axeConfig": {
"rules": {
"color-contrast": { "enabled": true }
}
}
}
}See Rules that are off by default.
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; ignore the rule for specific elements yourself with the data-a11y-ignore attribute; or leave the rule on and control whether it blocks your build in CI with the Results API. Keeping a rule reported but non-blocking is often the best choice, since you retain visibility into the issue.
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.
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. 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.
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 response. See Axe-Core® library version and updates.
Profiles
How do I apply different Cypress Accessibility settings to different runs?
In your project's App Quality configuration in Cypress Cloud, add a profiles array, give each profile a name, and record the run with a matching --tag. 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.
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, 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.
If a run has multiple tags that match profiles, which Cypress Accessibility profile is used?
Cypress Cloud uses the first profile in the 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.
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, soaq-config-regressionmatches only the tagaq-config-regression, notAQ-Config-Regressionoraq-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.
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 that exclude every view) so Cypress Cloud produces an empty or tightly scoped accessibility report for the run instead. See Why use profiles?.
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, 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 to fail the build when a critical flow regresses. See Block pull requests.
Can a Cypress Accessibility profile change which Axe Core® rules run for a specific run?
Yes. Set axeConfig 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 in your application code.
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 and 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 Troubleshooting (`docs/accessibility/troubleshooting.mdx`)
title: 'Troubleshooting: Cypress Accessibility' sidebar_label: Troubleshooting sidebar_position: 150
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 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.
:::
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 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 --recordand a valid record key, against a project with aprojectId. 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 firefoxand--browser webkitruns produce no accessibility report.cypress rundefaults 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 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
footermatches only the<footer>element itself, whilefooter *matches the controls inside it.Order rules from specific to broad, and place any
include: trueexception before theinclude: falserule 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? for the full precedence rules.
Your score didn't improve after excluding an element
You removed a failing element with elementFilters, but the 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 and How the accessibility score is calculated.
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-ignoreattribute 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, 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 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.
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, which drops them from the report and the score.Exclude whole URLs you don't intend to cover with
viewFilters. To keep only your own application's URLs, listinclude: truerules 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 ids 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). 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. Attributes you list are checked before the defaults, so a stabledata-cyordata-testproduces clearer, more consistent selectors. Listingaria-labelalso turns the report into an inventory of your label text.json title="app quality config"{ "significantAttributes": ["data-cy"] }Ignore the dynamic attribute with
attributeFiltersso identification falls back to a stable attribute. When you filter a dynamicid, also filter the attributes that reference it, such asfor,aria-labelledby, andaria-describedby. Patterns match the whole value (they're anchored as^(...)$), and JSON requires backslashes to be doubled, so a token like\dmust 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 the run to apply your current configuration. This is by far the most common cause.
- An earlier rule matched first. For
elementFiltersandviewFilters, the first matching rule wins, so a broad rule above your specific one prevents it from applying. List specific rules first, and placeinclude: trueexceptions before theinclude: falserule they should override. - A nested list replaced a root one. Nesting a shared property such as
elementFiltersorattributeFiltersunder anaccessibilityoruiCoveragekey 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.
attributeFilterspatterns are anchored to the whole value, sovalue: "user"matches only the exact stringuser; usevalue: "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, 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, 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 and the profile questions in the FAQ.
Still stuck?
- The Cypress Accessibility FAQ answers focused questions about ignoring elements and URLs, element identification, configuration, and profiles.
- The Configuration overview covers where configuration lives, how it's scoped, and how to regenerate reports.
- How Cypress Accessibility works and How the accessibility score is calculated 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 sidebar_label: Work with AI agents sidebar_position: 110
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 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 ``.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 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 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 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, 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-contrastfailures 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 comparison in Cypress Cloud, useful when you want the difference in writing or as data.
Here are two accessibility reports,
report-main.jsonandreport-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 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, 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:
- `` is the branch you track, such as
main. - `` is your Cypress project ID, the
projectIdin your Cypress configuration file. - `` identifies the project in your issue tracker that the tickets are filed into, such as the Jira project key
WEBor the repositoryacme/storefrontin 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.
- Find the latest completed run on for project and pull its accessibility report.
- 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.
- For each proposed ticket, search in my issue tracker for a matching issue, open or closed in the last 90 days, matching on rule ID and view name.
- Report three groups: already tracked and open, previously closed but failing again, and not tracked at all.`}
Plan tickets from the latest report
<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 for the untracked failures only. For each one: use the summary pattern [Accessibility]
Then list the issues you created with their keys, and tell me anything you skipped and why.`}
Create the missing issues
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 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 and Block pull requests and set policies.
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.
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-componentattributes 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.
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.
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.
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.
Api AGENTS (`docs/api/AGENTS.md`)
Agent rules: API reference pages
The root AGENTS.md still applies; this file adds the rules
specific to docs/api/ (commands, Cypress.* APIs, node events, utilities).
Reasoning and examples live inAGENTS_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 inAGENTS_REFERENCE.md.
Frontmatter
Reference frontmatter is terse. Mirror the sibling file you're adding next to.
---
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/apigets| Cypress API Documentationat build time fromsrc/sectionTitles.js, asserted bycypress/e2e/page_titles.cy.ts.description: one sentence saying what the command does.sidebar_label: the bare name, nocy.prefix, no parentheses.slug: only where the siblings carry one. It repeats the file's own route, sodocs/api/cypress-api/omits it entirely.- The H1 is the bare name (
# click), not the title.
Page skeleton
`` 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:
| 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' sidebar_label: 'Table of Contents' sidebar_position: 10
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.
Cypress commands can be classified one of the following
query- commands that read the state of your applicationassertion- command which assert on a given stateaction- interact with your application as a user wouldother- any other command that is useful for writing tests
The differences between queries and other commands are outline in the
Retry-ability Guide.
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() |
Assign an alias for later use. Reference the alias later within a cy.get() query or cy.wait() command. |
.children() |
Get the children of each element within a set of DOM elements. |
.closest() |
Get the element itself or its closest ancestor that matches a selector. |
.contains() |
Select a DOM element by text content. |
.document() |
Get the window.document of the active page. |
.eq() |
Select a DOM element by index from a collection. |
.filter() |
Filter elements with a selector. |
.find() |
Find descendent elements with a selector. |
.first() |
Select the first item in a collection. |
.focused() |
Get the DOM element that is currently focused. |
.get() |
Find DOM elements by selector, or read an alias previously created with the .as() command. |
.getAllCookies() |
Get all browser cookies. |
.getAllLocalStorage() |
Get localStorage data for all origins with which the test has interacted. |
.getAllSessionStorage() |
Get sessionStorage data for all origins with which the test has interacted. |
.getCookie() |
Get a browser cookie by its name. |
.getCookies() |
Get browser cookies for the current domain or a specified domain. |
.hash() |
Get the URL hash of the active page. |
.invoke() |
Invoke a function on the previously yielded subject. |
.its() |
Get a property's value on the previously yielded subject. |
.last() |
Select the last item in a collection. |
.location() |
Get the window.location object of the active page. |
.next() |
Get the next sibling element. |
.nextAll() |
Get all following sibling elements. |
.nextUntil() |
Get all following sibling elements until reaching a selector. |
.not() |
Filter selected elements with a selector. |
.parent() |
Get the parent of a DOM element. |
.parents() |
Get all parent elements of a DOM element. |
.parentsUntil() |
Get all parent elements up to a selector. |
.prev() |
Get the previous sibling element. |
.prevAll() |
Get all previous sibling elements. |
.prevUntil() |
Get all following previous sibling elements until reaching a selector. |
.root() |
Get the root DOM element. |
.shadow() |
Traverse into the shadow DOM of an element. |
.siblings() |
Get all sibling elements. |
.title() |
Get the document.title property of the active page. |
.url() |
Get the URL of the active page. |
.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
and the Assertions Reference.
| Command | Usage |
|---|---|
.and() |
Alias for .should(). Assert on the state of your application. |
.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.
| Command | Usage |
|---|---|
.check() |
Check checkbox or radio elements. |
.clear() |
Clear the value of an input or textarea. |
.click() |
Click a DOM element. |
.dblclick() |
Double-click a DOM element. |
.rightclick() |
Right click a DOM element. |
.scrollIntoView() |
Scroll an element into view. |
.scrollTo() |
Scroll to a specific position. |
.select() |
Select an <option> within a <select>. |
.selectFile() |
Selects a file in an HTML5 input element, or simulates dragging a file into the browser. |
.trigger() |
Trigger an event on a DOM element. |
.type() |
Type into a DOM element. |
.uncheck() |
Uncheck checkbox(es). |
Other Commands
Cypress has a variety of additional commands to help write tests.
| Command | Usage |
|---|---|
.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() |
Clear all browser cookies. |
.clearAllLocalStorage() |
Clear localStorage data for all origins with which the test has interacted. |
.clearAllSessionStorage() |
Clear sessionStorage data for all origins with which the test has interacted. |
.clearCookie() |
Clear a specific browser cookie. |
.clearCookies() |
Clear browser cookies for a domain. |
.clearLocalStorage() |
Clear data in localStorage for current domain and subdomain. |
.clock() |
Override the browser's built-in time objects (Date, setTimeout and similar), allowing them to be controlled via cy.tick(). |
.debug() |
Set a debugger statement and log what the previous command yields. |
.each() |
Invoke a callback on each item in an array. |
.env() |
Access secret environment variables in your tests. |
.fixture() |
Load a fixed set of data from disk. |
.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() |
Navigate back or forward using the browser's history. |
.hover() |
Cypress does not have a cy.hover() command. See Issue #10. |
.intercept() |
Spy and stub network requests and responses. |
.log() |
Print a message to the Cypress Command Log. |
.mount() |
Mount a component for Cypress Component Testing. |
.origin() |
Visit multiple domains of different origin in a single test. |
.pause() |
Pause test execution, allowing interaction with the application under test before resuming. |
.press() |
Trigger native key events in your application to simulate real user keyboard interactions. |
.prompt() |
Use natural language to generate Cypress tests with AI. |
.readFile() |
Read a file from disk. |
.reload() |
Reload the page. |
.request() |
Make an HTTP request. |
.screenshot() |
Take a screenshot of the application under test. |
.session() |
Cache and restore cookies, localStorage, and sessionStorage (i.e. session data) to recreate a consistent browser context between tests. |
.setCookie() |
Set a browser cookie. |
.spread() |
Invoke a callback function with multiple arguments. Similar to .then(). |
.spy() |
Wrap a method in a spy to record calls to the function. |
.stub() |
Replace a method, record its usage, and control its behavior. |
.submit() |
Submit a form. |
.task() |
Execute code in Node via the task plugin event. |
.then() |
Invoke a callback function with the current subject to run code at specific points during a Cypress test. |
.tick() |
Move time after overriding a native time functions with cy.clock(). |
.viewport() |
Control the size and orientation of the screen for your application. |
.visit() |
Visit a remote URL. Many tests begin with this command. |
.wait() |
Wait a number of milliseconds, or wait for an aliased resource to resolve. |
.within() |
Scopes all subsequent cy commands to within this element. Useful when working within a particular group of elements such as a <form>. |
.wrap() |
Yield the object passed into .wrap(). If the object is a promise, yield its resolved value. |
.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.
Custom Commands and Queries
Cypress exposes interfaces to write
Custom Commands and
Custom Queries. See those pages for more
details.
The Cypress community has created a large number of
Command Plugins 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 |
CPU architecture name of the underlying OS, as returned from Node's os.arch(). |
Cypress.browser |
Information about the current browser, such as browser family and version. |
Cypress.Commands |
Create new custom commands and extend or override existing ones. |
Cypress.config() |
Get and set Cypress configuration from inside your tests. |
Cypress.Cookies.debug() |
Generate console logs whenever a cookie is modified. |
Cypress.currentRetry |
A number representing the current test retry count. |
Cypress.currentTest |
An object with information about the currently executing test. |
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 |
A collection of DOM related helper methods. |
Cypress.ElementSelector |
Configure selector priority used by Cypress Studio and cy.prompt(). |
Cypress.expose |
Expose configuration values to the browser context. |
Cypress.isBrowser() |
Checks if the current browser matches the given name or filter. |
Cypress.isCy() |
checks if a variable is a valid instance of cy or a cy chainable. |
Cypress.Keyboard.defaults() |
Set default values for how the .type() command is executed. |
Cypress.platform |
The underlaying OS name, as returned by Node's os.platform(). |
Cypress.require |
Use dependencies within the cy.origin() callback function. |
Cypress.Screenshot.defaults() |
Set defaults for screenshots captured by the .screenshot() command and the automatic screenshots taken during test failures. |
Cypress.session |
A collection of helper methods related to the .session() command. |
Cypress.spec |
An object with information about the currently executing spec file. |
Cypress.testingType |
The current testing type, eg. "e2e" or "component". |
Cypress.version |
The current Cypress version. |
Utilities
Cypress makes several common libraries available directly on the globalCypress object.
| Utility | Usage |
|---|---|
Cypress.$ |
Cypress automatically includes jQuery and exposes it as Cypress.$. |
Cypress.Blob |
Cypress automatically includes a Blob library and exposes it as Cypress.Blob. |
Cypress.Buffer |
Cypress automatically includes a Buffer polyfill for the browser and exposes it as Cypress.Buffer. |
Cypress._ |
Cypress automatically includes lodash and exposes it as Cypress._. |
Cypress.minimatch |
Cypress automatically includes minimatch and exposes it as Cypress.minimatch. |
Cypress.Promise |
Cypress automatically includes Bluebird and exposes it as Cypress.Promise. |
Cypress.sinon |
Cypress automatically includes Sinon.JS 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 and
Node Events Overview.
| API | Usage |
|---|---|
| After Run Event | 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 | After a screenshot is taken, you can get details about it via the after:screenshot plugin event. |
| After Spec Event | 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 | 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 | 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 | 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 function. |
| Configuration API | Cypress enables you to dynamically modify configuration values and environment variables from your Cypress configuration. |
| 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' sidebar_label: FAQ sidebar_position: 220
Cypress Cloud FAQ
General
What is Cypress Cloud?
Cypress Cloud gives you access to tests you've
recorded - typically when running Cypress tests from your
CI provider - and provides you
insight into what happened during your tests run.
You can read more in the
introduction to Cypress Cloud.
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
before being sent to the Cloud so those are not captured.
When Test Replay capturing is enabled, the additional data outlined
below will be sent to the Cloud. You can
disable capturing 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.
How is this different than CI?
Cypress Cloud is complementary to your
CI provider, 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 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 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, see the stdout as well as
screenshots and video of the tests running. It should be instantly clear what
the problem was.
What counts as a test result?
Which pricing tier is best for you depends on
the number of tests you record each month in your organization.
Tests are recorded when cypress run
is called with the --record flag while supplying the record --key. This
means your test run data 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
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 page
within Cypress Cloud.
What counts as a user?
A user 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.
To see how many of your seats are in use, check the
Billing & Usage page in Cypress
Cloud.
How much does it cost?
See our Pricing Page for more details.
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 you explicitly invite to your
organization can see its
recorded runs. Even if someone knows your projectId, they will not have access
to your runs unless you have invited them.
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:
- Logging into Cypress Cloud
- Select your organization
- Navigate to the Billing and Usage tab
- Review your organization's usage
- Scroll down and select Upgrade under your plan of choice
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.
When does my billing period reset?
Your usage cycle resets at the start of each billing period, at which point
your recorded test result and AI usage counters
return to zero for the new period. Org-levelcy.prompt execution counts reset on the same schedule.
See cy.prompt 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 page.
How do I reduce my Cypress Cloud usage or lower my bill?
Because Cypress Cloud meters
test results (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
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
to cut redundant tests that cover the same flows. - 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 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 guide.
If your usage consistently exceeds your plan, compare options on the
pricing page; 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.
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 without the --record
flag which does not communicate with our external servers and will not record
any test results.
Using Cypress Cloud
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.
It's generated by Cypress and typically is found in your
Cypress configuration.
:::cypress-config-example
{
projectId: 'a7bq2k'
}:::
For further detail see the
Identification
section of the Cypress Cloud docs.
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. 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.
For further details see the
Identification
section of the Cypress Cloud docs.
How do I record my tests?
- First set up the project to record.
- Then record your runs.
After recording your tests, you will see them in
Cypress Cloud and in the Cypress App Runs tab.
Can I delete a run from Cypress Cloud?
You can archive a 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.
Can I host Cypress Cloud data myself?
No. A self-hosted version of Cypress Cloud is not available at this time.
Why is test parallelization based on spec files and not on the individual functions?
Cypress
test 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.
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 and
run with our sample projects,
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
when starting Cypress in each container:
cypress run --record --parallel --ci-build-id $CI_RUN_IDFor reference, here are
the variables
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.
I'm working with a restrictive VPN. Which subdomains do I have to allow on my VPN for Cypress Cloud to work properly?
Re-run optimization
Can I rerun only failed tests?
Yes, depending on where you are running tests:
- In CI, Re-run 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 lets
you rerun only the failed tests from a recorded CI run on your current branch. - During a single run, test retries automatically
re-attempt failed individual tests before the run finishes.
How is Re-run optimization different from test retries?
They solve different problems. 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.
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.
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.
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.
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.
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
What is Spec Prioritization?
Spec Prioritization is
a Smart Orchestration 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.
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: 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.
What plan do I need to use Spec Prioritization?
Spec Prioritization is available on the
Business and Enterprise tiers. Not sure if
upgrading is worth it? The
recommendations on the run
overview page predict how much time Smart Orchestration features would save your
suite.
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
for the full steps.
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
What is Auto Cancellation in Cypress?
Auto Cancellation is a
Cypress Cloud Smart Orchestration
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.
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
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.
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.
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.
Is Auto Cancellation free?
No. Auto Cancellation is a paid Smart Orchestration feature available on the
Business and Enterprise Cypress Cloud plans.
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.
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, which
opens the Test Results tab
pre-filtered to the failures, or to use the
Tests for Review panel, which
orders results by failures first. Open a failed test's
detail sidebar and
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
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 for how Cypress
Cloud detects and tracks them.
How does Cypress detect flaky tests?
With 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 based on its
flake rate.
What causes flaky tests?
Flake usually comes from timing issues, race conditions, or differences between
your local and CI environments. Test Replay lets
you compare a passing and failing attempt on the same code to find the cause.
How do I fix a flaky test?
Open a failing attempt from the flaky test details panel in
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.
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 for how
flake rate maps to severity levels.
Do I need test retries enabled to detect flaky tests?
Yes. Test retries are the
fundamental mechanism that lets Cypress Cloud detect flaky tests, so enabling
them is required for any Flaky Test Management feature.
Which Cypress Cloud plan is required for Flaky Test Management?
Flake detection, analytics, and alerting require a
Team Cypress Cloud plan. Enterprise Reporting and
the Data Extract API require an Enterprise plan, and
Cloud MCP is included on every Cypress Cloud
plan.
Cypress Cloud Account
What is a Cypress Cloud organization?
A Cypress Cloud organization is the top-level container that groups your
projects,
users,
teams, billing and usage, and
integrations. It lets you manage access
control and application quality across every project from one place instead of configuring each
project individually.
How do I create an organization in Cypress Cloud?
Open the organization switcher in Cypress Cloud and click
Create new organization. A "Default Project" is created automatically, which you can rename and
configure in Project Settings.
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 roll up within each
organization.
Who can manage an organization?
Organization owners and admins can invite users, create teams, configure
Cloud AI, and set up integrations. Only
owners can rename or delete an organization and configure
single sign-on (SSO). See
user roles for the full permissions breakdown.
How do I delete an organization?
You can delete an organization you own once it has no projects. First
delete or
transfer ownership of every project to
another organization, then delete the organization from its settings.
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.
What if I can't access my Cypress Cloud account?
If you haven't signed up, see the
Sign Up with an Invitation
instructions.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.
Can I delete my Cypress account?
You can delete your Cypress account from
your Cypress Cloud profile. Deleting your
account cannot be undone! By deleting your Cypress account, all associated data
in your account will be permanently deleted.
How do I invite a user to Cypress Cloud?
An organization Owner or Admin can
invite users from the Users & Teams page by clicking Invite User, adding
one or more email addresses, and selecting a role.
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 for details.
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 for an
exact breakdown.
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.
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.
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 page or contact
[email protected]. See
User updates.
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.
Teams
What is a team in Cypress Cloud?
A team 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.
Who can create and manage teams?
Organization owner or admin roles can create
teams. Once a team exists, owners, admins, and the dedicated
team admin 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.
Do teams affect access to public projects?
No. Public projects are visible to all
Cypress Cloud users, including those outside of your organization, regardless of team
membership. Teams only control access to private projects.
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 for setup best practices.
Debugging
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 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 for the full
workflow.
Can I debug a CI failure without reproducing it locally?
Yes. 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.
How do I know if a test failure is a real bug or just flaky?
Use Flaky Test Management to see whether
a test has a history of passing on retry, and
Branch Review to compare your branch against its
base and determine whether your change introduced the failure or it already
existed.
Do I need to change my tests to debug them in Cypress Cloud?
No. You only need to record your runs withcypress run --record. Test Replay, Error Summaries, and the test detail sidebar
work automatically, with no changes to your test code.
Test Replay
What is Test Replay?
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
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, 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!
How much does Test Replay cost?
Nothing. It's free and included in all Cypress Cloud plans.
Can I use Test Replay for tests recorded in different browsers?
Test Replay uses Chrome DevTools Protocol(CDP), 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 (screenshots, videos, and CI logs) via other browsers in separate run groups.
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.
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 in Cypress Cloud. There is no local option for opting out at this time.
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.
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.
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.
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.
Does Cypress Test Replay network redaction change what I can test?
No, your Cypress tests and assertions are not affected.
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.
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.
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.
Do I need a specific Cypress version to get network redaction in Test Replay?
Redaction isn't tied to a specific Cypress version.
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
What is the Cypress Cloud CLI?
The Cypress 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 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.
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 for full setup steps.
How do I authenticate the Cloud CLI in CI?
Set the CYPRESS_CLOUD_TOKEN environment variable to a
personal access token,
which you generate from your Cypress Cloud 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 for
the full setup, including OAuth and personal access token options.
How is the Cloud CLI different from Cloud MCP?
Both give programmatic access to your Cypress Cloud data.
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 is a command-line tool for humans,
scripts, and terminal-based agents, which suits automation and custom tooling.
Many teams use both.
Which URL does the Cloud CLI need allowed on a restrictive VPN?
The Cloud CLI communicates with the Cypress Cloud API athttps://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.
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.
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
[email protected] 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.
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 withcypress run --record.
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.
Why am I getting an authentication error from the Cloud CLI?
Confirm you are logged in with cy-cloud status. If you authenticate through theCYPRESS_CLOUD_TOKEN environment variable, verify the token is set and valid.
Remember that cy-cloud logout does not unset that environment variable.
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.
What does the Cloud CLI error "Replay not available" mean?
That test does not have Test Replay data available. Confirm
Test Replay capturing was enabled for the run, and
that the run is within your data retention window.
Cloud AI :sparkles:
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 and cy.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 for the full picture. For cy.prompt execution limits, billing, and the grace period, see cy.prompt below.
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, thecypress tapCLI, and
Cypress Studio recording (without AI
recommendations). - Any Cloud plan, including the free Starter plan:
cy.prompt, Studio AI recommendations, Test Intent
Summaries, Error Summaries, Cloud MCP, and
the Cloud CLI. - Included with a premium solution: UI Coverage Test Generation comes with
UI Coverage, and agent-ready
accessibility reports come with
Cypress Accessibility.
A paid plan raises limits rather than unlocking capabilities: a largercy.prompt execution allowance and higher hourly limits for cy.prompt and
Studio AI. See
AI usage limits.
cy.prompt
What is a cy.prompt execution?
Every time a cy.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
page. For migrating from cy.prompt to regular Cypress code, see the
App FAQ.
What is AI self-healing?
cy.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 in the AI Test
Generation guide.
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 multiplecy.promptcalls.
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.
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.
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.promptwill 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.
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.
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? and your
organization's
Billing & Usage page for dates.
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
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.
Can I be notified of usage approaching limits?
Yes. On the Billing & Usage
page, you can set thresholds for email alerts based on usage, similar to the
ones you already get for test management.
What limitations does cy.prompt have?
See the Limitations section in thecy.prompt API reference 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 still applies; this file adds the rules
specific to docs/partials/, the shared MDX fragments rendered inside other
pages. Reasoning lives inAGENTS_REFERENCE.md.
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.
# which pages render <CloudFreePlan />?
grep -rl "CloudFreePlan" docs --include="*.mdx"Writing one
- Name it
_kebab-case.mdx. The leading underscore is what keeps Docusaurus
andscripts/lint-frontmatter.jsfrom 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.jsis 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.
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:
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 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.
- Error name: This is the type of error (e.g.
AssertionError,CypressError) - 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. - Learn more: Some error messages contain a Learn more link that will
take you to relevant Cypress documentation. - 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
and highlight the line and column in editors that support it. - Code frame: This shows a snippet of code where the failure occurred, with
the relevant line and column highlighted. - 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. - 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.
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:
- Open your project in Cypress Cloud and go to Project Settings.
- Select the App Quality tab, which holds the configuration editor.
- 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.
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 detachedSplit the chain into separate statements so each one re-queries from the top.
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() 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 withThe subject is no longer attached to the DOM.
// 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 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. 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 for details, including how to regenerate past reports with a new configuration without rerunning your tests.
Syntax
{
"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 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
attributeandvaluepattern is anchored automatically, as if wrapped in^(...)$, so it must match the entire name or value. Use wildcards for partial matches:value: "user-.*"matchesuser-123, whereasvalue: "user"matches only the exact stringuser. 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
\dmust be written\\din the configuration. A single backslash is dropped, turning\dinto a literaldthat matches nothing you intended. - Attribute names are matched case-insensitively; values are matched case-sensitively.
- Only attributes and individual
classtokens 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.
{
"attributeFilters": [
{
"attribute": "id",
"value": ":r.*",
"include": false,
"comment": "React useId() values are regenerated on every render"
}
]
}HTML
<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 (
foron labels) - ARIA relationships (
aria-labelledby,aria-describedby,aria-controls,aria-owns,aria-details)
{
"attributeFilters": [
{
"attribute": "id|for|aria-describedby|aria-labelledby",
"value": "mat-.*",
"include": false,
"comment": "Angular Material regenerates mat-* ids per render"
}
]
}HTML
<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"]
spanKeeping 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.
{
"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
<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.
{
"attributeFilters": [
{
"attribute": "id",
"value": "delete-user-\\d+",
"include": false,
"comment": "Row action ids include the per-user database id"
}
]
}HTML
<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. 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`)
Benefits: Cancelling a run once
test failures reach your threshold will:
- Save time. Identify failures early and resolve issues faster.
- Reduce CI costs. Cut down on unnecessary test execution, leading to significant savings for large test suites.
- Free up CI resources. Stop spending machines on a failed run and keep CI pipelines available for validating fixes.
- Optimize future runs. With 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`)
Recording test results with the
--recordflag
to Cypress Cloud.- In-depth and shareable
test reports. - Visibility into test failures via quick access to Test Replay, error messages, stack
traces, screenshots, videos, and contextual details. - Integrating testing with the pull-request (PR) process
via
commit status check guards
and convenient
test report comments. - Detecting flaky tests and surfacing
them via Slack alerts or
GitHub PR status checks.
- In-depth and shareable
Parallelizing test runs
and optimizing their execution via
intelligent load-balancing
of test specs across CI machines with the--parallelflag.Organizing and consolidating multiple
cypress runcalls by labeled groups
into a single report within Cypress Cloud. In
the example above we use the--group UI-Chromeflag 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 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 withcy.on('uncaught:exception')
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() 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.
Incorrect Usage
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' }Correct Usage
cy.env(['apiKey']).then(({ apiKey }) => {
expect(Boolean(apiKey)).to.be.true
})
// ✅ Command Log: assert expected true to be truePartials Cy Env Vs Cypress Expose (`docs/partials/_cy-env-vs-cypress-expose.mdx`)
Both cy.env() and Cypress.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
// ✅ 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 browserPartials 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(),.invoke(), and any chained command that fails can all
print a value to the Command Log and
the console output. What happens
to a value after cy.env() yields it is up to you. See
Handling the yielded value safely.
:::
Partials Default Selector Priority (`docs/partials/_default-selector-priority.mdx`)
Default Selector Priority
data-cydata-testdata-testiddata-qanameidclasstagattributesnth-child
Partials Document Domain Workaround (`docs/partials/_document-domain-workaround.mdx`)
:::caution
Re-Enabling document.domain Injection
As of Cypress v14.0.0, 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 in the same test.
By setting the
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 becypress.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 clusters. - 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 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 [](/app/core-concepts/introduction-to-cypress#Assertions) {#Assertions}
Partials Header Requirements (`docs/partials/_header-requirements.mdx`)
Requirements [](/app/core-concepts/introduction-to-cypress#Chains-of-Commands) {#Requirements}
Partials Header Timeouts (`docs/partials/_header-timeouts.mdx`)
Timeouts [](/app/core-concepts/introduction-to-cypress#Timeouts) {#Timeouts}
Partials Header Yields (`docs/partials/_header-yields.mdx`)
Yields [](/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:
:::note
A note for React users
The mount() command exported from the
cypress/react
module supports standard JSX syntax for mounting components.
:::
import { mount } from 'cypress/react':::note
A note for Vue users
The mount() command exported from the
cypress/vue
library uses Vue Test Utils internally, but
instead of mounting your components in a virtual browser in node, it mounts them
in your actual browser.
:::
import { mount } from 'cypress/vue':::note
A note for Angular users
The mount() command exported from the
cypress/angular
library uses Angular TestBed
internally, but instead of mounting your components in a virtual browser in
node, it mounts them in your actual browser.
:::
import { mount } from 'cypress/angular'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.
:::
Partials Inverted Contains Selection (`docs/partials/_inverted-contains-selection.mdx`)
There is no built-in negation for cy.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() and the
jQuery :contains selector. The
match is a case-sensitive substring match.
<ul>
<li>Test: Name</li>
<li>Test: Name (1)</li>
<li>Test: Name (2)</li>
<li>Test: Name (3)</li>
</ul>// yields only <li>Test: Name</li>, the item without a numeric suffix
cy.get('li').not(':contains("(")')The same approach works with .filter() and the
:not() selector when you would rather
keep a positive filter:
// 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.
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 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 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
elementFiltersrules and a profile defines its ownelementFilters, 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
accessibilityanduiCoverageobjects are merged one level deep. Overriding a single setting inside one of them, such asaccessibility.significantAttributes, leaves the sibling settings in that object (likeaccessibility.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
profilesarray 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,
viewFiltersthat 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
{
"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:
- Record the Cypress run and run your validation script within the same CI run (the same build, workflow, or pipeline).
- 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, orrequires), 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.
References: Understanding GitHub Actions | GitHub Actions 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.
References: GitLab CI/CD pipelines | GitLab predefined variables
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.
References: Jenkins documentation | Jenkins 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.
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.
References: Azure Pipelines key concepts | Azure Pipelines predefined 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 Azure environment. Previous Cypress versions are not supported in Azure pipelines.
Essential environment variables
TF_BUILDandAZURE_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 theSYSTEM_JOBATTEMPTbeing incremented.SYSTEM_JOBATTEMPT- Value identifies the pipelines shared attempt index. Value is incremented when jobs are retried from failure.
References: About CircleCI | CircleCI 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 newCIRCLE_WORKFLOW_IDvalue 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.
References: AWS CodeBuild documentation | AWS CodeBuild environment variables
Essential environment variables
CODEBUILD_BUILD_ID- Presence identifies the environment as an AWS CodeBuild environment. Value uniquely identifies a build.
References: Drone pipeline overview | Drone environment reference
Essential environment variables
DRONE- Presence identifies the environment as a Drone environment.DRONE_BUILD_NUMBER- Value uniquely identifies a Drone build.
References: Bitbucket Cloud documentation | Bitbucket 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.
References: Buildkite documentation | Buildkite 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.
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.
CYPRESS_PROJECT_ID=AAA
CYPRESS_RECORD_KEY=BBB
GITHUB_ACTIONS=true
GITHUB_RUN_ID=111
GITHUB_RUN_ATTEMPT=1
node verifyResults.jsThe 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:
{props.product === 'accessibility' ? (
The scrollIntoView 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.
) : 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, 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
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.
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, ensure that inline
source maps are enabled to get the same experience. Some examples of this include:
- With webpack and the
webpack preprocessor, set
thedevtooloption toinline-source-map. - With esbuild and the
esbuild preprocessor, set
thesourcemapoption toinlinewhen
creating the bundler. - With cucumber and the
cucumber preprocessor
third party bundlers are used to bundle the code.- For esbuild and the
esbuild preprocessor,
set thesourcemapoption toinlinewhen
creating the bundler.
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.
- For esbuild and the
If using TypeScript with any custom preprocessor, you will want to make sure that the TypeScript
compiler is generating source maps. This can be done by setting the sourceMap option in yourtsconfig.json to true. The inlineSourceMap option is not recommended as it does not provide an accurate code frame.
See our recommended tsconfig.json as a reference.
Partials Support File Configuration (`docs/partials/_support-file-configuration.mdx`)
A great place to put this configuration is in the
supportFile,
since it is loaded before any test files are evaluated.
Partials Test Replay Info (`docs/partials/_test-replay-info.mdx`)
:::tip
Debugging Cypress Cloud Test Runs?
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
:::
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
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.
:::
Partials Url Parts Diagram (`docs/partials/_url-parts-diagram.mdx`)
In a hash-based route, a query string after the # is part of the hash:
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 APIhttps://capture.cypress.io- Cypress Test Replayhttps://s3.amazonaws.com/capture.cypress.io- Uploading Cypress Test Replay from Test Runnerhttps://cloud.cypress.io- Cypress Cloud, Studiohttps://cloud-api.cypress.io- Cypress Cloud CLI (cy-cloud)https://docs.cypress.io- Cypress documentationhttps://download.cypress.io- CDN download of Cypress binaryhttps://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 IP18.213.72.78- Dedicated IP35.169.145.173- Dedicated IP44.199.152.70- Dedicated IP52.70.95.89- Dedicated IP
Partials Viewfilters Example Third Party (`docs/partials/_viewfilters-example-third-party.mdx`)
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/aboutViews shown in UI
https://www.my-app.com/home
https://www.my-app.com/aboutPartials Viewfilters Matching And Validation (`docs/partials/_viewfilters-matching-and-validation.mdx`)
Pattern matching follows 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/adminmatcheshttps://www.my-app.com/admin?tab=users. - Trailing slashes are optional by default:
https://www.my-app.com/adminmatches both/adminand/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 matchhttps://www.my-app.com/home, buthttps://*.my-app.com/*does. - The pattern
*on its own matches every URL.
Validation rules
Cypress Cloud rejects a configuration when:
- A rule is missing
patternorinclude. - A
patternisn'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 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
{
"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/payViews shown in UI
/dashboards
/dashboards/*The two numbered dashboard URLs group into a single /dashboards/* view through the automatic view creation rules, 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
{
"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/500Views shown in UI
http://localhost:3000/homePartials Viewfilters Syntax (`docs/partials/_viewfilters-syntax.mdx`)
Syntax
{
"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=doneand/home?status=newgroup into a single/homeview. A pattern that captures a query parameter lets you report on them separately. - Create distinct view groups: Use
groupByto 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 andelementFilters, 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
{
"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:
{
"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 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, where possible.
- A pattern that doesn't match any URLs in the run does not appear in the report.
- URLs excluded by a
viewFiltersrule are excluded beforeviewspatterns are applied. Aviewspattern cannot bring an excluded URL back into the report.
Pattern matching follows 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/*matcheshttps://www.my-app.com/users/bob#settings. - Trailing slashes are optional by default:
/users/boband/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
{
"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=trueViews shown in UI
/users/*
/usersThe 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
{
"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=trueViews shown in UI
/users/:name
/usersGrouping by a path parameter
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/harperViews shown in UI
/analytics/performance/:id
/analytics/usage/:idGrouping 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
{
"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#statusViewViews 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
{
"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/editViews shown in UI
/home
/profile
/profile/editTroubleshooting
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 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' sidebar_label: Changelog sidebar_position: 200
Changelog
Week of May 18, 2026
- UI Coverage in Enterprise Reporting: UI Coverage trends are now available in the Enterprise Reporting 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 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, 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_runstool now also reports each run's UI Coverage score. See working 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.
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.
Week of Dec 19, 2025
- Document scoping for nested contexts (
documentScope): TheelementFilters,elements,elementGroups, andallowedInteractionCommandsconfiguration properties now accept an optionaldocumentScopefield 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, Elements, Element Groups, and Allowed Interaction Commands documentation for details and examples.
Week of Dec 12, 2025
- Per-run configuration with
profiles: Theprofilesconfiguration property lets you apply different configuration settings to different runs based on run tags. Use it to customize UI Coverage behavior for specific environments, branches, or test scenarios. See the Profiles guide for details. - Inline configuration comments: All configuration objects now support an optional
commentproperty 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 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:
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.
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 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.
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, 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 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 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, GitLab, and Bitbucket pull request and merge request comments alongside test results. Install integrations and enable comments in Project Settings.
Week of Aug 12, 2024
- Improved
attributeFiltersbehavior: When matching against class attributes, theattributeFiltersconfiguration option now targets and filters individual class names rather than the entireclassattribute 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
elementFiltersin your UI Coverage configuration 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
viewFiltersin your UI Coverage configuration 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.
- Anchor elements considered interactive: Anchor elements (
atags) are now considered interactive even when they do not have anhrefattribute.
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-groupattribute 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' sidebar_label: FAQ sidebar_position: 160
Cypress UI Coverage FAQ
General
What is UI Coverage?
UI Coverage 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, along with a coverage score you can track over time.
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 data, so any run recorded to Cypress Cloud with Test Replay on Cypress v13 or later is ready to use. See setup for details.
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 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 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.
How do I get started with UI Coverage?
Record a run to Cypress Cloud with 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, and optionally tune the report with App Quality configuration. The Get Started guide walks through the whole path.
What do I need to use UI Coverage?
Three things: a Cypress project recording to Cypress Cloud, 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. No test changes, plugins, or code instrumentation are required.
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, 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.
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.
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 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.
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.
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 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.
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, 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.
What's the difference between UI Coverage and Cypress Accessibility?
Both are Cypress Cloud App Quality features built on the same 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 tells you whether the UI your tests render has accessibility violations. They share configuration properties like viewFilters and elementFilters, which you can scope to one product or the other. See Configuration scope.
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. 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 for example prompts and how to tune reports for clearer agent signal.
Finding coverage gaps
How do I find which parts of my UI aren't tested?
Record a run to Cypress Cloud with 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 by coverage score, lists the untested interactive elements on each one, and flags the pages your tests never visited as untested links. The Identify coverage gaps guide walks through the full workflow step by step.
Where should I start if my UI Coverage score is low?
In Cypress Cloud, start with your lowest-scoring 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) and links to pages you'll never test (exclude them with viewFilters) both lower a score without pointing to a real gap. See Why is my UI Coverage score lower than I expect? and Identify coverage gaps.
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 and Views.
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.
Closing coverage gaps
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, 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 or by writing a targeted test yourself. An element moves from untested to tested once a recognized interaction command targets it. See Address coverage gaps for the full workflow.
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.
Can Cypress UI Coverage write tests for me?
Yes, through Test Generation. 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.
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 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 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.
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.
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 and Start with your lowest-scoring views.
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 creates a view 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
How do I compare UI Coverage reports between two runs?
You have two routes. In 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 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 for the full workflow with each.
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.
How do I tell whether a pull request reduced my UI Coverage?
Open the pull request's run in 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. See Compare reports and Block pull requests to fail CI automatically when coverage drops.
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.
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 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 and exclude unstable identifiers with attributeFilters, then regenerate the run. See Stabilize the comparison.
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, since both read the same recorded runs. See Compare reports and Branch Review best practices.
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, 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.
Can I compare UI Coverage reports with an AI agent or the Cypress Cloud MCP?
Yes. The Cypress 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.
Monitoring coverage over time
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 diffs any two runs and the Results API enforces the trend in CI. See Monitor changes for the full workflow.
How do I get notified when my UI Coverage changes?
Connect Slack or 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, GitLab, or Bitbucket) 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: Cypress Cloud sends run.uiCoverage.completed when the UI Coverage report finishes processing. See Monitor changes.
Can I see UI Coverage trends across all my projects?
Yes. Enterprise Reporting 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 to build your own dashboards. See Track trends across projects.
Reducing test duplication
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.
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 on each occurrence. See Reduce test duplication.
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.
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 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(), set a cookie or storage flag directly, or seed state with cy.request(). Keep one test that still drives the flow through the UI so its coverage is preserved. The Reduce test duplication guide walks through the full workflow.
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() 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.
What's the difference between reducing noise and reducing test duplication in UI Coverage?
Reducing 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 in Cypress Cloud. Reducing 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
What does Cypress UI Coverage count as an interactive element?
UI Coverage follows the WHATWG definition of interactive content, plus a few Cypress-specific rules. In short, an element counts when it is natively interactive (like <a>, ``, 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 for the full rules.
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 with a click handler isn't recognized as interactive. The best fix is to give the control real semantics, such as using a or adding an appropriate role, which also improves accessibility. When that isn't possible, add data-cy-ui-interactive="include" to the element so UI Coverage tracks it.
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" 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 rule with include: false. Excluded elements are removed from both the report and the score.
Views and URLs
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 pattern to group them yourself. See how views are created for the full set of automatic rules.
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 pattern with groupBy on that parameter to split it into separate views.
How do I create a separate UI Coverage view for each value of a URL parameter?
In Cypress UI Coverage, write a 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.
How do I exclude URLs from UI Coverage?
In Cypress Cloud, add a 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 guide walks through common cases.
In Cypress UI Coverage, what's the difference between viewFilters and views?
They do opposite things. viewFilters removes URLs from your report and score, so excluded pages and the links pointing to them stop counting. 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?.
How do I exclude a third-party login or OAuth page from UI Coverage?
Add a 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.
Can I exclude a URL from UI Coverage without affecting Cypress Accessibility?
Yes. A 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.
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: truerule 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 matchwww.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 for details.
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 for a complete example.
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 in the report, where pages that are linked to but never visited appear. Also confirm that a viewFilters rule isn't excluding the page unintentionally.
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 exists for that page. Untested links count against your score unless you exclude their destination with viewFilters. See Untested Links.
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" to the anchor.
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. See Which hrefs count as links.
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
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 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. Automatic grouping needs at least two similar elements; a control that appears once stays on its own. See Element Grouping for the full set of rules.
How does grouping affect my UI Coverage score?
A group 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.
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 rule in your Cypress Cloud configuration.
Which UI Coverage grouping mechanism wins when more than one could apply?
The data-cy-ui-group markup attribute takes priority over everything, then elementGroups configuration rules in Cypress Cloud, and finally the automatic grouping rules apply to whatever no attribute or rule claimed. Elements removed by elementFilters are never grouped at all.
What happens if two UI Coverage elementGroups rules match the same element?
In Cypress UI Coverage, the first matching rule in your 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.
Can I group UI Coverage elements in my application code instead of Cypress Cloud configuration?
Yes. Add the data-cy-ui-group attribute 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 configuration rules.
Can I group or filter UI Coverage elements inside iframes or shadow DOM?
Yes. In Cypress UI Coverage, the elementGroups, elementFilters, elements, and 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.
Why isn't my element group showing up in the UI Coverage report?
The most common causes in Cypress UI Coverage are:
- An earlier
elementGroupsrule matches the same elements, and the first matching rule wins. - The elements are excluded by
elementFilters, so they're never considered for grouping. - The elements declare a group in markup with the
data-cy-ui-groupattribute, 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.
How do I exclude elements from UI Coverage?
In Cypress Cloud, add an 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 guide walks through common cases.
How do I exclude a third-party widget like a chat launcher or cookie banner from UI Coverage?
In Cypress Cloud, add an 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. See Ignore elements for the full walkthrough.
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 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 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.
Do excluded elements count toward my UI Coverage score?
No. In Cypress UI Coverage, an element excluded by 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 or elements rules.
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
footermatches only the<footer>element. Use a descendant selector likefooter *to exclude everything inside a container. - An earlier
elementFiltersrule already matched the element, and the first matching rule wins. Aninclude: truerule above your exclude rule protects the elements it matches. - The rule has a
documentScopethat 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.
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.
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, for example auto-generated IDs or dynamic class names. Use attributeFilters to ignore the dynamic attributes, or elements to define the element's identity explicitly. See troubleshooting for more scenarios.
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, 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 for the full priority list and how identification works across snapshots.
How does UI Coverage identify an element that has no test attribute or id?
When an element has none of the identifying attributes, 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.
How do I make UI Coverage use my own attribute to identify elements?
Add the attribute name to 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.
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 instead.
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 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.
Why isn't my UI Coverage elements rule applying?
In Cypress UI Coverage, an 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
documentScopeor a more specific selector, or useelementGroupsif 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, so it's never considered. - A later
elementsrule 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.
How do I stop dynamic IDs or class names from splitting one UI Coverage element into many?
Add an 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 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.
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 rule only when your application produces unstable attributes these built-in filters don't already cover.
In UI Coverage, what's the difference between attributeFilters and significantAttributes?
They pull in opposite directions. attributeFilters removes attributes from consideration so Cypress won't identify elements by them, while 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.
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
^(...)$), sovalue: "user"matches only the exact stringuser. Use wildcards for partial matches, such asvalue: "user-.*". - An earlier rule matches the same attribute first, and the first matching rule wins. List specific
include: trueexceptions before broadinclude: falserules. - The rule targets a tag name or sibling position. Only attributes and individual
classtokens can be filtered, not an element's tag name ornth-childposition. - The report was processed before you saved the configuration. Regenerate the run to apply the current configuration.
Interaction commands
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 or allowedInteractionCommands. See 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.
How do I make UI Coverage count cypress-real-events commands like realClick and realType?
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, nested under the uiCoverage key. Once listed, the elements they target are marked as tested.
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 (or allowedInteractionCommands), matched case-sensitively and written exactly as you registered it. Second, the command must log a snapshot that references the subject element, so UI Coverage knows which element to credit. In practice, register the command with prevSubject, call 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.
In UI Coverage, what's the difference between additionalInteractionCommands and allowedInteractionCommands?
In Cypress UI Coverage, additionalInteractionCommands extends the set of commands recognized as interactions everywhere, so a custom or plugin command counts as coverage on any element. 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.
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 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.
Can I count assertions as UI Coverage?
Yes. In Cypress UI Coverage, assertions don't count by default, but an 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.
In UI Coverage, do commands in allowedInteractionCommands also need to be in additionalInteractionCommands?
No. In Cypress UI Coverage, listing a command in an allowedInteractionCommands rule automatically registers it as a recognized interaction, so a custom or plugin command works without also appearing in additionalInteractionCommands. As with any custom command, it only produces coverage if it logs a snapshot that references the subject element.
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 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
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 for what each option does.
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.
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.
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 instead. The editor reports the offending property so you can correct it before saving.
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.
Does my configuration apply to Cypress Accessibility too?
Root-level properties like viewFilters, elementFilters, and 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.
Can I use different UI Coverage configuration for different runs?
Yes. In Cypress UI Coverage, the profiles property applies configuration overrides based on run tags, so a smoke-test run and a full regression run can each use their own settings.
Profiles
How do I apply different UI Coverage settings to different runs?
In your project's App Quality configuration in Cypress Cloud, add a profiles array, give each profile a name, and record the run with a matching --tag. 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.
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, 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.
If a run has multiple tags that match profiles, which UI Coverage profile is used?
Cypress Cloud uses the first profile in the 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.
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, soaq-config-regressionmatches only the tagaq-config-regression, notAQ-Config-Regressionoraq-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.
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 that exclude every view) so Cypress Cloud produces an empty or tightly scoped report for the run instead. See Why use profiles?.
Results API and CI
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 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 and 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.
How do I fail a CI build or block a pull request when Cypress UI Coverage drops?
Use the 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 for a complete example.
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.
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 --recordstep. 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--tagand pass the matching tag togetUICoverageResults. - 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 for how each provider is matched.
Why does the Cypress UI Coverage Results API say no report was found for my run?
UI Coverage reports are generated from 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.
How do I get Cypress UI Coverage results when I record multiple runs in one CI build?
Record each run with a distinct --tag 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.
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 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 applied you match the run's tags against profile names yourself. See Assert the configuration.
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.
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 untestedElementsCount to a small JSON file committed to your repository, then in CI use the Cypress 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 guide has the complete script.
Why compare untested-element counts instead of the UI Coverage score when gating pull requests?
The 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?.
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.
Troubleshooting
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. 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. Finally, one control split into many by an unstable attribute adds duplicate untested elements. See the coverage score looks wrong for the fixes.
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, so custom commands and plugin commands like cypress-real-events' realClick don't count until you add them with additionalInteractionCommands or allowedInteractionCommands. A custom command also has to log a snapshot 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.
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 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 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 for the full checklist.
How do I debug a UI Coverage report that looks wrong?
Start by regenerating the run in Cypress Cloud so it reflects your current configuration, then match your symptom to a cause on the 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
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.
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, 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.
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 third-party widgets you don't own, promote a stable attribute so elements have clean, readable names, and group 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.
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 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.
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.
See also
- Troubleshooting UI Coverage maps common report problems to their causes and fixes.
- Monitor changes sets up a repeatable workflow to track coverage trends and catch regressions before they merge.
- Work with AI agents uses the Cypress Cloud MCP to read reports, summarize gaps, and draft tests.
- Results API fetches a run's UI Coverage results in CI so you can enforce coverage standards.
- Configuration overview lists every configuration option and what each one is for.
- Profiles apply different configuration to runs based on run tags.
- Views explains how URLs become views and how automatic grouping works.
- Element Identification covers how elements are identified and grouped across snapshots.
- 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' sidebar_label: Results API sidebar_position: 100
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.
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/checkoutthan 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 for a worked script behind each of these.
Because reports are processed server-side from
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:
- 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 for
details. - 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. - 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 aftercypress 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:
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 for the full list.
Supported CI providers at a glance
The Results API supports the following CI providers:
- Azure
- CircleCI
- GitHub Actions
- GitLab
- Jenkins
- AWS CodeBuild
- Drone
- Bitbucket
- Buildkite
For other CI providers, contact Cypress Support at [email protected] to request
support.
Installation
Install the @cypress/extract-cloud-results module in your install step in CI.
:::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:
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 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:
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.
{
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:
{
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 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 thename 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.
:::
{
"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 descriptiveError 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.
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:
- Update your install step to install the
@cypress/extract-cloud-resultsmodule. - Pass any necessary arguments to
getUICoverageResults. - Add a step, after your Cypress run, that executes your verification script.
Example workflow updates
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.jsimage: 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.jspipeline {
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'
+ }
+ }
}
}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)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-testsphases:
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.jskind: 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.jsimage: 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.jssteps:
- 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.jsRecording 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 matchingrunTags argument for each run. This is how each run is uniquely identified so
the correct results are returned. Tags can also activate
Profiles that apply different
configuration to different runs.
For example, imagine that within a single CI build you callcypress 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:
getUICoverageResults({ runTags: ['staging'] })
getUICoverageResults({ runTags: ['production'] })Examples
Each example below assumes you have written a script that callsgetUICoverageResults 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:
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:
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:
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:
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:
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 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.
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:
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
guide.
Required CI environment variables
See also
- Block pull requests and set policies: set a coverage policy and fail a pull request when it isn't met.
- Monitor changes: track coverage trends and catch regressions over time.
- Results API FAQ: quick answers to common Results API and CI questions.
- Profiles: apply different configuration to different runs using run tags.
Ui Coverage Troubleshooting (`docs/ui-coverage/troubleshooting.mdx`)
title: 'Troubleshooting: UI Coverage' sidebar_label: Troubleshooting sidebar_position: 150
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 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.
:::
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 by building an [identity](/ui-coverage/core-concepts/element-identificatio