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 clicksAction.moveTo
- Moves mouse cursor naturally to coordinatesAction.type
- Types text with realistic typing patterns and speedAction.scroll
- Scrolls page with smooth, natural motion
Examples
Complete Search Automation
- Python
- JavaScript
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})
async function searchExample(page) {
// Create CDP session for human-like actions
const client = await page.context().newCDPSession(page);
await page.goto('https://duckduckgo.com', { waitUntil: 'load' });
// Wait for search input to be ready
await page.waitForSelector('input[name="q"]');
// Get search box coordinates
const searchBox = await page.locator('input[name="q"]').boundingBox();
const x = searchBox.x + searchBox.width / 2;
const y = searchBox.y + searchBox.height / 2;
// Click on search box with human-like precision
await client.send('Action.click', { x, y, button: 'left' });
// Type search query
await client.send('Action.type', { text: 'Surfsky cloud browser' });
// Get submit button coordinates
const clickBox = await page.locator('button[type="submit"]').boundingBox();
const btnX = clickBox.x + clickBox.width / 2;
const btnY = clickBox.y + clickBox.height / 2;
// Move mouse naturally to submit button
await client.send('Action.moveTo', { x: btnX, y: btnY });
// Click submit button
await client.send('Action.click', { x: btnX, y: btnY, button: 'left' });
// Wait for results to load
await page.waitForSelector('.results');
// Scroll down naturally
await client.send('Action.scroll', { deltaY: 500, duration: 1.5 });
}
Form Filling with Natural Behavior
- Python
- JavaScript
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)
async function fillFormNaturally(page, client) {
// Form fields with typing speeds
const 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 (const field of fields) {
// Get element position
const element = await page.locator(field.selector).boundingBox();
const x = element.x + element.width / 2;
const y = element.y + element.height / 2;
// Move to field
await client.send('Action.moveTo', { x, y });
// Click to focus
await client.send('Action.click', {
x,
y,
button: 'left'
});
// Type with specified speed
await client.send('Action.type', {
text: field.text,
wpm: field.wpm
});
// Natural pause between fields
await page.waitForTimeout(500);
}
}
Scrolling and Navigation
- Python
- JavaScript
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
})
async function navigatePage(page, client) {
// Smooth scroll down
await client.send('Action.scroll', {
deltaY: 300,
duration: 1.0 // 1 second smooth scroll
});
// Scroll to element
const element = await page.locator('.target-section').boundingBox();
const currentPosition = await page.evaluate('window.pageYOffset');
const scrollDistance = element.y - currentPosition - 100; // 100px offset
await client.send('Action.scroll', {
deltaY: scrollDistance,
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
:
- Python
- JavaScript
# 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
})
// 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
});