Add steps parameter to MouseMove for smooth drag gestures #81

Closed
opened 2026-02-28 16:21:39 +00:00 by Claude · 2 comments
Collaborator

Problem

MouseMove(x, y float64) currently calls ib.page.Mouse().Move(x, y) without passing MouseMoveOptions{Steps}. Playwright's Steps parameter defaults to 1, meaning only one Input.dispatchMouseEvent CDP call is generated per MouseMove() invocation.

This is a problem for slider captchas (e.g. DataDome) and other drag-based interactions where the target JavaScript listens for a stream of mousemove events during a drag. When the mouse jumps from position A to position B in a single event (no intermediate positions), the JS detects it as bot-like behavior and rejects the interaction.

How Playwright's Steps Works

From Playwright's Mouse.move() docs:

steps - Defaults to 1. Sends intermediate mousemove events between the current position and the target position.

When Steps: 5 is passed, Playwright interpolates 5 intermediate positions and dispatches 5 separate Input.dispatchMouseEvent CDP calls, making the movement appear smooth and human-like.

The playwright-go bindings support this via MouseMoveOptions:

type MouseMoveOptions struct {
    Steps *int `json:"steps"`
}

See also: playwright-go/tests/input_test.go which tests Steps: playwright.Int(5).

Proposed Fix

1. Add steps variadic parameter to MouseMove

Change the signature to accept an optional steps count (backward compatible):

// Before (interactive.go:195-197)
func (ib *interactiveBrowser) MouseMove(x, y float64) error {
    return ib.page.Mouse().Move(x, y)
}

// After
func (ib *interactiveBrowser) MouseMove(x, y float64, steps ...int) error {
    var opts playwright.MouseMoveOptions
    if len(steps) > 0 && steps[0] > 1 {
        opts.Steps = playwright.Int(steps[0])
    }
    return ib.page.Mouse().Move(x, y, opts)
}

The InteractiveBrowser interface would also need updating:

// Before
MouseMove(x, y float64) error

// After
MouseMove(x, y float64, steps ...int) error

This is fully backward compatible — existing callers that pass no steps argument get the same behavior as today.

2. (Optional) Add Drag convenience method

A higher-level method that does MouseDown → MouseMove (with steps) → MouseUp:

Drag(fromX, fromY, toX, toY float64, steps int) error

This would be convenient but is less critical since callers can compose the three calls themselves.

Impact

This fix is trivial (1-2 lines changed) but enables smooth drag gestures in the mort captcha proxy and browser proxy. Without it, mort has to implement manual position interpolation on its side as a workaround.

## Problem `MouseMove(x, y float64)` currently calls `ib.page.Mouse().Move(x, y)` without passing `MouseMoveOptions{Steps}`. Playwright's `Steps` parameter defaults to 1, meaning only **one** `Input.dispatchMouseEvent` CDP call is generated per `MouseMove()` invocation. This is a problem for slider captchas (e.g. DataDome) and other drag-based interactions where the target JavaScript listens for a **stream** of `mousemove` events during a drag. When the mouse jumps from position A to position B in a single event (no intermediate positions), the JS detects it as bot-like behavior and rejects the interaction. ## How Playwright's `Steps` Works From Playwright's [Mouse.move() docs](https://playwright.dev/docs/api/class-mouse#mouse-move): > **steps** - Defaults to 1. Sends intermediate `mousemove` events between the current position and the target position. When `Steps: 5` is passed, Playwright interpolates 5 intermediate positions and dispatches 5 separate `Input.dispatchMouseEvent` CDP calls, making the movement appear smooth and human-like. The `playwright-go` bindings support this via `MouseMoveOptions`: ```go type MouseMoveOptions struct { Steps *int `json:"steps"` } ``` See also: [`playwright-go/tests/input_test.go`](https://github.com/playwright-community/playwright-go/blob/main/tests/input_test.go) which tests `Steps: playwright.Int(5)`. ## Proposed Fix ### 1. Add `steps` variadic parameter to `MouseMove` Change the signature to accept an optional steps count (backward compatible): ```go // Before (interactive.go:195-197) func (ib *interactiveBrowser) MouseMove(x, y float64) error { return ib.page.Mouse().Move(x, y) } // After func (ib *interactiveBrowser) MouseMove(x, y float64, steps ...int) error { var opts playwright.MouseMoveOptions if len(steps) > 0 && steps[0] > 1 { opts.Steps = playwright.Int(steps[0]) } return ib.page.Mouse().Move(x, y, opts) } ``` The `InteractiveBrowser` interface would also need updating: ```go // Before MouseMove(x, y float64) error // After MouseMove(x, y float64, steps ...int) error ``` This is fully backward compatible — existing callers that pass no `steps` argument get the same behavior as today. ### 2. (Optional) Add `Drag` convenience method A higher-level method that does MouseDown → MouseMove (with steps) → MouseUp: ```go Drag(fromX, fromY, toX, toY float64, steps int) error ``` This would be convenient but is less critical since callers can compose the three calls themselves. ## Impact This fix is trivial (1-2 lines changed) but enables smooth drag gestures in the mort captcha proxy and browser proxy. Without it, mort has to implement manual position interpolation on its side as a workaround.
Author
Collaborator

Starting work. Will add the steps ...int variadic parameter to MouseMove in the interface and implementation, and update the mock. Skipping the optional Drag convenience method for now since callers can compose the three calls themselves.

Starting work. Will add the `steps ...int` variadic parameter to `MouseMove` in the interface and implementation, and update the mock. Skipping the optional `Drag` convenience method for now since callers can compose the three calls themselves.
Author
Collaborator

Done. PR #82 merged. MouseMove now accepts an optional steps ...int parameter for smooth intermediate mousemove events.

Done. PR #82 merged. `MouseMove` now accepts an optional `steps ...int` parameter for smooth intermediate mousemove events.
Sign in to join this conversation.