How UI Coverage measures interactivity
Your UI Coverage score is built from the interactive parts of your app: the buttons, inputs, links, and controls a user can actually touch. To read your report with confidence, it helps to know the three rules that shape it:
- An element is counted when it is interactive, which forms the denominator of your score.
- An interactive element is marked as tested when a recognized Cypress command targets it, which forms the numerator.
- A link is flagged as untested when its destination is never visited during your run.
Put simply, your score is the share of interactive elements your tests exercise: tested ÷ total, where grouped elements count once. See how the score is calculated for the details.
This page covers all three, along with the configuration and markup overrides you can use to make each one match your application. All three are computed from Test Replay data, so they work automatically with no setup or instrumentation. Reach for the overrides only when the defaults don't fit.
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.
How UI Coverage turns a recorded run into a coverage score.
Interactive Elements
UI Coverage follows the WHATWG definition of interactive content, extended with a few Cypress-specific rules. An element is counted as interactive when it falls into any of these categories:
- Natively interactive elements: elements the browser already treats as interactive, such as
<a>links,<button>, form controls like<input>and<select>, and any element that iscontenteditable. - Elements with an interactive ARIA role: an explicit
rolesuch asbutton,checkbox,tab, ormenuitem, or anaria-haspopupvalue that opens a menu or dialog. - Tab-navigable elements: any element made keyboard-focusable with a
tabindexof0or greater.
Contact links are the one deliberate exception: anchors whose href uses tel:, mailto:, or sms: are not treated as interactive. See Untested Links for how the rest of an anchor's href is handled.
Because detection is based on semantics rather than event handlers, a real <button> is recognized automatically, while a <div> wired up with a click handler is not, until you give it interactive semantics.

UI Coverage finds each interactive element in a snapshot and tracks whether your tests exercise it.
Overriding interactive elements with data-cy-ui-interactive
When the automatic rules don't match your app, the data-cy-ui-interactive attribute lets you override them directly in your markup. It accepts four values, matched case-insensitively:
| Value | Effect |
|---|---|
include | Treats the element as interactive even when it wouldn't be otherwise. |
exclude | Removes the element from UI Coverage, even when it's normally interactive. |
exclude-all | Removes the element and every element nested inside it. |
reset | Re-enables tracking for a subtree nested inside an element marked exclude-all. |
Include a custom control the browser doesn't recognize:
<!-- A custom drag handle built from a div -->
<div role="presentation" data-cy-ui-interactive="include">Reorder</div>
Exclude a whole section while keeping one control inside it tracked:
<section data-cy-ui-interactive="exclude-all">
<!-- Nothing in this experimental panel is tracked... -->
<button>Beta action</button>
<div data-cy-ui-interactive="reset">
<!-- ...except controls inside here -->
<button>Save feedback</button>
</div>
</section>
Excluding an element removes it from UI Coverage entirely: it no longer counts as an interactive element, and if it's a link, it also stops appearing as an untested link, so neither affects your score.
In most cases we recommend not using include, and instead updating the HTML to be something the browser already treats as interactive, such as a real <button> in place of a clickable <div>. That produces better overall behavior, including for accessibility, since the same semantics that let assistive technology operate a control are what UI Coverage reads. data-cy-ui-interactive is a fallback for situations where that isn't possible.
To exclude elements without editing your application's markup, elementFilters does the same job from Cypress Cloud configuration. Prefer it when the team that manages configuration isn't the team that owns the markup:
{
"elementFilters": [
{
"selector": ".intercom-launcher, .intercom-launcher *",
"include": false,
"comment": "Third-party chat widget, not owned by our tests"
}
]
}
How elements get marked tested
An interactive element is marked as tested when a recognized Cypress command targets it. UI Coverage recognizes this built-in set of commands:
blurcheckclearclickdblclickfocusrightclickscrollIntoViewscrollToselectselectFilesubmittriggertypeuncheck
Using at least one of them on every interactive element is what drives your coverage score, so a test flow naturally marks the elements it exercises as tested:
// Each command marks its target element as tested
cy.get('[data-cy="signup-plan-pro"]').check()
cy.get('[data-cy="signup-submit"]').click()

An element moves to the Tested list once a recognized command interacts with it, with the interaction count shown per element.
A command only counts when it logs a snapshot that highlights the element it acts on, which is how UI Coverage knows which element to credit. Built-in commands do this automatically; a custom command must do it explicitly (see Requirements for a custom command).
Customizing interaction commands
Two configuration options let you change which commands count:
additionalInteractionCommandsextends the built-in set everywhere, so custom commands or ones from third-party libraries (such ascypress-real-events'realClick) count as coverage on any element.allowedInteractionCommandsworks per element: for elements matching a selector, only the commands you list count. This lets you both require a meaningful interaction (a chart that must be hovered, not just clicked) and credit commands the defaults ignore (anasserton a read-only badge).
For example, to require a hover rather than a plain click on a chart before it counts as tested:
{
"uiCoverage": {
"allowedInteractionCommands": [
{
"selector": "[data-cy='revenue-chart']",
"commands": ["trigger"],
"comment": "Only a hover (dispatched via trigger) proves the tooltip works"
}
]
}
}
See Which option do I need? for a side-by-side comparison.
Untested Links
UI Coverage tracks links (<a> elements) whose destination URLs are never visited during testing. A link to a page no test navigates to is a coverage gap even when no view exists for that page, so untested links surface the flows your suite is missing, not just the elements it skipped.

An untested link highlighted in the report: its destination was never visited during the run.
Which hrefs count as links
The href value determines how UI Coverage treats each anchor. At a glance:
href example | Interactive element? | Can be an untested link? |
|---|---|---|
/settings, #/settings, https://external.com, blob: | Yes | Yes |
#pricing (page fragment) | Yes | No |
# or javascript: | Yes | No |
Empty or missing href | Yes | No |
tel:, mailto:, sms: | No | No |
The three cases in detail:
1. Counted as untested links and interactive elements
An href that resolves to a URL is treated as a link to a destination, and the anchor is also an ordinary interactive element. This covers:
- URLs: relative paths like
/settings, hash routes like#/settings, and absolute URLs, including links to entirely external websites. - Other schemes: any other scheme, such as
ftp:,file:,data:,blob:, or a custom app scheme, treated the same as anhttp(s)URL.
The anchor counts as tested once a test either interacts with it or visits its destination. If the destination is never visited, the link appears as an untested link and counts against your score, unless a viewFilters rule excludes the destination URL.
2. Counted only as interactive elements
These anchors are ordinary interactive elements that must be interacted with to count as tested. They point to no separate destination, so they never appear as untested links:
- Document fragments: an
hrefpointing to a fragment on the current page, such as#pricing. #andjavascript:values: anchors withhref="#"or ajavascript:value.- Empty or missing
href: an anchor with no usablehrefvalue.
3. Not counted in UI Coverage
tel:,mailto:, andsms:values: contact links are not considered interactive elements. They don't appear in reports and don't count toward your coverage score. To track one anyway, adddata-cy-ui-interactive="include"to the anchor.
Exclude link destinations from your score
To keep destinations you'll never test, such as external sites, your marketing pages, or a status page, from counting against your score, exclude them by URL:
{
"viewFilters": [
{
"pattern": "https://status.example.com/*",
"include": false,
"comment": "External status page, linked from the footer but not owned by our team"
}
]
}
Excluding a destination with viewFilters also removes the links that point to it, so they stop appearing as untested links. See Ignore views and links for the full workflow. To exclude a single link from your markup instead, add data-cy-ui-interactive="exclude" to the anchor.
Untested link details
Expanding an untested link in the report reveals where it came from and which destinations it covers, so you can decide whether to test it or exclude it. That detail is organized into two tabs, Referrers and URLs.

Referrers
The Referrers tab lists the views that contain a link to the untested destination, so you can trace it back to the pages that link to it and the flows that lead there.
URLs
The URLs tab groups similar destinations for dynamic routing. For instance, links to /users/1, /users/2, and /users/3 are grouped as /users/*. Only path segments that are numbers or UUID-like IDs are treated as dynamic, so /users/alice and /users/bob stay separate. The grouping shows the scope and variations of a dynamic route, and the pattern it surfaces is the one to use when writing views and viewFilters rules.
See also
- Element Identification: how UI Coverage gives each interactive element a stable identity across snapshots.
additionalInteractionCommands: count custom or plugin commands as interactions everywhere.allowedInteractionCommands: control which commands count for specific elements.elementFilters: remove elements from reports and scores using configuration.viewFilters: exclude views and link destinations from reports.- UI Coverage FAQ: common questions about interactive elements, interaction commands, and links.