Skip to content
CertiQA is in early access. Request access

1.11 Self-Healing Browser Actions for AI Agents

How agent-driven browser actions (an agent using browser_click, browser_type, and friends as tools) recover automatically from a changed selector, and how to assert on the resulting page state.

CertiHeal™ Self-Healing (2.2) recovers broken selectors in hand-authored Playwright-style UI test steps. This is the same underlying idea applied to a different surface: an AI agent that is itself given browser tools – browser_navigate, browser_click, browser_type, browser_select, browser_press_key, browser_read, browser_screenshot – and uses them autonomously as part of a multi-turn conversation. When the agent asks to click the checkout button and the page markup has drifted since the test was written, the underlying session resolves a resilient replacement locator (ARIA role, semantic text, visual anchor) before failing the call outright, exactly like CertiHeal does for a scripted step.

Pass –browser-target (a real page) or –browser-fixture (a deterministic fixture page, for tests that shouldn’t depend on a live staging environment) to run. Both proxy the agent’s browser tool calls to a certiqa-engine session over –engine-url (and –engine-token, if the engine requires one) – the engine is what actually holds the browser, resolves locators, and performs the self-heal.

Terminal window
certiqa-agent-runner run \
-p <project-id> -s <suite-id> \
-u https://agent.example.com/invoke \
-r https://api.example.com/api/v1/projects/<id>/runs -t <api-token> \
--browser-fixture checkout-v2 \
--engine-url http://localhost:3000

The browser tools are an MCP server the runner starts for the run. When a run is started by the platform (or a self-hosted runner), that server listens on a free port chosen for that run, so two runs on one machine never share it. Every request the runner sends to your agent carries the address in an X-Certiqa-Mcp-Url header (for example http://localhost:51234/mcp); connect your agent’s MCP client to that URL rather than a fixed port. The address is localhost, so the agent must run on the same machine as the runner. With --mcp-interceptor-port <port> you can still pin a port yourself, and the standalone certiqa-agent-runner keeps its default of 4792.

An agent can call browser_click successfully and still be wrong about what happened next – or it can narrate success in its final message while the page shows an error banner. ASSERT_BROWSER_STATE (see the Actions & Selectors reference) checks the live DOM directly – VISIBLE, TEXT_CONTAINS, VALUE_EQUALS, and the same verification vocabulary as a scripted UI step’s ASSERTION action – so a case can confirm the checkout page actually shows an order confirmation, independent of the agent’s own account of events.

- action: ASSERT_BROWSER_STATE
expect:
- selector: '[data-testid="order-confirmation"]'
verificationType: VISIBLE
- selector: '[data-testid="order-total"]'
verificationType: TEXT_CONTAINS
value: "{{expectedTotal}}"