# Dynamic IDs are breaking my tests every time I refresh

**URL:** <https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034>\
**Category:** Web Testing\
**Created:** [April 14, 2026, 3:42am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034 "2026-04-14T03:42:01Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![ali.khan1](https://avatars.discourse-cdn.com/v4/letter/a/b3f665/32.png) [@ali.khan1](https://forum.katalon.com/u/ali.khan1)\
**Post date:** [April 14, 2026, 3:42am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/1 "2026-04-14T03:42:01Z")

</div>

Hi everyone, I’m really new to Katalon Studio and I’m hitting a wall with the login page of my web app. I used the **Record Web** tool to create a simple login script, and it worked perfectly the first time. But when I try to run it again, or if I just refresh the page, the test fails with a `Step Failed: Object 'Object Repository/Login_Button' not found` error.

I looked at the HTML, and it seems like the ID for the login button is something like `btn-5821` one minute, and then `btn-9374` the next. Since Katalon recorded it using that specific ID, it can’t find it once the numbers change. I tried manually editing the object in the Object Repository to use a different attribute, but I’m not sure which one is “safe” to use or how to make the selector more flexible. It feels like I’m chasing a moving target—how do I get Katalon to recognize the button even when the ID keeps changing?

---

<div class="post-metadata">

**Author:** ![Elly\_Tran](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/elly_tran/32/21874_2.png) [@Elly\_Tran](https://forum.katalon.com/u/Elly_Tran)\
**Post date:** [April 14, 2026, 3:42am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/2 "2026-04-14T03:42:01Z")

</div>

Hi there, and thanks for posting in the Katalon community! 🤗

To help you faster, please review our guide on Record Web Utility here: [Record Web utility in Katalon Studio | Katalon Docs](https://docs.katalon.com/katalon-studio/record-and-spy/webui-record-and-spy-utilities/record-web-utility-in-katalon-studio). Double-checking the steps and configurations might resolve the issue.

If the doc doesn’t help, feel free to provide more details, and a community member will assist you soon.

Thanks for being a part of our community!  
Best,  
Elly Tran

---

<div class="post-metadata">

**Author:** ![Monty\_Bagati](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/monty_bagati/32/33047_2.png) [@Monty\_Bagati](https://forum.katalon.com/u/Monty_Bagati)\
**Post date:** [April 14, 2026, 3:50am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/3 "2026-04-14T03:50:24Z")

</div>

show us the html code of that button pls and we will help you , it seems you are not using the correct locator

---

<div class="post-metadata">

**Author:** ![qurzunta.kaab](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/qurzunta.kaab/32/31470_2.png) [@qurzunta.kaab](https://forum.katalon.com/u/qurzunta.kaab)\
**Post date:** [April 14, 2026, 10:26am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/4 "2026-04-14T10:26:43Z")

</div>

What you are encountering is a classic “Dynamic Attribute” issue. Developers often use frameworks (like React, Angular, or Vue) that auto-generate IDs during the build or render process. Relying on these IDs is a recipe for brittle tests.

To build a **robust and scalable framework** , we shift away from “Recorded” absolute attributes and move toward **Relative XPaths** or **Parametrized Selectors**. Instead of looking for a random number, we look for stable “anchors” like text labels, class names, or hierarchical relationships.

### The Solution: XPath Optimization

Instead of using an ID that looks like `//button[@id='btn-1234']`, we use a partial match or a text-based match. This ensures that as long as the button says “Login,” the test will pass.

1. **Open your Object Repository** and select the failing object.

2. **Switch the Detection Method** to `XPath`.

3. **Update the XPath** to one of the following stable patterns:

### Custom Keyword: The “Smart Finder”

To make your life easier, you can create a Custom Keyword that finds an element by its text regardless of its changing ID. This makes your scripts much more readable and maintainable.

Groovy

```auto
package com.helpers

import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

public class SmartElementFinder {

    /**
     * Finds a button by its visible text, ignoring dynamic IDs
     */
    @Keyword
    def clickButtonByText(String buttonText) {
        TestObject dynamicObject = new TestObject("DynamicButton")
        // Create an XPath that looks for a button containing the specific text
        String xpath = "//button[normalize-space()='" + buttonText + "']"
        
        dynamicObject.addProperty("xpath", ConditionType.EQUALS, xpath)
        
        WebUI.waitForElementVisible(dynamicObject, 5)
        WebUI.click(dynamicObject)
    }
}

```

### Implementation Strategy:

- **Avoid the Recorder for IDs:** When recording, if you see an ID with long strings of numbers, immediately flag it.

- **Use Data Attributes:** If you have influence over the development team, ask them to add `data-testid="login-button"`. These attributes are ignored by CSS/JS and are dedicated solely to making your automation stable.

- **The “Normalize-Space” Trick:** Use `normalize-space()` in your XPaths to ignore weird gaps or tabs that developers sometimes leave around the button text.

By implementing these selector strategies, your test suite will remain stable across different environments and UI refreshes.

---

<div class="post-metadata">

**Author:** ![kazurayam](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/kazurayam/32/333_2.png) [@kazurayam](https://forum.katalon.com/u/kazurayam)\
**Post date:** [April 14, 2026, 10:46am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/5 "2026-04-14T10:46:15Z")

</div>

> [@ali.khan1](#):
>
> how do I get Katalon to recognize the button even when the ID keeps changing?

Solution for the difficulty caused by dynamic id entirely depends on how the target HTML is written. If you want the guys in this forum to answer to your question, you should disclose the HTML source of your target.

To view the DOM nodes, use [Chrome DevTools](https://developer.chrome.com/docs/devtools/dom).

---

<div class="post-metadata">

**Author:** ![grylion54](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/grylion54/32/16265_2.png) [@grylion54](https://forum.katalon.com/u/grylion54)\
**Post date:** [April 14, 2026, 7:38pm UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/6 "2026-04-14T19:38:30Z")

</div>

if you go to **Project** \> **Settings** \> **Test Design** \> **Web UI,** you can change the priority of your pathway locators. Jump over to the Attribute tab and remove the check for the `<id>` attribute; It was the `<id>` attribute that was the main dynamic reference within our software. Try this for a bit.  
For me, I eventually put the checkmark back and then modified the pathway using “contains” and “starts-with”, like @qurzunta.kaab states.

```auto
//a[contains(@id, 'mainmenu') and contains(@id,'CashAndBankManagement') and contains(@id,'CashFlowForecasting')]

//input[starts-with(@id,'DirPartyQuickCreateForm_') and contains(@id, 'DynamicDetail_CustGroup_input')]/following-sibling::div/div[@class='lookupButton']

//input[contains(@id,'ledgercalendars_') and contains(@id, '_YearGroup_StartDate_input')]

```

---

<div class="post-metadata">

**Author:** ![qurzunta.kaab](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/qurzunta.kaab/32/31470_2.png) [@qurzunta.kaab](https://forum.katalon.com/u/qurzunta.kaab)\
**Post date:** [April 14, 2026, 10:57pm UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/7 "2026-04-14T22:57:56Z")

</div>

Thanks, That a nice hack!

---

<div class="post-metadata">

**Author:** ![dineshh](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/dineshh/32/24488_2.png) [@dineshh](https://forum.katalon.com/u/dineshh)\
**Post date:** [April 15, 2026, 6:46am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/8 "2026-04-15T06:46:16Z")

</div>

**Dynamic IDs (btn-5821 → btn-9374)** kill recorded tests— **switch to stable XPath** ignoring numbers.

## Robust Selectors

**Object Repo \> Login\_Button** → Edit XPath:

```auto
1. Text: //button[normalize-space(text())='Login'] // Exact match
2. Contains ID: //button[contains(@id, 'btn-')] // Partial
3. Class+Text: //button[contains(@class, 'login') and text()='Login']

```

**Custom Smart Click** :

```auto
@Keyword
void clickByText(String text) {
    TestObject btn = new TestObject('dynamic')
    btn.addProperty('xpath', ConditionType.EQUALS, "//button[.='${text}']")
    WebUI.click(btn)
}

```

`CustomKeywords.clickByText('Login')`—page refresh proof!

Ask devs for `data-testid="login-btn"`—automation gold.

---

<div class="post-metadata">

**Author:** ![viet.nguyen](https://dub1.discourse-cdn.com/katalon/user_avatar/forum.katalon.com/viet.nguyen/32/21142_2.png) [@viet.nguyen](https://forum.katalon.com/u/viet.nguyen)\
**Post date:** [April 15, 2026, 7:19am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/9 "2026-04-15T07:19:10Z")

</div>

If you want to learn about working with test objects using Studio, we got a [learning path](https://academy.katalon.com/learning-path/working-with-web-test-objects-using-katalon-studio/) for that.

---

<div class="post-metadata">

**Author:** ![ali.khan1](https://avatars.discourse-cdn.com/v4/letter/a/b3f665/32.png) [@ali.khan1](https://forum.katalon.com/u/ali.khan1)\
**Post date:** [April 17, 2026, 2:51am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/10 "2026-04-17T02:51:59Z")

</div>

thanks i am following these

---

<div class="post-metadata">

**Author:** ![ali.khan1](https://avatars.discourse-cdn.com/v4/letter/a/b3f665/32.png) [@ali.khan1](https://forum.katalon.com/u/ali.khan1)\
**Post date:** [April 17, 2026, 2:52am UTC](https://forum.katalon.com/t/dynamic-ids-are-breaking-my-tests-every-time-i-refresh/190034/11 "2026-04-17T02:52:09Z")

</div>

this fixed on one part i also need help with some other webcomponents can you answer my query with some code that solve it
