How to Click at Specific Coordinates With the Puppeteer Mouse API
Use Puppeteer's Mouse API to click a viewport point, choose a mouse button, and handle common coordinate and timing pitfalls.
To click a point in a Puppeteer page, call await page.mouse.click(x, y). The coordinates are CSS pixels in the main frame’s viewport, measured from its top-left corner: x is horizontal and y is vertical. They are not desktop-screen coordinates or document coordinates. Puppeteer’s Mouse API reference documents the method and its options.
Click a viewport coordinate
Here is a complete Node.js example. Install Puppeteer with npm install puppeteer, save this as click.js, then run node click.js. It opens a page, clicks at a viewport point, and closes the browser.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
// 250 CSS pixels right and 120 CSS pixels down from the viewport's top-left.
await page.mouse.click(250, 120);
} finally {
await browser.close();
}
})();
The point must lie within the page viewport to hit visible page content. If the coordinates come from an image, first make sure they use the same viewport dimensions and coordinate frame as the page. A screenshot displayed at a scaled size, a device-scale-factor image, or coordinates measured from the whole desktop can require conversion; the Mouse API expects viewport CSS pixels.
Mouse API options
click(x, y, options) is a shortcut for moving to the point and pressing and releasing the mouse button. Await it: the method returns a promise. Left is the default button. The documented button choices are left, right, middle, back, and forward.
// Right-click at the point.
await page.mouse.click(250, 120, { button: 'right' });
// Move in five intermediate steps, then click.
await page.mouse.move(250, 120, { steps: 5 });
await page.mouse.click(250, 120);
// Explicit low-level sequence, useful when press and release must be controlled.
await page.mouse.move(250, 120);
await page.mouse.down();
await page.mouse.up();
move accepts a steps option; its documented default is one. More steps emit intermediate movement events, but do not make automation equivalent to physical human input. Use the explicit down/up sequence only when the separate events matter to your automation.
Choose coordinates or an element locator
| Approach | Use it when | Tradeoff |
|---|---|---|
page.mouse.click(x, y) |
The coordinate itself is the target, or you need mouse events without first identifying an element. | A fixed point can miss if the layout, viewport, or content changes. |
page.locator(selector).click() |
The target is a known element in a page whose layout may change. | You need a reliable selector for the target. |
Puppeteer’s current guide recommends locators for known elements. Locator clicks check that the element is in the viewport, visible, enabled, and has a stable bounding box over consecutive animation frames. For example:
await page.locator('button[type="submit"]').click();
The older page.click(selector) API is also documented. It finds the selector, scrolls the element into view if needed, and clicks its center using the page mouse. For a selector click that triggers navigation, Puppeteer documents starting the navigation wait and click together to avoid a race:
const [response] = await Promise.all([
page.waitForNavigation(),
page.click('a.some-link'),
]);
That navigation pattern is documented for Page.click. For coordinate clicks, choose and await a navigation or other readiness wait based on what the target actually does.
Coordinate and interaction limits
- Viewport origin: the origin is the top-left of the main-frame viewport. Scrolling changes which document content occupies a viewport point; a document position is not directly interchangeable with a viewport coordinate.
- CSS pixels: use CSS pixel values, not device pixels from a high-density screenshot. If you measured a point from a resized screenshot, map it back to the page viewport dimensions before clicking.
- Frames: these coordinates are for the main-frame page coordinate space described by the API reference. A point inside an embedded frame can require accounting for that frame’s position and the page’s layout.
- Synthetic input: Puppeteer’s Mouse events trigger synthetic
MouseEvents and do not fully reproduce normal physical mouse capabilities. The reference specifically says dragging and selecting text are not possible withpage.mouse; use the DOM Selection API when actual text selection is needed. - Layout changes: overlays, responsive breakpoints, animations, and delayed content can move the intended target after coordinates were chosen. Wait for the relevant page state or use a locator for a known element.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The click hits the wrong place. | Coordinates were measured from the desktop, a full-page document, or a resized/device-pixel screenshot. | Use viewport CSS pixels from the viewport’s top-left. Convert screenshot coordinates to the current viewport’s CSS-pixel scale. |
| The point no longer targets the element. | The viewport size, scroll position, responsive layout, or dynamic content changed. | Set a known viewport, wait for the content that determines layout, recalculate the point, or switch to a locator. |
| The click seems to do nothing. | The point is outside the page content, an overlay intercepts it, or the intended target is disabled or not ready. | Confirm the viewport dimensions and page state. For a known target, use a locator click so its readiness conditions are checked. |
| Navigation wait times out or races. | The click did not cause a navigation, or the wait was started after a navigation had already begun. | Only wait for navigation when the action should navigate. For selector clicks, start waitForNavigation() and the click together as shown above; for other actions, wait for the relevant condition. |
| A drag or text selection cannot be reproduced. | page.mouse generates synthetic events and does not fully support those physical mouse capabilities. |
Use the DOM Selection API for text selection. For dragging, use an interaction method supported by the page and Puppeteer rather than assuming a coordinate click sequence reproduces physical input. |
Performance, reliability, and cost
A coordinate click is a small browser action; the main reliability cost usually comes from maintaining the coordinate mapping as viewport size, scroll position, and page layout change. Reuse a fixed viewport when coordinate-based interaction is necessary, wait for the state that determines the target position, and avoid arbitrary delays when a specific selector or navigation condition can be awaited. For a known element, locator readiness checks reduce dependence on a hard-coded point.
Running Puppeteer requires launching and managing a browser process, which has runtime and infrastructure costs in your environment. The cited Mouse API documentation does not specify performance benchmarks or a cost per click, so measure your own end-to-end workflow if throughput or infrastructure cost matters.
Or skip the browser setup
If you need a screenshot rather than browser-side interaction, ScreenshotNeo is a website screenshot API and MCP server for developers. Its one-call API returns an image or PDF; it does not perform Puppeteer coordinate clicks. The options below show the equivalent screenshot task in cURL, Python, and Node.js. See the ScreenshotNeo API docs for the available parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = require('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does page.mouse.click return a result?
It returns a Promise<void>; await it to ensure the mouse action has completed.
Can I click with the right or middle button?
Yes. Pass { button: 'right' } or { button: 'middle' }; the documented options also include left, back, and forward.
Can I use a screenshot point directly?
Only if that point is expressed in the page viewport’s CSS-pixel coordinate system. Convert points measured from scaled or device-pixel images first.
Is a coordinate click the same as a real user’s click?
No. Puppeteer’s mouse API generates synthetic mouse events and does not reproduce every physical mouse capability.


