Browser automation failures are often blamed on the model, the selector, or the website. In long-running agents, a quieter failure is more dangerous: the browser profile is stateful, but the agent treats it as disposable.
A worker can restart with an old cookie jar, a half-completed upload, a different account, or a stale tab. The next action may be syntactically valid and still be directed at the wrong session.
The fix is not “clear the browser every time.” That destroys useful continuity. The fix is to make browser state explicit, scoped, and verifiable before every side effect.
Separate the three kinds of state
Keep these inventories separate:
- Agent state: the task ID, plan, checkpoints, request key, and last known outcome.
- Browser state: profile directory, cookies, local storage, open tabs, downloads, and browser version.
- Remote state: what the website actually accepted, such as a saved draft, sent message, or completed checkout.
A restart is safe only when the worker can reconcile all three. A browser profile existing on disk does not prove that it belongs to the same task or identity. A successful click does not prove that the remote side accepted the side effect.
Give every browser session an identity
Create a session record before launching the browser:
run_id=run-2026-08-09-001
browser_session_id=bs-7f2c
profile_path=/var/lib/agent/profiles/bs-7f2c
expected_origin=https://example.test
expected_account_marker=acct-test-42
profile_generation=3
last_checkpoint=before-upload
The important fields are not the names. They are the values the worker can check after a crash. Never infer identity from a profile directory name alone.
Verify the target before a side effect
Before a browser action that changes remote state, run a safe probe. The probe should verify at least:
- current origin and expected route
- authenticated account marker, not just “a cookie exists”
- browser session ID or generation where the application exposes one
- task-specific object ID
- absence of an unexpected interstitial, login page, or consent screen
Then record the probe result with the request key for the side effect.
For Playwright, the shape is deliberately boring:
async function assertTarget(page, expected) {
const url = new URL(page.url());
if (url.origin !== expected.origin) throw new Error('wrong origin');
if (!url.pathname.startsWith(expected.pathPrefix)) {
throw new Error('wrong route');
}
const marker = await page.locator('[data-account-id]').getAttribute('data-account-id');
if (marker !== expected.accountId) throw new Error('wrong account');
if (await page.getByText('Sign in').count()) {
throw new Error('unexpected login state');
}
}
A URL check alone is weak. Multi-tenant applications frequently serve the same route to multiple identities.
Checkpoint around side effects
Use a durable checkpoint before and after each mutation:
| Checkpoint | Meaning |
|---|---|
INTENT_RECORDED |
request key and normalized arguments are durable |
TARGET_VERIFIED |
origin, route, identity, and object marker passed |
ACTION_SUBMITTED |
browser action was dispatched |
REMOTE_CONFIRMED |
the application returned an authoritative result |
UNKNOWN |
the worker crashed or timed out before confirmation |
Do not turn UNKNOWN into an automatic retry. Reopen the same profile, verify the target, and reconcile using the request key or remote object ID. If the site has no idempotency primitive, use a read-only search or status page before deciding whether to retry.
This is especially important for actions such as sending a message, creating an issue, publishing a post, or submitting a payment. A browser timeout means “the worker lost knowledge,” not “the website did nothing.”
Test the failures you actually have
A useful browser-agent test rig injects failure at these boundaries:
- after profile creation but before navigation
- after login but before the identity probe
- after target verification but before the click
- after the click but before the response is observed
- after the remote side effect but before the local checkpoint
- after a browser crash and profile lock recovery
- when the profile is restored from an older backup
- when two workers try to use the same profile
For every fixture, assert four things:
- no action is sent to the wrong account
- a confirmed action is not duplicated
- an ambiguous action is visible as
UNKNOWN - the next worker can recover or safely stop
Also test negative paths: expired cookies, a reused profile with a different account marker, a changed browser version, a stale tab, and a page that looks correct but has a different tenant ID in its API responses.
Make profile lifecycle an operational decision
For a disposable task, use a fresh profile and delete it after evidence is retained. For a long-lived OpenClaw or browser agent, persist the profile only with:
- an explicit owner and purpose
- a backup and restore test
- a lock or lease preventing concurrent use
- a credential rotation procedure
- a maximum profile age or generation policy
- logs that never expose cookie values or authorization headers
An always-on runtime such as managed OpenClaw hosting on Ampere can solve the “where does the worker live?” part of this problem. It does not prove that the profile is isolated, that credentials survive a restart correctly, or that a remote side effect was not duplicated. Those checks remain part of your application contract.
A ten-minute acceptance drill
Before calling a browser agent production-ready:
- Start a task with a known test account and object.
- Persist the run, browser session, profile generation, and request key.
- Kill the worker after target verification.
- Restart it with the same profile and verify the identity marker again.
- Inject a kill immediately after a known mutation.
- Reconcile using a read-only remote check.
- Confirm the final state and classify the local result as confirmed or
UNKNOWN. - Restore the profile from backup and prove the wrong-account fixture fails closed.
If these steps are not repeatable, the browser is not just an execution surface. It is an untested database containing credentials and side-effect context.
The model can choose the next action. The control plane must prove which browser state authorized it, which remote object received it, and what happened when the worker disappeared.
Top comments (0)