Creating flexible XPath expressions with dynamic values in Puppeteer automation

I’m working on a Puppeteer automation project and need help with creating XPath selectors that can handle dynamic content. I have element IDs that follow a specific pattern but contain randomly generated values in the middle part.

Here are some examples of the XPath patterns I’m dealing with:

// Example selectors with dynamic content
const selector1 = "//*[@id='dataTable_mainColumn_{A1B2C3D4-1234-5678-9ABC-DEF012345678}_1']";
const selector2 = "//*[@id='dataTable_mainColumn_{F9E8D7C6-ABCD-EFGH-1234-567890ABCDEF}_1']";

The part between the curly braces {A1B2C3D4-1234-5678-9ABC-DEF012345678} changes every time the page loads, but the prefix dataTable_mainColumn_ and suffix _1 stay constant.

How can I write a flexible XPath expression that will match these elements regardless of what the dynamic ID portion contains? I need a solution that works reliably with Puppeteer’s page evaluation methods.

XPath’s contains() function is perfect for this. It’ll match the constant parts while ignoring that dynamic UUID:

const flexibleSelector = "//*[contains(@id, 'dataTable_mainColumn_') and contains(@id, '_1')]"

This finds elements with both your prefix and suffix patterns. I’ve used this tons of times in production scripts where IDs have timestamps or session tokens. It handles cases where there’s extra characters before or after your pattern.

Want more precision? Combine it with other attributes. Sometimes dynamic content shows up in multiple elements, so adding and @class='your-class' helps narrow it down to exactly what you need. This approach has saved me hours debugging flaky selectors in enterprise apps with generated IDs.

you can also use xpath wildcards with position matching. try //*[@id[substring-after(substring-before(., '_1'), 'dataTable_mainColumn_')]] - this grabs the middle part without worrying about what’s inside. really useful when you’ve got multiple similar elements and need precise positioning.

I’ve hit this same dynamic ID problem in my automation work. Best solution I’ve found is combining XPath’s starts-with() and ends-with() functions:

const dynamicSelector = "//*[starts-with(@id, 'dataTable_mainColumn_') and ends-with(@id, '_1')]";

This matches any element where the ID starts with your prefix and ends with your suffix - doesn’t matter what’s in the middle. Way more reliable than just using contains() since you’re locking down the exact static parts.

Just use it with page.$x() or page.waitForXPath() in Puppeteer. Handles page reloads and dynamic content way better than trying to extract and substitute values. Performance hit is basically nothing and it’s much cleaner than regex solutions.