Skip to content

[FEATURE] OS-Level Mouse Driver — port Clicky's CGEvent pattern for anti-CDP-detection #232

@Delqhi

Description

@Delqhi

OS-Level Mouse Driver (Anti-CDP-Detection)

Why

stealth-runner today uses CDP for all clicks (page.mouse.click(x, y)). This is detectable by:

  • PerimeterX: traces Runtime.evaluate calls
  • DataDome: fingerprints navigator.webdriver and DOM event sources
  • Akamai Bot Manager: detects CDP-injected MouseEvent properties
  • Cloudflare Bot Management: combines all of the above

When stealth-runner is deployed on protected sites, CDP-based clicking will fail at the bot-detection layer before the CAPTCHA solver even runs.

Clicky's solution (CGEventCreateMouseEvent on macOS Accessibility API): generate real OS-level mouse events that are indistinguishable from human interaction.

Acceptance Criteria

  • New module survey-cli/survey/captcha/coordinate_mouse.py
  • Cross-platform: macOS (pyobjc), Linux (xdotool/pyautogui), Windows (pyautogui)
  • API: click_at(x, y, button="left"), move_to(x, y, duration=0.5), drag(start, end)
  • Coordinates map browser pixels to OS screen pixels (handles devicePixelRatio)
  • Bezier curve mouse trajectories with human-like jitter
  • Variable timing distributions (NOT fixed sleeps)
  • Unit tests with mocked OS calls
  • Integration test: click target on a test page, verify via JS event listener

API Spec

from survey.captcha.coordinate_mouse import OSMouse

mouse = OSMouse()  # auto-detects platform

# Single click at browser coordinate (200, 300)
await mouse.click(x=200, y=300, button="left", human_like=True)

# Drag (for slider CAPTCHAs)
await mouse.drag(start=(100, 100), end=(400, 100), duration=1.5, steps=20)

# Multiple clicks (for image grid CAPTCHAs)
await mouse.click_sequence(
    points=[(100, 100), (200, 100), (300, 100)],
    inter_click_delay_ms=(200, 800),  # randomized within range
)

Implementation Notes

Platform-Specific Backends

Platform Backend Why
macOS pyobjc + Quartz.CGEvent* Native, undetectable, low-level
Linux xdotool (subprocess) or pyautogui xdotool is more native; pyautogui as fallback
Windows pyautogui + win32api Win32 APIs are direct OS calls
Headless (CI) pyvirtualdisplay + pyautogui For automated testing on Linux CI

Human-Like Trajectories

def bezier_curve(start, end, control_points=2, jitter=5):
    """Generate human-like mouse path using Bezier curves with random jitter."""
    # Implementation based on research papers on mouse-movement biometrics

Browser Pixel ↔ Screen Pixel Mapping

async def browser_to_screen(cdp, browser_x, browser_y):
    """Convert browser viewport coords to absolute screen coords."""
    window_bounds = await cdp.send("Browser.getWindowBounds")
    dpr = await cdp.eval("window.devicePixelRatio")
    return (
        window_bounds["left"] + browser_x * dpr,
        window_bounds["top"] + browser_y * dpr,
    )

Dependencies

  • pyautogui (cross-platform, well-maintained)
  • pyobjc-framework-Quartz (macOS only, for CGEvent)
  • python-xdotool (Linux optional, falls back to pyautogui)
  • All optional, gracefully degrade if unavailable

Related

Labels

enhancement, priority-high, anti-detection, architecture

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions