CDP Recovery and Context Selection
Disconnection Recovery
When the browser closes or crashes (Target page, context or browser has been closed):
- Check the port:
Invoke-WebRequest -Uri 'http://localhost:<port>/json/version' -TimeoutSec 5. - If refused, verify whether the owned process exited. Restart only an authorized owned instance, applying the foreground-exception rule before launch; never restart a user's browser or another session's process automatically.
- Confirm
/json/versionreturnsBrowser. - Reconnect using the tool's verified attachment semantics;
browser_closeis not a generic disconnect. Re-establish the owned target identity, authentication, and durable state before any write. - If another helper is needed, stop the owned controller and detach without destroying tabs. If safe detachment is unavailable, retain the current route or stop. Reconnection never resets the logical operation's recovery budget.
Sign-In Rejected as an Unsafe Browser
- A provider message such as "This browser or app may not be secure" is browser sign-in rejection, not proof of a wrong account or password. Record the observed message separately from the cause: automation/CDP can be a hypothesis, not a diagnosis from the screenshot alone. Google guidance lists several possible browser-related causes.
- Stop retries on the unchanged rejected route. Ask the user to test the intended account in a normally launched, supported browser; credentials and MFA stay user-entered. This is a next check, not a verified recovery. Do not spoof automation signals, weaken security settings, copy cookies/credentials or restart a user browser without consent.
- Successful manual login does not transfer authentication or control to MCP/CDP. Re-establish the authorized route and target/account identity before writes; otherwise offer a manual handoff. Never borrow another session's authenticated browser to escape the rejection.
- Preserve completed work and the verified artifacts. Report authentication, tool attachment and the intended submission/save as separate states; request only the blocked next step, not a repeat of completed writes.
Unresponsive but Still Connected
If /json/list works but Runtime.evaluate or Page.enable times out, suspect a JS dialog, beforeunload prompt, reload confirmation, or in-page modal.
- Use one short read probe.
Page.getFrameTreecan also stall; switching from JavaScript to another page command does not exclude a browser-chrome modal. - For a known leave-site confirmation on the owned target, try
Page.handleJavaScriptDialog({accept: false})once. ANo dialog is showingresponse describes that CDP session, not the entire browser window. If page commands still stall, inspect native UI before asking the user to intervene. - Keep
Page.enable, dialog events and command responses on the same WebSocket session when using event-driven recovery; dispatch responses by command ID instead of dropping dialog notifications. - While a browser-chrome prompt is visible,
/json/listcan show the destination URL before navigation commits. Verify the actual address and same-target DOM after dismissal; do not infer navigation or save success from the target list. - Do not close tabs, kill the browser, clear profiles or blindly send Escape/Enter to recover a dirty editor. If safe ownership and dialog matching cannot be established, request manual Cancel/Stay and preserve the stopped state.
Windows Browser-Chrome Leave-Site Prompt
Use native UI Automation only to cancel an identified leave-site prompt, not as a generic consent handler. Cancellation preserves the form; Leave can discard it.
- Resolve the loopback CDP listener's owning process and verify the expected browser executable and dedicated profile. Pin the target ID and the application's owned resource identity. Enumerate only that process's top-level windows with
UIAutomationClient/UIAutomationTypes. - In that window, match the selected-tab address bar through
ValuePatternagainst the approved origin and resource route. A matching process or generic window title alone is insufficient. Refuse unrelated URLs, multiple candidates or an unavailable address. - Require an exact leave-site dialog title, unsaved-changes warning, and one visible enabled Cancel/Stay button in that dialog subtree, using labels actually observed for the current locale. Edge can expose the dialog as a
RootViewwindow while CDP reports none. Treat class names as observed hints, not universal version guarantees. - Default to dry-run. On explicit apply within the authorized browser task, recheck the candidate and invoke its
InvokePatternonce. Do not activate the window or send global keystrokes to make matching succeed; announce any necessary activation under the foreground-exception rule. Do not click coordinates, accept Leave, target permission/authentication prompts, or operate another tab. - Verify both dialog disappearance and
Runtime.evaluateresponse on the same owned target. A repeat with no matching dialog must not click anything. If readback fails, record dismissal and page recovery separately rather than claiming success.
Keep screenshots, capture time and sanitized recovery results; protect exact addresses and identifiers in private records. Read persisted settings separately: Cancel leaves a dirty form dirty. Use a clean work tab for subsequent server-state reads and never overwrite the original evidence.
Windows Application Content Without CDP
An authenticated window outside the inspected CDP endpoint is not evidence of logout. Before relaunching, copying profiles, installing OCR, or guessing coordinates, check whether native UI Automation exposes the intended application content. This route does not expand permission to handle browser consent, credentials, or leave-site dialogs.
- Enumerate top-level windows under the verified browser process;
MainWindowHandlemay identify a different window under the same PID. Match the selected address/document URL and resource identity, then pin the HWND for this run. A title or process match alone is insufficient; ambiguity stops writes. - Check minimization before trusting a small or blank
PrintWindowimage or empty UIA tree. A successful capture return value is not rendering proof. Restore only the identified, authorized window after announcing any necessary activation; re-read its bounds and content before further action. - Prefer scoped
TextPatternreads and a uniquely matched control's supported pattern over global keys or OCR. Separate conversation history from the composer and repeated list previews; retrieve full relevant content before deciding whether a reply is outstanding. Stop if the target URL or content cannot be verified. ValuePattern.SetValue,SetForegroundWindow,SetFocus, andInvokePatternmay return before observable state changes; a successful call is not input or save proof. Before native keystrokes, verifyGetForegroundWindow()equals the pinned HWND and the intended editor has keyboard focus. Await those conditions within a deadline; on mismatch send no keys, and never use blind Enter/Escape to recover.- Re-read the editor after input and compare it with the approved body before enabling a send step. Treat delayed readback as pending, not permission to type twice. Record whether focus, typing, or submission actually occurred; resume only from verified state within the same retry budget.
- Keep PowerShell UIA helpers repeatable: do not store collections in the automatic
$Matchesvariable; guard unchangedAdd-Typedeclarations, and use a new type name with consistent call sites when a signature changes. Parse CDP JSON arrays into a variable and enumerate their objects before projecting fields; blank projections must not become "no windows/tabs".
A Widget Stops Responding After Many Operations
A single component can wear out while the rest of the page stays healthy: a type-ahead that stops returning suggestions after a few dozen lookups, a picker that no longer opens, an editor that stops accepting input. The page answers Runtime.evaluate normally, so none of the dialog checks above apply.
- Reloading often does not clear it. When the app restores its state from the server or session storage, the reloaded page rebuilds the same wedged component. A passing reload is not evidence that the component recovered.
- A fresh owned background tab may rebuild the component. Choose this as the single recovery after the initial failure, not an extra attempt after two failures. Preserve the original dirty tab and verify the replacement's authentication and resource identity.
- Assert the widget's actual success signal. Before replaying a write, establish non-application or use duplicate protection; unknown outcomes stop the operation. No new tab, tool, or script resets the shared two-attempt budget.
- For long loops, persist completed item IDs and the last verified stage. Resume only unresolved work after ownership and state checks, and do not confuse healthy asynchronous progress with another failed attempt.
Context / Page Selection
connect_over_cdp() can expose multiple browser contexts and profiles. Never assume contexts[0].pages[0] is the right page.
Safe selection:
- Enumerate contexts/pages only to identify the approved profile and workload; domain matches are candidates, not ownership evidence.
- Reuse an explicitly designated target or create a dedicated background work tab using the existing-browser procedure.
- Verify login, authorization, origin, resource route, and required controls after loading; generic titles or header/footer-only frames are inconclusive. Pin that context and target ID for the run.
- Before writes, re-check route, resource/item identity, and absence of competing user editing. Pause on drift or ownership uncertainty; do not silently choose another matching tab.
- If identity or readiness cannot be established, return a compact stopped state with sanitized URL/title and reason. After a crash, rebind explicitly instead of pretending the old target ID is still valid.