Finding elements reliably
Pages and windows change, and a selector that worked yesterday can stop finding its element today. Botream keeps tasks running with fallback locators, anchors and self-healing, and selector health tells you which captures to renew before they break.
How an element is found
For capture and desktop element actions, the agent tries in this order:
- The command's own locator:
--dompathfor web,--by/--targetfor desktop. - Fallback locators: yours from
--fallback, then alternatives built from the object properties table. - Self-healing: the most similar element, compared by the object properties captured with the command.
The run continues, with a warning in the log, whenever step 2 or 3 found the element. When nothing is found, the step fails and the nearest catch handles it.
Fallback locators
--fallback lists other locators, separated by ||, that are tried in order when the first one finds nothing:
capture --browser:$shop$ --action:click --dompath:"#save-btn" --fallback:"//button[normalize-space(.)='Save'] || [data-testid=save]"
desktop --action:click --window:$erp$ --by:automationid --target:"btnSave" --fallback:"name=Save || classname=SaveButton"
- Web: any XPath or CSS selector.
- Desktop:
name=…,automationid=…,classname=…, or an XPath.
Automatic fallbacks
You do not have to write fallbacks for captured elements. When a run starts, Botream completes the list from the whole Object properties table:
- First, the checked properties without the index and the DOM XPath, because a changed position is the most common break. When the DOM XPath is checked, the captured position among those properties' matches (the unchecked index) is tried before them.
- Then the element type with one identifying property each: test id, id, name, aria-label, placeholder, title,
for, link, source, alt text, text or value for web; AutomationId, Name, help text or class name for desktop.
Values that look generated (hex strings, GUIDs, framework counters, long digit runs) are skipped. Your stored task is not changed.
What happens when a fallback is used
The action runs with the first locator. Only when it fails and the element really is not there does the agent take the first fallback that finds it, log a warning ("Not found: … Using the fallback … re-capture the element") and continue. exists is true when any locator matches, and wait --type:element and wait --type:desktopelement also accept a fallback that appears.
Tip: A fallback warning means the page changed. Capture the element again before the fallbacks run out too.
Anchors
Some elements have nothing unique about them: five identical edit boxes in an old form, a price cell in a grid. An anchor is a nearby element that does not change, such as a label or a heading. When the locator matches several elements, the one closest to the anchor is used.
capture --browser:$shop$ --action:settext --dompath:"input.f" --anchor:"//label[.='Amount']" --anchorposition:right --value:$amount$
desktop --action:settext --window:$erp$ --by:classname --target:"Edit" --anchor:"name=Amount" --anchorposition:right --value:$amount$
--anchorposition |
Picks |
|---|---|
near (default) |
The match whose centre is closest to the anchor. |
right, left, below, above |
The closest match on that side of the anchor. The command fails when no match lies on that side. |
- Web:
--anchoris a selector. - Desktop:
--anchorisname=Amount,automationid=lblTotal,classname=Staticor an XPath. Anchors do not work with--by:index. - Capturing: click Capture next to Anchor and click the label or heading. Only its selector is kept: the anchor is a reference point, not the element the command acts on.
This is how you automate legacy applications without ids: "the edit box to the right of the Amount label".
Self-healing
When neither the locator nor any fallback finds the element, self-healing looks for the element that is most similar to the one you captured, and uses it if it is similar enough.
It works for capture and desktop element actions (not for exists and not for waits), and only for commands with captured object properties. Commands typed in by hand have none and are not healed.
How similarity works
- Candidates are the visible elements of the same HTML tag in the page or frame, or the elements of the same control type in the window. A button is only ever replaced by a button.
- Each property is compared with the captured value: an exact or wildcard match counts fully (comparisons kept from older tasks: Contains, Starts with and Ends with count as wildcards, Not equal to values are left out), labels and texts count by how many words and characters they share, classes by the class names they share.
- Identifying properties weigh most: id, name and test ids (web), AutomationId and Name (desktop). Then the text, aria-label and placeholder; less for title, link, type, role and class; least for the value.
- Position is ignored: the DOM XPath and the index are left out, because a moved element is exactly what healing should find.
- The result is a score from 0 to 100 %.
The best candidate is used when its score reaches the Minimum similarity (90 % by default) and no other candidate is almost as similar: when two candidates are within 2 points of each other, none is guessed.
What you see in the run
- Healed: the log shows a warning such as "Self-healed: used … (93 % similar)" and the run continues.
- Not healed: the step fails with the original error plus a line such as "Self-healing: the most similar element, button "Save", is 72 % similar; 90 % is needed".
Settings
Administrators set the defaults under Self-healing settings:
| Setting | Default | Meaning |
|---|---|---|
| Heal elements that are not found | On | Use the most similar element when it is similar enough. |
| Minimum similarity | 90 % | How similar an element must be (50–100 %). Below this the step fails with the best score in its message. |
| Only suggest for clicks that cannot be undone | On | See below. |
| Report elements changed below | 95 % | The drift warning of selector health. |
Task policy
Each task can override the setting. In the task list, choose Edit details; in Task details, under Self-healing, set When an element is not found:
| Option | Behaviour |
|---|---|
| As in the settings | Follows Heal elements that are not found. |
| Use the most similar element | Heals, whatever the setting says. |
| Only suggest it (the step fails) | Runs fail as before, and the editor shows the element self-healing would have used. |
| Off | No self-healing for this task. |
Only suggest it suits tasks whose clicks must never reach a wrong element. Tasks called through runtask follow their own policy.
Clicks that cannot be undone
With Only suggest for clicks that cannot be undone on, a click, double click or submit is never healed when the captured or the found element is labelled Delete, Remove, Send, Submit, Approve, Confirm, Pay, Transfer, Purchase, Buy, Sign or Publish (also Sil, Kaldır, Gönder, Onayla, Öde, Satın al, İmzala, Yayınla). The text, aria-label, value, title and name are checked. The most similar element is only suggested and the step fails.
Applying a suggestion in the editor
After a run with healing, the commands concerned show a Healed badge in the editor. Select the block to see the suggestion in the properties panel:
- Self-healed in N runs: the element was not found, so a similar one was used.
- Not found in N runs: self-healing found a similar element but did not use it (the task only suggests, or the click cannot be undone), so the step failed.
The card names the element used and offers two buttons:
- Apply puts that element's properties into the Object properties table (the same checks where it has them, index unchecked) and rebuilds the selector, so the task finds it directly. Save the task to keep the change.
- Dismiss forgets the suggestion.
Applying and dismissing are recorded in the audit log.
Selector health
Selector health measures every captured element in normal runs, with no extra runs: just before each capture or desktop element action, the element is read and compared with the capture. The comparison uses the same score as self-healing, but leaves out the web text and value, since those are the data a task reads, not a sign that the page changed.
Statuses
A selector's status comes from its latest run:
| Status | Meaning |
|---|---|
| Broken | The element was not found: the step failed. |
| Healed | Self-healing used a similar element. Apply the suggestion in the editor. |
| Fallback | Found by a fallback locator only. Re-capture the element. |
| Drifting | Found, but less similar to the capture than Report elements changed below (95 % by default). Re-capture it before the selector breaks. |
| Healthy | Found by its own locator, as captured. |
The Selector health page
Selector health in the main menu (Edit tasks permission) lists every measured selector, worst first, for the last 24 hours, 7 days or 30 days:
- Status, Task, Line and Command.
- Similarity in the latest run, and the lowest of the period.
- Runs and Last run (a link to that execution).
Filter by status, and click a row to open the command in the editor with its block selected. Only commands with captured object properties are measured: capture elements with the Capture button or the recorder.
Dashboard card
The Selector health card on the dashboard shows:
| Figure | Meaning |
|---|---|
| Steps healed | Element steps where self-healing used a similar element. |
| Saved by fallbacks | Element steps a fallback locator found. |
| Failures prevented | Runs that completed only because an element was healed or found by a fallback. |
| Drifting, Broken, Healthy | Selectors by status. |
View report opens the Selector health page.
Daily email
Under Notifications settings, Daily selector health report takes the addresses that get a daily email listing the selectors that are broken, healed, found by a fallback or drifting. Send the selector health report at sets the hour (server time, default 6). The email covers the last 24 hours and is sent only when something is not healthy. It needs the mail (SMTP) settings.
Best practices for stable selectors
- Capture, don't type. Captured commands carry object properties, which give you automatic fallbacks, self-healing and selector health. Hand-written selectors get none of these.
- Check what the element is, not only where it is. Prefer test ids, ids, names, labels and AutomationIds. A web capture checks the DOM XPath together with them: the run finds exactly the captured element, and when the layout changes the fallbacks (the same properties without the path) find it again. Leave Index unchecked whenever another property makes the element unique. Desktop captures skip values that look generated or contain a time when choosing what to check.
- Use wildcards for changing parts.
Invoice*instead ofInvoice 2026-10-06,*total*instead of a full sentence. - Use variables for data-driven elements. An inner text of
$customerName$finds the row for the current customer. - Anchor anonymous fields to their labels instead of counting them with an index.
- Watch the warnings. A fallback or healing warning in the log, a Healed badge or a Drifting status means the application changed. Re-capture or apply the suggestion while the task still works.
- Keep risky clicks protected. Leave Only suggest for clicks that cannot be undone on, and use Only suggest it for tasks that move money or send messages.
- Wait for the page, not the clock. Use
wait --type:elementor a--timeoutrather than fixed delays, so slow pages do not look like broken selectors.