ScreenshotNeo

BlogHow-to

Puppeteer TouchHandle: How to Simulate Touch Gestures

Use Puppeteer’s TouchHandle to start, move, and end touch gestures. Learn when to use tap helpers, how to handle throttled events, and how to troubleshoot.

By the ScreenshotNeo team4 October 20265 min read

To simulate a multi-step touch gesture in Puppeteer, call page.touchscreen.touchStart(x, y), keep the returned TouchHandle, call move(x, y) for each point in the gesture, and finish with end(). For a tap, use page.touchscreen.tap(x, y) or page.tap(selector) instead.

The key detail is that a TouchHandle represents a touch that has already started. It lets you move or end that particular active touch.

1. Simulate a touch gesture with TouchHandle

This JavaScript example shows a swipe using the documented API shape. Replace the coordinates with points appropriate for the page and viewport you are automating.

const touch = await page.touchscreen.touchStart(120, 500);
await touch.move(150, 400);
await touch.move(190, 300);
await touch.end();

The sequence is start, zero or more moves, then end. Use intermediate coordinates when you want to describe a path rather than jump directly from start to finish. The API reference describes move(x, y) as dispatching a touch move for the active touch and end() as dispatching touch end.

Complete runnable example

Install Puppeteer in a Node.js project, save this as gesture.js, and run it with Node. This script opens a page, performs a gesture, and closes the browser even if the interaction fails.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });

    const touch = await page.touchscreen.touchStart(120, 500);
    await touch.move(150, 400);
    await touch.move(190, 300);
    await touch.end();
  } finally {
    await browser.close();
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

The coordinates above are illustrative. Choose points inside the relevant page area for your browser setup, and verify the API signatures against the documentation for the Puppeteer version installed in your project.

End the touch reliably

If code between touchStart() and end() can throw, make a best effort to end the touch in a finally block:

const touch = await page.touchscreen.touchStart(startX, startY);
try {
  await touch.move(midX, midY);
  await touch.move(endX, endY);
} finally {
  await touch.end();
}

Keep the handle returned by touchStart(). Do not call move() or end() on a handle that was never successfully created.

2. Choose between a gesture and a tap

Method Use it for Targeting behavior
TouchHandle A swipe or another multi-step touch interaction Explicit coordinate start, moves, and end
page.touchscreen.tap(x, y) A tap at a known point Coordinate tap; dispatches touch start and touch end
page.tap(selector) Tapping a page element Brings the element into view if needed, then taps its center

Use the highest-level helper that matches the interaction. A selector-based tap is usually easier to maintain when the target is an element; coordinates are appropriate when the gesture itself is the subject of the test.

3. Coordinate and event behavior

The API takes horizontal and vertical x and y positions. The supplied references do not establish additional coordinate transformations or a universal coordinate context for every setup, so check the documentation matching your installed Puppeteer release before relying on assumptions about scaling or device emulation.

Do not assume every call to move() results in one observable DOM touchmove event. Puppeteer’s reference warns that browser optimizations can throttle touch move events. Your automation can request multiple points while the browser emits fewer events.

If the behavior under test depends on movement, assert the resulting application behavior or final state where possible. Avoid making an exact event-count assertion unless the browser and application contract specifically guarantees it.

4. Check the installed Puppeteer version

Puppeteer API references are versioned. The references used for this guide label the TouchHandle, touchStart, and touchMove pages as version 25.3.0, while the tap reference is labeled 25.2.1. Those labels do not establish a definitive current release or the version in which each method was introduced.

  1. Check the version in your project lockfile or package manifest.
  2. Open the API reference for that same release.
  3. Confirm the exact signatures and behavior before depending on details beyond the start, move, end, and tap semantics described here.

5. Troubleshooting

Symptom Likely cause Fix
move() or end() fails The touch did not start successfully, or the handle is not the one returned by the active touchStart(). Await touchStart(), retain its returned handle, and use that handle for the gesture.
The page does not react to every requested move The browser may throttle or optimize touch move events. Do not expect one DOM event per call. Check the final interaction result and use the installed-version reference for event details.
A tap misses the intended control The coordinates may not match the target, or the element may have moved or not been visible. For an element target, try page.tap(selector), which brings it into view when needed and taps its center.
The example’s coordinates do not work on your page The example points are illustrative and may not land inside the relevant content for your viewport. Choose coordinates for the page and viewport in your setup; consult the matching API docs for coordinate details.
Behavior differs from the documentation you found The documentation may describe a different Puppeteer version. Match the API reference to the version installed in your project.

6. Performance, reliability, and cost

A gesture makes a sequence of browser automation calls, so add only the intermediate points your scenario needs. The cited API references do not establish a performance comparison between TouchHandle and tap helpers. They also do not promise that each requested movement becomes a separate browser event.

For reliable automation, keep the gesture tied to the page state you intend to test, end the touch after movement, and avoid relying on exact move-event counts in the face of browser throttling. The research references do not specify a Puppeteer usage cost; any cost depends on how and where you run the browser automation.

7. Or skip the browser setup

If the goal is to capture a page rather than test a touch interaction, ScreenshotNeo is a website screenshot API and MCP server. Its API takes a URL and returns an image or PDF. See the ScreenshotNeo API documentation for request options.

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}`);

ScreenshotNeo accepts cookie and consent banners like 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 the response identifies the page verdict and billed status in headers. Its MCP server includes take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

8. FAQ

Does TouchHandle start the touch?

No. Call and await page.touchscreen.touchStart(x, y) first; it returns the handle for that started touch.

Can I use TouchHandle for a simple tap?

You can express a touch with a start and end, but Puppeteer’s touchscreen.tap(x, y) or page.tap(selector) is the direct helper for tap-only interactions.

Will each move call fire a touchmove event?

Not necessarily. Browser optimizations may throttle touch move events, so a requested move is not a guarantee of a separately emitted DOM event.