Skip to main content

Human Emulation

Overview

Human Emulation is an advanced feature that enables human-like interaction with web pages through sophisticated mouse movement and keyboard input synthesis. This technology helps bypass anti-bot detection systems by generating biometrically accurate user behavior patterns.

Key Advantages

  • Human-like Behavior: Generates natural mouse movements and typing patterns with realistic acceleration, deceleration, and physiologically accurate trajectories
  • Anti-Detection: Bypasses sophisticated bot detection systems through low-level CDP control, eliminating robotic patterns
  • Flexible Integration: Works seamlessly with Playwright, Puppeteer, and Selenium

Available CDP Methods

The human emulation layer provides the following CDP actions:

  • Action.click - Performs human-like mouse clicks
  • Action.moveTo - Moves mouse cursor naturally to coordinates
  • Action.type - Types text with realistic typing patterns and speed
  • Action.scroll - Scrolls page with smooth, natural motion

Examples

Complete Search Automation

import asyncio

async def search_example(page):
# Create CDP session for human-like actions
client = await page.context.new_cdp_session(page)

await page.goto("https://duckduckgo.com", wait_until="load")

# Wait for search input to be ready
await page.wait_for_selector('input[name="q"]')

# Get search box coordinates
search_box = await page.locator('input[name="q"]').bounding_box()
x = search_box["x"] + search_box["width"] / 2
y = search_box["y"] + search_box["height"] / 2

# Click on search box with human-like precision
await client.send("Action.click", {"x": x, "y": y, "button": "left"})

# Type search query
await client.send("Action.type", {"text": "Surfsky cloud browser"})

# Get submit button coordinates
click_box = await page.locator('button[type="submit"]').bounding_box()
x = click_box["x"] + click_box["width"] / 2
y = click_box["y"] + click_box["height"] / 2

# Move mouse naturally to submit button
await client.send("Action.moveTo", {"x": x, "y": y})

# Click submit button
await client.send("Action.click", {"x": x, "y": y, "button": "left"})

# Wait for results to load
await page.wait_for_selector(".results")

# Scroll down naturally
await client.send("Action.scroll", {"deltaY": 500, "duration": 1.5})

Form Filling with Natural Behavior

async def fill_form_naturally(page, client):
# Form fields with typing speeds
fields = [
{"selector": "#name", "text": "John Smith", "wpm": 70},
{"selector": "#email", "text": "[email protected]", "wpm": 60},
{"selector": "#message", "text": "This is a test message", "wpm": 80}
]

for field in fields:
# Get element position
element = await page.locator(field["selector"]).bounding_box()
x = element["x"] + element["width"] / 2
y = element["y"] + element["height"] / 2

# Move to field
await client.send("Action.moveTo", {"x": x, "y": y})

# Click to focus
await client.send("Action.click", {
"x": x,
"y": y,
"button": "left"
})

# Type with specified speed
await client.send("Action.type", {
"text": field["text"],
"wpm": field["wpm"]
})

# Natural pause between fields
await asyncio.sleep(0.5)

Scrolling and Navigation

async def navigate_page(page, client):
# Smooth scroll down
await client.send("Action.scroll", {
"deltaY": 300,
"duration": 1.0 # 1 second smooth scroll
})

# Scroll to element
element = await page.locator(".target-section").bounding_box()
current_position = await page.evaluate("window.pageYOffset")
scroll_distance = element["y"] - current_position - 100 # 100px offset

await client.send("Action.scroll", {
"deltaY": scroll_distance,
"duration": 2.0 # 2 second smooth scroll
})

CDP Action Parameters

// Action.click parameters
await client.send("Action.click", {
// Either x,y coordinates OR selector is required
x: 100, // X coordinate
y: 200, // Y coordinate
// OR
selector: "button.submit", // CSS selector (alternative to x,y)

button: "left", // "left", "right", or "middle"
});

// Action.moveTo parameters
await client.send("Action.moveTo", {
// Either x,y coordinates OR selector is required
x: 300, // Target X coordinate
y: 400, // Target Y coordinate
// OR
selector: "#target-element", // CSS selector (alternative to x,y)

duration: 0.8 // Optional: movement duration in seconds
});

// Action.type parameters
await client.send("Action.type", {
text: "Hello World", // Text to type
wpm: 60, // Optional: Words per minute (typing speed)
typoRate: 0.02 // Optional: typo probability (default: 0)
});

// Action.scroll parameters
await client.send("Action.scroll", {
deltaY: 500, // Vertical scroll distance (positive = down)
deltaX: 0, // Optional: horizontal scroll distance
duration: 1.5 // Scroll animation duration in seconds
});

Direct Selector Usage

Instead of calculating coordinates, you can use CSS selectors directly with Action.click and Action.moveTo:

# Click using CSS selector
await client.send("Action.click", {
"selector": "button[type='submit']"
})

# Move to element using CSS selector
await client.send("Action.moveTo", {
"selector": "#menu-item"
})

# Click with additional options
await client.send("Action.click", {
"selector": "button.primary-btn",
"button": "left"
})

# Move to element with duration
await client.send("Action.moveTo", {
"selector": "a.nav-link",
"duration": 0.8
})