Browser tool: click coordinates drift because outerWidth/outerHeight diverge from the CDP-overridden viewport

Status Open
Maintainer reply None cached
Activity 1 comment · opened Jul 17, 2026

Summary

The in-app Browser pane tool (mcp__Claude_Browser__*) delivers left_click/computer coordinates that map to the live page inconsistently, even when the page itself is completely static. Root cause appears to be that the tool's click-coordinate transform is based on the real underlying window's outerWidth/outerHeight, which drifts independently of the CSS viewport set via the resize_window tool (innerWidth/innerHeight), and independently of any actual page change.

This makes precise coordinate-based interaction (e.g. tapping a specific spot on a <canvas>-rendered video stream) unreliable — the same fractional target position works one moment and misses the next, with no visible cause on the page side.

Environment

  • Claude Code CLI, macOS (Darwin 25.3.0)
  • Reproduced against a local Node.js app (ws-scrcpy, a web-based Android screen-mirroring client) rendering a live device stream into two stacked <canvas> elements inside the Browser pane.

Steps to reproduce

  1. Open any page with a <canvas> element (or similar) in the Browser pane via preview_start.
  2. Call resize_window to set a fixed viewport, e.g. {width: 1000, height: 700}. Confirm via javascript_tool that innerWidth/innerHeight read 1000/700 — this stays constant for the rest of the session.
  3. Attach a capture-phase mousedown listener via javascript_tool that records event.clientX, event.clientY, and simultaneously outerWidth, outerHeight, innerWidth, innerHeight, devicePixelRatio.
  4. Issue several computer left_click calls at different coordinate values (e.g. [10,10], [200,100], [300,200], [500,500], [350,250]), spaced out with other tool calls in between (e.g. screenshot, more javascript_exec calls).
  5. Compare the recorded clientX/clientY against the input coordinate for each click.

Observed

  • The effective scale factor (clientX / inputX) is not stable: observed values include ~1.6x, ~4.104x, and ~3.58x across different clicks in the same session, with innerWidth/innerHeight unchanged (1000x700) throughout.
  • outerWidth/outerHeight, read via javascript_exec at different points, were also inconsistent across calls with zero action from the page or from us in between: observed 800x560, 1200x800, and other values, despite innerWidth/innerHeight and the target page's DOM (e.g. a canvas's getBoundingClientRect()) staying byte-for-byte identical.
  • Separately, screenshot actions returned varying PNG pixel dimensions for the identical, unchanged page/viewport across consecutive calls (e.g. 800x450, 800x1090, 698x1428, 800x560, 698x488), with no resize action performed by us.
  • A requestAnimationFrame loop started via javascript_exec, expected to log ~60 frames over 4 seconds, logged only 1 frame, firing at t=5739ms — i.e., the tab went ~5.7 seconds without a single animation frame executing. This suggests the tab is being treated as backgrounded/throttled by the browser engine at least some of the time, even while computer/screenshot actions are actively being issued against it.

Expected

  • resize_window should pin down the actual window/frame used for both screenshot capture and click-coordinate mapping, not just an independent CSS layout viewport override — so that a fixed CSS viewport implies a fixed, predictable click-coordinate space.
  • Coordinate mapping for computer actions (click, etc.) should be based on the same, single source of truth as whatever the screenshot action reports (or a documented fixed reference size), so callers can reliably compute target coordinates from a screenshot.
  • The tab should not appear to be background-throttled while it's the active target of computer/screenshot tool calls.

Impact

Any workflow relying on the Browser pane's computer coordinate clicking against non-DOM content (canvas/video streams, custom-rendered UI) is unreliable — the same relative on-screen target can hit or miss unpredictably, with no way for the caller to detect or compensate for it ahead of time (only explicit screenshot calls report a size, and that size does not reliably predict the scale used by a subsequent left_click). Ref-based clicks on real DOM elements are unaffected and remain reliable, as does driving input through an out-of-band channel (e.g. adb for an Android device rendered via the canvas), which is the workaround currently in use.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗