[Bug]: click/keys/hover/drag report success but dispatch nothing when the page is not visible (background tab, minimized or occluded window)
Summary
browser click, hover, dblclick, drag and keys return a success envelope while doing nothing at all whenever the session's page is not being composited by Chrome — a background tab, a minimized window, or a window that is fully occluded by another window (including a popup the page itself opened with window.open).
CDP Input.dispatchMouseEvent / Input.dispatchKeyEvent resolve normally in that state, but Chrome never delivers the events to the renderer. Reads (eval, extract, state, find) and type (Input.insertText) keep working, so the session looks completely healthy and the agent has no way to notice that every write is being dropped.
This is a silent failure with a success-shaped return value:
{"clicked": true, "target": "#toggleMenu", "matches_n": 1, "match_level": "exact"}…while the page never sees the click.
Environment
- opencli 1.8.6 (also reproduced against a build of
upstream/main@8271afc6, v1.8.8) - Browser Bridge extension v1.0.22
- macOS 15 (Darwin 25.6.0), Chrome, Node v22.22.0
Minimal reproduction
index.html, served with python3 -m http.server 8765:
<!doctype html>
<html><head><meta charset="utf-8"><title>opencli focus repro</title>
<style>#menu{display:none}#menu.open{display:block}</style></head><body>
<button id="openTab">open a popup (window.open)</button>
<button id="toggleMenu">toggle dropdown</button>
<div id="menu"><div>item A</div></div>
<p>marker: <span id="marker">none</span></p>
<script>
let n = 0;
document.getElementById('openTab').addEventListener('click', () => window.open('popup.html', 'reproTab'));
document.getElementById('toggleMenu').addEventListener('click', () => {
document.getElementById('menu').classList.toggle('open');
document.getElementById('marker').textContent = 'CLICKED-' + (++n);
});
</script></body></html>opencli browser repro open "http://127.0.0.1:8765/index.html"
# 1) baseline — page is visible, the click lands
opencli browser repro eval "document.visibilityState" # visible
opencli browser repro click "#toggleMenu" # {"clicked": true, ...}
opencli browser repro eval "document.getElementById('marker').textContent"
# CLICKED-1 ✅
# 2) let the page open a popup, so the session's window is no longer the
# composited one (any other way of hiding the window works too: minimize
# Chrome, or switch to another tab in the same window)
opencli browser repro click "#openTab"
# 3) same click, same selector, same session
opencli browser repro eval "document.visibilityState" # hidden
opencli browser repro click "#toggleMenu" # {"clicked": true, ...}
opencli browser repro eval "document.getElementById('marker').textContent"
# none ❌ the listener never rankeys fails the same way, and just as quietly:
opencli browser repro eval "window.__k=0; document.addEventListener('keydown', () => window.__k++); 'ok'"
opencli browser repro keys Enter # prints "Pressed: Enter"
opencli browser repro eval "String(window.__k)"
# 0 ❌Meanwhile the DOM path works perfectly on the very same hidden page:
opencli browser repro eval "document.getElementById('toggleMenu').click(); document.getElementById('marker').textContent"
# CLICKED-1 ✅Expected vs actual
Expected: either the input reaches the page, or the command reports that it could not be delivered.
Actual: {"clicked": true} for a click the page never received. An agent driving a multi-step flow keeps going and every subsequent step is built on a state that never happened.
Workaround
Make the session's page the composited one again and the identical commands start working:
- background tab in the same window →
opencli browser <session> tab select <targetId> - occluded or minimized window → raise/restore the Chrome window by hand
There is no way to detect the bad state from a command's output, so an agent cannot know when to apply the workaround.
Root cause
At 8271afc6:
src/browser/base-page.ts:327—click()commits to the native path when the measured rect is non-zero and the point hit-tests onto the target. Both of those are computed withgetBoundingClientRect()/elementFromPoint(), which keep returning entirely correct values on a hidden renderer, so nothing in the probe notices the problem.src/browser/base-page.ts:353—tryNativeClick()returnstrueas soon as the CDP call resolves.nativeClick()(src/browser/base-page.ts:1247) only issuesInput.dispatchMouseEvent, and Chrome resolves it whether or not the renderer consumes it. Theel.click()fallback below it is therefore never reached.src/browser/base-page.ts:1017—pressKey()has the identical shape:tryNativeKeyPress()resolving is taken as proof the key was delivered, sopressKeyJs()never runs.extension/src/background.ts:2023—handleCdp()attaches the debugger and forwardsInput.*without ever checking or changing the tab's activation/visibility. The only code that activates a tab ishandleTabs'selectcase (extension/src/background.ts:1940), i.e. thetab selectworkaround.
So every layer reports success and none of them observes delivery.
Two related observations
browser screenshot(Page.captureScreenshot) forces a compositor frame, and immediately afterwards CDP input starts landing on the same still-hiddenpage. That makes the bug look intermittent if a screenshot happens to sit between two clicks.tab listreportsactive: falsefor the session's page in the background-tab case, so the extension does have the signal — it just isn't consulted on the input path, and it does not cover the minimized/occluded-window case (where the tab isactive: trueand the renderer is still hidden).
Related
- #2418 — same "click reports
clicked: truewhile dispatching nothing" shape, from CLI/extension version skew rather than visibility. Different trigger, same missing delivery check. - #2076 — led to
click_methodbeing surfaced; the same idea applies here, since the JS path is the one that actually works while hidden. - #2479 — the lifecycle RFC notes that automation should stay out of the user's way; this is the failure mode that makes "stay out of the way" silently lossy today.
I have a fix and will open a PR referencing this issue.
Source: jackwener/OpenCLI