Using DOM Matching


In web applications, user-facing elements like input fields represent behind-the-scenes HTML code. For example, in the screenshots below, the field on the left is defined by the <input...> tag visible on the right.

In Rainforest, to select the target element of a test action, you can either (1) take a screenshot of the relevant part of your app’s user interface or (2) enter the relevant XPath or CSS selectors.


DOM matching is currently an experimental feature.

We’re still actively working on the stability and implementation of this feature.

Currently, Chrome on Windows 10 is the only supported browser.

How to use DOM matching

To add a DOM-matching step, you first need to identify the desired XPath or CSS selector.


One way to get the selector is to open your browser’s developer tools while your app is loaded, right-click on node you want to use, and select Copy > Copy XPath.

Once you have the appropriate selector, inside Rainforest:

  1. Click the plus button to add a new test step.

  2. Select the action type (e.g., Click, Fill, Hover).

  3. Change the search method from ‘Screenshot’ to ‘DOM search’.

    Screenshot 2023-10-26 at 11.34.48 AM.png

  4. Input the XPath or CSS selector in the field.

  5. Preview the step for accuracy.

Locating an element

There are multiple ways you can use DOM search to find the right element. You can use either CSS or XPath selectors and Rainforest will automatically detect which one is being used.


If there are multiple tabs open in the browser, DOM Search will search through all of them and switch to the tab where there is a match. If a match is found in multiple tabs, the action will fail, just like when there are multiple matches on a single page.

Here are some example selectors and their explanations:

To LocateUse
Button that reads "Continue"//button[text()="Continue"]
Button that contains the string "Go to" in the visible text//button[contains(text(), "Go to")]
Input element with any name attribute presentinput[name]
Input element with placeholder="login"input[placeholder='login']
Input element with name="login"input[name='login']
Input element with name containing "login"input[name*='login']
Input element with name starting with "login"input[name^='login']
Input element with name ending with "login"input[name$='login']
Input element with case-insensitive name "login" (so e.g. "Login" and "LOGIN" would also match)input[name='login' i]
Any element with id="submit-button"#submit-button
Any element that has class="large"//*[@class='large']
A canvas elementcanvas
The first button element inside the element with id="nav"//*[@id="nav"]//button[1]

Additional considerations

Ensure that your selector:

  • has valid syntax
  • matches exactly 1 element on the page

There are many possible selectors that can match any specific element and choosing the correct selector is important to keep your tests robust. Best selectors are short, uniquely identify an element and are unlikely to change in the future. It’s best to avoid selectors that rely on the hierarchical structure of HTML as those are more likely to change as your application evolves.

For example, given the following HTML structure:

<div id="main-navigation" class="nav">
	<button class="btn-sm">Home</button>
	<button class="btn-sm">Pricing</button>
	<button class="btn-sm">About</button>

To click on “Pricing” any of these selectors will work:

  • //button[text()="Pricing"]
  • //div[@id="main-navigation"]//button[2]

The first option is going to be more robust to future changes because it won’t be affected by changing the order of buttons. Relying on user-visible attributes such as button text is generally preferable to HTML structure.

If you have any questions, reach out to us at [email protected].