Self-Healing Locators in Vibium, Explained
Vibium has no bolt-on self-healing locator engine — it earns resilience via semantic selectors, accessibility-tree finding, pickBest, and auto-wait.
Vibium doesn't ship a bolt-on "self-healing" engine that silently rewrites broken selectors — and it's worth being honest about that. Instead, Vibium earns locator resilience by design. You find elements the way a person reads a page: by accessible role, visible text, label, or test id, rather than by a fragile CSS path like div.form > button:nth-child(3). Those semantic selectors describe intent ("the Sign in button"), so they keep working when developers reshuffle the DOM. Vibium backs this with accessibility-tree finding, a pickBest heuristic that resolves ambiguous matches to the most likely element, and server-side auto-wait that retries until the element is genuinely ready. The result is locators that "heal" in the practical sense — they survive markup churn — without a magic black box guessing at replacements you can't audit.
Why do traditional locators break?
Most flaky tests trace back to brittle locators tied to implementation details. A selector like #root > div:nth-child(2) > form > button encodes the exact structure of the page. The instant a developer wraps the form in another div or reorders fields, that path points at the wrong node or nothing at all. XPath positional selectors fail the same way. The element a user sees — "the blue Submit button" — hasn't changed, but the locator that described its position has.
Vibium's answer is to stop describing position and start describing the element itself.
How do semantic selectors heal locators?
Vibium's find() accepts semantic keyword arguments that match an element by what it is and what it says, not where it sits in the tree. These map directly to how assistive technology and users perceive the page.
| Parameter | Matches against |
|---|---|
role | ARIA role (explicit, or implicit from the tag) |
text | Visible text content (substring match) |
label | aria-label, aria-labelledby, or associated <label> |
placeholder | placeholder attribute |
testid | data-testid attribute |
A button found this way survives a DOM reshuffle, because its role and label don't change when its position does:
from vibium import browser_sync as browser
vibe = browser.launch()
vibe.go("https://app.example.com/login")
# Resilient: describes the element, not its DOM position
vibe.find(role="button", text="Sign in").click()
vibe.find(label="Email").type("alice@example.com")
vibe.quit()Compare that to find("#root > form > button:last-child"). The semantic version reads like a sentence and doesn't care how many wrappers surround the button.
What does the pickBest heuristic do?
When a text query matches more than one element, Vibium needs to resolve the ambiguity — and it does so with a heuristic called pickBest, which selects the element with the shortest text content. This prefers a <button>Submit</button> over a large <div> that merely contains the word "Submit" buried in a paragraph. In effect, the heuristic picks the element a real user would click, which is exactly the behavior that keeps a semantic locator pointing at the right node as the page evolves. If you ever need to be explicit, you can pass an index to bypass the heuristic entirely.
How does the accessibility tree help?
The most resilient way to find elements is to read the page the way a screen reader does, then act on what you find. Vibium's accessibility tree exposes every meaningful element with its role and accessible name, which you can feed straight back into find():
from vibium import browser_sync as browser
vibe = browser.launch()
vibe.go("https://app.example.com")
tree = vibe.a11y_tree() # structured, role + name view of the page
# ...inspect the tree, discover the accessible name at runtime...
vibe.find(role="button", label="Sign in").click()
vibe.quit()Because the tree is built from semantics rather than markup, an AI agent (or your script) can rediscover an element after a redesign without anyone hand-updating a CSS path. This runtime discovery loop is the closest thing Vibium has to "self-healing" — and it's transparent, because you can see exactly what the tree returned.
When should I still use CSS selectors?
Semantic locators aren't always the right tool, and Vibium fully supports CSS (and XPath) when you want precision. Reach for CSS when you know the structure is stable or when you're reading state rather than interacting.
| Use semantic selectors when... | Use CSS selectors when... |
|---|---|
| Interacting like a user (click, type) | Reading text or state precisely |
| The markup may change | You control the structure and IDs are stable |
| Finding by role and name | Targeting a specific id or class |
A pragmatic pattern is to mix them: use a stable data-testid (via find(testid="...")) for elements you control, and semantic role/text for everything else.
So is Vibium "self-healing" or not?
It depends on your definition. Vibium does not include an engine that detects a failed selector and machine-guesses a substitute. What it gives you instead is durable-by-construction locators: semantic selectors, accessibility-tree finding, the pickBest heuristic, and auto-wait, working together so locators rarely break in the first place. That's a more honest and more debuggable form of resilience than a hidden healing layer — you always know why a locator matched.
Next steps
Frequently asked questions
Does Vibium have self-healing locators?
Vibium doesn't ship a separate self-healing engine that rewrites broken selectors. Instead it makes locators resilient by design: you find elements by accessible role, text, and label rather than brittle CSS paths, so selectors survive markup changes the same way a human reading the page would.
How does Vibium make selectors resilient?
Vibium combines semantic selectors (role, text, label, placeholder, testid), accessibility-tree finding, a pickBest heuristic that prefers the closest matching element, and server-side auto-wait. Together these reduce the brittleness that traditional CSS or XPath locators suffer when a page's structure changes.
What is the pickBest heuristic in Vibium?
When a text query matches several elements, Vibium's pickBest heuristic chooses the element with the shortest text content. That prefers a real button labeled Submit over a large container that merely contains the word Submit, so semantic finds resolve to the element a user would actually click.
Vibium is created by Jason Huggins. This is an independent tutorial — see the official Vibium site and GitHub repo for canonical docs.
Related guides
WebDriver BiDi vs CDP: What's the Difference?
WebDriver BiDi vs CDP: both are bidirectional protocols, but BiDi is a cross-browser W3C standard while CDP is Chrome-specific and vendor-controlled.
4 min read→Concepts & InternalsEvent-Driven Browser Automation with Vibium
Event-driven browser automation with Vibium uses WebDriver BiDi's pushed events for auto-waiting, console capture, and reliable scripts without sleeps.
4 min read→Concepts & InternalsHow Vibium's Actionability (Auto-Wait) Works
Vibium's actionability auto-wait runs checks (visible, stable, receives events, enabled, editable) server-side in Go before each action — skip sleeps.
4 min read→Concepts & InternalsSync vs Async in Vibium: How It Works Under the Hood
Sync vs async in Vibium under the hood: both clients call the same Go binary over a local WebSocket, so blocking and awaiting share one automation engine.
4 min read→