If you have ever written a Selenium test, a Puppeteer script, or any browser automation, you know the pain. You spend an afternoon crafting a perfect workflow, deploy it, and three days later it breaks because someone on the target website renamed a CSS class from btn-primary to button--main. Traditional browser automation is fragile by design: it relies on exact selectors that assume the DOM will never change. Tensor takes a fundamentally different approach. Our selectors heal themselves.
Why Traditional Selectors Fail
The root problem is straightforward. A CSS selector like #checkout-form > div:nth-child(3) > button.submit-btn is an absolute path through the DOM tree. It describes structure, not intent. If a developer wraps that button in an additional container, changes its class name, or reorders the children, the selector breaks. The intent, "click the submit button," remains unchanged, but the path to it has shifted.
This fragility is not an edge case. Modern web applications deploy changes daily. A/B tests swap components. React re-renders can produce different DOM structures depending on state. Third-party scripts inject wrapper elements. The average e-commerce site changes its checkout page structure approximately every two weeks, which means any automation targeting checkout flows has a shelf life measured in days, not months.
Testing frameworks have tried to address this with data attributes like data-testid, but these only work when you control the codebase. When you are automating a third-party website, you control nothing. You are at the mercy of their deployment schedule.
The Selector Resolution Stack
Tensor's self-healing system does not rely on a single selector strategy. Instead, it maintains a ranked stack of resolution strategies that it evaluates in order of reliability. When recording a user action, Tensor captures not just the primary selector but an entire fingerprint of the target element. That fingerprint includes:
- Element ID — the most stable identifier, but only useful when present and unique
- data-testid / data-cy / data-qa — testing attributes that developers intentionally keep stable
- ARIA attributes —
aria-label,role, andaria-describedbyare semantic and rarely change - Text content — the visible text of a button or link is often the most stable feature
- CSS class names — useful but volatile, especially with CSS-in-JS solutions that generate hashed classes
- XPath with structural hints — a path-based fallback that uses tag names and relative positioning
- Visual and positional matching — when all else fails, Tensor uses the element's position, size, and visual characteristics to find a match
When replaying an action, Tensor starts at the top of the stack and works down. If the ID still exists, it uses that. If the ID is gone but the aria-label matches, it uses that. If both are gone but there is exactly one button with the text "Submit Order," it uses that. Each strategy returns a confidence score, and Tensor requires a minimum threshold before proceeding.
// Selector resolution example
const strategies = [
{ type: 'id', selector: '#submit-order', confidence: 0.99 },
{ type: 'testid', selector: '[data-testid="order-btn"]', confidence: 0.97 },
{ type: 'aria', selector: '[aria-label="Submit order"]', confidence: 0.95 },
{ type: 'text', selector: 'button:has-text("Submit")', confidence: 0.88 },
{ type: 'class', selector: '.checkout__submit-btn', confidence: 0.72 },
{ type: 'xpath', selector: '//form//button[last()]', confidence: 0.65 },
{ type: 'visual', selector: { role: 'button', near: 'order summary' }, confidence: 0.58 }
];
// Resolution: try each in order, use first above threshold
const match = await resolveElement(strategies, { threshold: 0.6 });
Fuzzy Matching and Similarity Scoring
Real-world DOM changes rarely destroy all signals simultaneously. More commonly, a class name changes while the text remains the same, or the element moves within the tree but keeps its ARIA attributes. Tensor exploits this by computing a composite similarity score across all strategies rather than relying on a single one.
The fuzzy matching engine uses Levenshtein distance for text comparisons, Jaccard similarity for class lists, tree edit distance for structural comparisons, and cosine similarity on a feature vector that combines all signals. When the composite score exceeds the healing threshold, Tensor considers the element found and updates its stored fingerprint for future runs.
This means the selectors literally get better over time. Each successful healing event refines the fingerprint, adding new attributes that proved stable and downranking attributes that proved volatile. After a few healing cycles, the system has learned which signals are reliable for that specific page and which are noise.
Handling Dynamic Content
Some elements are inherently dynamic. A product list might have different items each time you visit. A news feed rearranges based on recency. A dashboard shows different metrics depending on the time range. For these cases, Tensor uses contextual anchoring rather than absolute identification.
Instead of targeting "the third item in the list," Tensor targets "the item containing the text 'Wireless Headphones' in the list below the heading 'Recommended Products.'" This description is both human-readable and machine-resolvable. The anchoring system identifies stable landmarks on the page, such as headings, navigation elements, and section boundaries, and then locates the target element relative to those landmarks.
When even contextual anchoring fails, Tensor enters recovery mode. It takes a screenshot of the area where the element should be, uses a vision model to identify the most likely candidate, and presents the match to the user for confirmation. If confirmed, the new element is incorporated into the fingerprint. If denied, the workflow pauses and explains exactly what changed and what it tried.
The Cost of Not Healing
To quantify the impact, we ran an experiment. We recorded 200 workflows across 50 popular websites and replayed them daily for 30 days. With traditional fixed selectors, the median workflow survived 4 days before breaking. With Tensor's self-healing selectors, 94% of workflows completed successfully on day 30 without any manual intervention.
The remaining 6% hit edge cases that required recovery mode: full page redesigns where the target element was removed entirely, or single-page applications that changed their routing structure. Even in those cases, Tensor provided clear diagnostic information about what broke and why, turning a frustrating debugging session into a two-minute fix.
For enterprises running hundreds of automated workflows, the difference is transformative. A team that previously spent 30% of their time maintaining broken scripts now spends that time building new automations. The ROI is not in the automation itself but in the maintenance hours it eliminates.
Building Resilient Selectors: Best Practices
Even with self-healing, you can improve reliability by following a few practices when recording workflows:
- Prefer semantic actions — "Click the button labeled Submit" is more resilient than "Click the element at coordinates (450, 320)"
- Add wait conditions — wait for specific text or elements to appear rather than using fixed delays
- Use checkpoints — break long workflows into segments so that healing only needs to fix one step, not replay everything
- Review healing reports — when Tensor heals a selector, it logs exactly what changed, helping you understand the target site's update patterns
Self-healing selectors are not a silver bullet. They cannot fix a workflow when the underlying business process changes, such as when a checkout flow adds a new mandatory step. But for the vast majority of breakages caused by cosmetic and structural DOM changes, they eliminate the maintenance burden entirely. Browser automation should be write-once, run-forever. With Tensor, it finally is.
Automation That Maintains Itself
Try Tensor's self-healing workflows and never fix a broken selector again.
Download Tensor