Skip to content

Stopping Stuck Browser Actions with CDP

I’ve spent many hours debugging automation scripts that just… stop. You send a command to evaluate some JavaScript, it takes longer than expected, and suddenly your entire browser tab is unresponsive. Every click or type action you send afterward gets stuck in a queue.

It’s a common pain point when your execution engine serializes every command. If one script hangs, the whole tab hangs. I want to show you how we are moving act:evaluate to a separate CDP-based engine to keep your browser operations moving.

  • browser.evaluateEnabled gate must be active.
  • Access to the browser-level CDP socket.

The new architecture ensures that a stuck evaluate command cannot block later actions on the same tab. Here is how the path works now.

  1. Set a Budget: We use a single budget for the entire request. The createBudget helper links your timeout and abort signals.
// The budget helper provides a single source of truth
const budget = createBudget({ timeoutMs, signal });
// It exposes these properties:
// budget.signal (the linked AbortSignal)
// budget.deadlineAtMs (absolute deadline)
// budget.remainingMs() (budget for child operations)
  1. Isolate the Execution: The system connects to the CDP endpoint and uses Target.attachToTarget with flatten: true to get a sessionId. This bypasses the standard Playwright command queue.

  2. Target Elements with Refs: If you provide a ref, the system looks for a backendDOMNodeId. This allows us to run element-level evaluations without switching everything off Playwright.

{
"role": "button",
"name": "Submit",
"nth": 0,
"backendDOMNodeId": 12345
}
  1. Run the Script: The engine executes Runtime.evaluate for page-level scripts or Runtime.callFunctionOn for elements. If the script times out, the system sends Runtime.terminateExecution and closes the session.
  • Script Side Effects: When a timeout or abort occurs, we trigger Runtime.terminateExecution. While this unblocks the queue, it can leave the page in an inconsistent state because the JavaScript was forcibly stopped.
  • Mapping Failures: If the AX tree cannot map a ref to a backendDOMNodeId, the system falls back to the standard Playwright path. This ensures the action still attempts to run, even if it uses the older, serialized queue.

If you have more questions about setting this up, check out the AI Setup Assistant.

OpenClaw

OpenClaw Expert

Still stuck?

If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.