{
  "doc": {
    "id": "ui-coverage/core-concepts/element-identification",
    "title": "How UI Coverage identifies elements",
    "description": "How Cypress UI Coverage gives each interactive element a stable, unique identity across DOM snapshots, using test attributes like data-cy, an id and name fallback, and DOM structure, so the same control counts once and your coverage score stays accurate.",
    "section": "ui-coverage",
    "source_path": "/llm/markdown/ui-coverage/core-concepts/element-identification.md",
    "version": "29f95bf8bb06f320986f3749f5bf09a35a409eab",
    "updated_at": "2026-09-04T10:49:54.630Z",
    "headings": [
      {
        "id": "ui-coverage/core-concepts/element-identification#element-identification",
        "text": "Element Identification",
        "level": 1
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#snapshots",
        "text": "Snapshots",
        "level": 2
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#how-an-element-is-identified",
        "text": "How an element is identified",
        "level": 2
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#when-an-element-has-no-identifying-attribute",
        "text": "When an element has no identifying attribute",
        "level": 2
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#unstable-attributes-are-filtered-automatically",
        "text": "Unstable attributes are filtered automatically",
        "level": 2
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#elements-in-iframes-and-shadow-dom",
        "text": "Elements in iframes and shadow DOM",
        "level": 2
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#tuning-element-identification",
        "text": "Tuning element identification",
        "level": 2
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#prioritize-your-own-attributes",
        "text": "Prioritize your own attributes",
        "level": 3
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#ignore-an-unstable-attribute",
        "text": "Ignore an unstable attribute",
        "level": 3
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#fix-a-single-elements-identity",
        "text": "Fix a single element's identity",
        "level": 3
      },
      {
        "id": "ui-coverage/core-concepts/element-identification#see-also",
        "text": "See also",
        "level": 2
      }
    ]
  },
  "chunks": [
    {
      "id": "ui-coverage/core-concepts/element-identification#snapshots",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Snapshots",
      "heading_level": 2,
      "content_markdown": "## Snapshots\n\nA snapshot is a capture of your application's DOM at one moment during a test. As your tests run, the same capture protocol that powers [Test Replay](/llm/markdown/cloud/features/test-replay.md) records snapshots automatically as your application changes state, on page loads, interactions, and other DOM updates, with no extra code or configuration.\n\nUI Coverage analyzes the snapshots in a recorded run: it detects the [interactive elements](/llm/markdown/ui-coverage/core-concepts/interactivity.md) in each one and computes an identity for each element using the rules on this page. Elements that produce the same identity in different snapshots count as one element, and [views](/llm/markdown/ui-coverage/core-concepts/views.md) group snapshots by URL. An identity that changes between snapshots, such as one built from an autogenerated `id`, is what splits a single button into many untested elements.\n",
      "section": "ui-coverage",
      "anchors": [
        "snapshots"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 165
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#how-an-element-is-identified",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "How an element is identified",
      "heading_level": 2,
      "content_markdown": "## How an element is identified\n\nFor each interactive element it tracks, UI Coverage looks for an **identifying attribute**. It checks a single prioritized list and uses the first attribute that is present with a usable value:\n\n1.  The markup attribute `data-cy-ui-id`, which outranks every other option. `data-cy-ui-id` replaces the element's identity outright: its value becomes the identity, with no tag or selector appended.\n2.  Your [`significantAttributes`](/llm/markdown/ui-coverage/configuration/significantattributes.md), in the order you list them\n3.  The default test attributes, in order: `data-cy`, `data-test`, `data-testid`, `data-test-id`, `data-qa`, and `row-id` (data grids)\n4.  `id`, then `name`, as fallbacks\n\nThe first attribute in this list that the element has, with a value that isn't excluded by an [`attributeFilters`](/llm/markdown/ui-coverage/configuration/attributefilters.md) rule, becomes the element's **identifying attribute**. That single attribute-value pair drives how the element is identified across snapshots and named in reports. It also drives [grouping](/llm/markdown/ui-coverage/core-concepts/element-grouping.md), with one exception: the `id` and `name` fallbacks identify an element but never group it.\n\nFor example, both attributes below can identify this button, but `data-cy` outranks `id`, so it wins:\n\n```\n<button data-cy=\"place-order\" id=\"btn-8f3a\">Place order</button>\n```\n\nThe button is identified as `[data-cy=\"place-order\"]`, and the generated `id` is never used. Using one of these attributes consistently across your application is the most effective way to keep identification accurate.\n\nIn reports, elements appear under their identifying selector, and the **Snapshots** column shows how many snapshots each one spans while still counting as a single element. An element without a usable attribute falls back to a structural selector.\n",
      "section": "ui-coverage",
      "anchors": [
        "how-an-element-is-identified"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 328
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#when-an-element-has-no-identifying-attribute",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "When an element has no identifying attribute",
      "heading_level": 2,
      "content_markdown": "## When an element has no identifying attribute\n\nNot every interactive element carries a useful attribute. When none of the attributes above apply, UI Coverage falls back to identifying the element by its structure and position in the DOM, such as its tag and where it sits among sibling elements. Its visible text content is never used, so a button labeled \"Save\" that briefly becomes \"Saving…\" during a request stays one element.\n\nA structural identity like this is less stable than an attribute you control: a change to the surrounding markup can shift it, so the same element can appear as new and untested when you [compare two runs in Branch Review](/llm/markdown/ui-coverage/guides/compare-reports.md). Adding a stable test attribute is the reliable fix.\n\n**Links are a special case.** An `<a>` element is identified by its destination `href`. Links whose URLs follow the same pattern are resolved into [views](/llm/markdown/ui-coverage/core-concepts/views.md) and grouped by that pattern, so a list of 50 product links doesn't become 50 separate untested elements.\n",
      "section": "ui-coverage",
      "anchors": [
        "when-an-element-has-no-identifying-attribute"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 219
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#unstable-attributes-are-filtered-automatically",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Unstable attributes are filtered automatically",
      "heading_level": 2,
      "content_markdown": "## Unstable attributes are filtered automatically\n\nUI Coverage already ignores the most common sources of unstable identity, such as auto-generated IDs and framework-generated class names, so in most applications you don't need to configure anything.\n\nIf your application produces an unstable value that these built-in rules don't cover, add an [`attributeFilters`](/llm/markdown/ui-coverage/configuration/attributefilters.md) rule to ignore it. If a single specific element needs a fixed identity, use an [`elements`](/llm/markdown/ui-coverage/configuration/elements.md) rule.\n",
      "section": "ui-coverage",
      "anchors": [
        "unstable-attributes-are-filtered-automatically"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 91
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#elements-in-iframes-and-shadow-dom",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Elements in iframes and shadow DOM",
      "heading_level": 2,
      "content_markdown": "## Elements in iframes and shadow DOM\n\nUI Coverage identifies interactive elements inside iframes and shadow DOM as well, qualifying each element's identity with its host chain. A `#submit` button inside a checkout iframe is therefore a different element from a `#submit` in the main document, and both are tracked. To target an element inside a specific iframe or shadow root with a configuration rule, use the `documentScope` property on [`elements`](/llm/markdown/ui-coverage/configuration/elements.md#Options), [`elementFilters`](/llm/markdown/ui-coverage/configuration/elementfilters.md), or [`elementGroups`](/llm/markdown/ui-coverage/configuration/elementgroups.md) rules.\n",
      "section": "ui-coverage",
      "anchors": [
        "elements-in-iframes-and-shadow-dom"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 100
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#tuning-element-identification",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Tuning element identification",
      "heading_level": 2,
      "content_markdown": "## Tuning element identification\n\nWhen the defaults don't match your application, three configuration options adjust how elements are identified. Set them in the **App Quality** tab of your project settings in Cypress Cloud, then [regenerate a recent run](/llm/markdown/ui-coverage/configuration/overview.md#Setting-configuration) to preview the effect without re-running your tests.\n\n| Your goal | Use |\n| --- | --- |\n| Prefer your own attribute (like `data-component`) as identity | [`significantAttributes`](/llm/markdown/ui-coverage/configuration/significantattributes.md) |\n| Stop a dynamic or generated attribute from identifying elements | [`attributeFilters`](/llm/markdown/ui-coverage/configuration/attributefilters.md) |\n| Give one specific element a stable identity or a readable name | [`elements`](/llm/markdown/ui-coverage/configuration/elements.md) |\n\nSee [Which option do I need?](/llm/markdown/ui-coverage/configuration/overview.md#Which-option-do-I-need) in the configuration overview for how these fit alongside grouping and filtering.\n\n### Prioritize your own attributes\n\nIf your components already render a descriptive attribute, add it to `significantAttributes` so UI Coverage prefers it over the defaults. Elements are then identified and named by the vocabulary your team recognizes, showing `[data-component=\"CheckoutButton\"]` instead of a generated selector.\n\nApp Quality Config\n\n```\n{\n  \"uiCoverage\": {\n    \"significantAttributes\": [\"data-component\"]\n  }\n}\n```\n\nRefer to the [`significantAttributes`](/llm/markdown/ui-coverage/configuration/significantattributes.md) guide for the full priority rules and examples.\n\n### Ignore an unstable attribute\n\nExclude a dynamically generated attribute value so it can't split one element into many. For example, to stop a React-generated `id` like `:r17:` from being used as identity:\n\nApp Quality Config\n\n```\n{\n  \"uiCoverage\": {\n    \"attributeFilters\": [\n      {\n        \"attribute\": \"id\",\n        \"value\": \":r.*:\",\n        \"include\": false\n      }\n    ]\n  }\n}\n```\n\nOnce the unstable value is ignored, UI Coverage identifies the element by the next stable attribute it has. Learn more in the [`attributeFilters`](/llm/markdown/ui-coverage/configuration/attributefilters.md) guide.\n\n### Fix a single element's identity\n\nWhen one element's attributes change between snapshots, an [`elements`](/llm/markdown/ui-coverage/configuration/elements.md) rule pins it to a selector you choose and gives it a readable name. The matched element is identified by the rule's selector alone, so it stays one element across snapshots even as its `id` regenerates.\n\nApp Quality Config\n\n```\n{\n  \"uiCoverage\": {\n    \"elements\": [\n      {\n        \"selector\": \"#checkout-form [id^='country-']\",\n        \"name\": \"Country Dropdown\"\n      }\n    ]\n  }\n}\n```\n\nAn `elements` rule applies only when its selector matches exactly one interactive element in a snapshot. Refer to the [`elements`](/llm/markdown/ui-coverage/configuration/elements.md) guide for how rules are matched and scoped.\n",
      "section": "ui-coverage",
      "anchors": [
        "tuning-element-identification"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 481
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#prioritize-your-own-attributes",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Prioritize your own attributes",
      "heading_level": 3,
      "content_markdown": "### Prioritize your own attributes\n\nIf your components already render a descriptive attribute, add it to `significantAttributes` so UI Coverage prefers it over the defaults. Elements are then identified and named by the vocabulary your team recognizes, showing `[data-component=\"CheckoutButton\"]` instead of a generated selector.\n\nApp Quality Config\n\n```\n{\n  \"uiCoverage\": {\n    \"significantAttributes\": [\"data-component\"]\n  }\n}\n```\n\nRefer to the [`significantAttributes`](/llm/markdown/ui-coverage/configuration/significantattributes.md) guide for the full priority rules and examples.\n",
      "section": "ui-coverage",
      "anchors": [
        "prioritize-your-own-attributes"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 91
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#ignore-an-unstable-attribute",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Ignore an unstable attribute",
      "heading_level": 3,
      "content_markdown": "### Ignore an unstable attribute\n\nExclude a dynamically generated attribute value so it can't split one element into many. For example, to stop a React-generated `id` like `:r17:` from being used as identity:\n\nApp Quality Config\n\n```\n{\n  \"uiCoverage\": {\n    \"attributeFilters\": [\n      {\n        \"attribute\": \"id\",\n        \"value\": \":r.*:\",\n        \"include\": false\n      }\n    ]\n  }\n}\n```\n\nOnce the unstable value is ignored, UI Coverage identifies the element by the next stable attribute it has. Learn more in the [`attributeFilters`](/llm/markdown/ui-coverage/configuration/attributefilters.md) guide.\n",
      "section": "ui-coverage",
      "anchors": [
        "ignore-an-unstable-attribute"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 104
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#fix-a-single-elements-identity",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "Fix a single element's identity",
      "heading_level": 3,
      "content_markdown": "### Fix a single element's identity\n\nWhen one element's attributes change between snapshots, an [`elements`](/llm/markdown/ui-coverage/configuration/elements.md) rule pins it to a selector you choose and gives it a readable name. The matched element is identified by the rule's selector alone, so it stays one element across snapshots even as its `id` regenerates.\n\nApp Quality Config\n\n```\n{\n  \"uiCoverage\": {\n    \"elements\": [\n      {\n        \"selector\": \"#checkout-form [id^='country-']\",\n        \"name\": \"Country Dropdown\"\n      }\n    ]\n  }\n}\n```\n\nAn `elements` rule applies only when its selector matches exactly one interactive element in a snapshot. Refer to the [`elements`](/llm/markdown/ui-coverage/configuration/elements.md) guide for how rules are matched and scoped.\n",
      "section": "ui-coverage",
      "anchors": [
        "fix-a-single-elements-identity"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 133
    },
    {
      "id": "ui-coverage/core-concepts/element-identification#see-also",
      "doc_id": "ui-coverage/core-concepts/element-identification",
      "heading": "See also",
      "heading_level": 2,
      "content_markdown": "## See also\n\n*   [Element Grouping](/llm/markdown/ui-coverage/core-concepts/element-grouping.md): how related elements are combined so interacting with one counts for the set.\n*   [Interactivity](/llm/markdown/ui-coverage/core-concepts/interactivity.md): which elements UI Coverage tracks and which commands mark them tested.\n*   [`significantAttributes`](/llm/markdown/ui-coverage/configuration/significantattributes.md): prioritize your own attributes for identifying and naming elements.\n*   [`attributeFilters`](/llm/markdown/ui-coverage/configuration/attributefilters.md): stop dynamic or generated attribute values from identifying elements.\n*   [`elements`](/llm/markdown/ui-coverage/configuration/elements.md): give a single element a stable identity and a readable name.\n*   [UI Coverage FAQ](/llm/markdown/ui-coverage/faq.md#Element-grouping-and-identification): common questions about element identification.\n",
      "section": "ui-coverage",
      "anchors": [
        "see-also"
      ],
      "path": "/llm/json/chunked/ui-coverage/core-concepts/element-identification.json",
      "token_estimate": 101
    }
  ]
}