Skip to content

Commit 88f9e25

Browse files
committed
feat: Implement humanized keyboard typing and physics-based scroll, and add iframe interaction support.
1 parent ed5d3ff commit 88f9e25

File tree

15 files changed

+1532
-1806
lines changed

15 files changed

+1532
-1806
lines changed

docs/en/deep-dive/fingerprinting/behavioral-fingerprinting.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ This three-level interpolation produces the same result but avoids high-power po
368368
- **[Pyautogui](https://pyautogui.readthedocs.io/)**: Basic tweening (easily detectable)
369369
- **[Humanize.js](https://github.com/HumanSignal/label-studio-frontend/blob/master/src/utils/utilities.js)**: Advanced composite curves
370370

371+
!!! success "Pydoll Implementation"
372+
Pydoll implements **Cubic Bezier curves** for its scroll engine, ensuring that all scroll movements follow natural acceleration and deceleration profiles. This is combined with random jitter, micro-pauses, and overshoot correction to defeat advanced behavioral analysis.
373+
371374
### Mouse Movement Entropy
372375

373376
**What is Entropy in This Context?**
@@ -708,6 +711,13 @@ def simulate_human_typing(text: str) -> List[Tuple[str, str, float]]:
708711

709712
These studies show keystroke dynamics can achieve **95%+ authentication accuracy** with as few as 50-100 keystrokes.
710713

714+
!!! success "Pydoll Implementation"
715+
Pydoll's `type_text(humanize=True)` automatically handles keystroke dynamics by:
716+
717+
1. **Variable Intervals**: Using a bell curve distribution for inter-key timings.
718+
2. **Typo Simulation**: Intentionally making mistakes based on keyboard layout proximity (e.g., pressing 's' instead of 'a').
719+
3. **Correction Logic**: Simulating the backspace sequence to correct typos, adding to the "human" noise.
720+
711721
### The "Paste Detection" Problem
712722

713723
One of the easiest bot indicators is **text insertion without keyboard events**:
@@ -962,6 +972,14 @@ def simulate_human_scroll(target_distance: int, direction: int = 1) -> List[Tupl
962972

963973
This is implemented in browsers' smooth scrolling via CSS `scroll-behavior: smooth` using **bezier easing functions**.
964974

975+
!!! success "Pydoll Implementation"
976+
Pydoll's scroll engine is built on top of these physics principles. When you use `scroll.by(..., humanize=True)`, it:
977+
978+
1. Calculates a **Cubic Bezier** trajectory for the scroll.
979+
2. Applies **momentum** and **friction** to the velocity profile.
980+
3. Injects **random jitter** to the delta values.
981+
4. Adds **micro-pauses** and **overshoot** behavior to mimic human imperfection.
982+
965983
## Event Sequence Analysis
966984

967985
Beyond individual actions, anti-bot systems analyze the **sequence and timing** of events. Humans follow predictable interaction patterns, while bots often skip steps or execute them in unnatural orders.

docs/en/features/automation/human-interactions.md

Lines changed: 69 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22

33
One of the key differentiators between successful automation and easily-detected bots is how realistic the interactions are. Pydoll provides sophisticated tools to make your automation virtually indistinguishable from human behavior.
44

5-
!!! warning "Future Enhancements"
6-
Pydoll is continuously improving its human-like interaction capabilities. Future versions will include:
5+
!!! info "Feature Status"
6+
**Already Implemented:**
77

8-
- **Variable typing speed**: Built-in random intervals between keystrokes to eliminate the need for manual randomization
9-
- **Realistic keyboard sequences**: Automatic simulation of typing mistakes, backspacing, corrections, and dynamic pauses for maximum realism
10-
- **Automatic random click offsets**: Optional parameter to automatically randomize click positions within elements, eliminating manual offset calculations
11-
- **Mouse movement simulation**: Realistic cursor paths with bezier curves
12-
- **Mouse delta events**: Natural acceleration and deceleration patterns
13-
- **Hover behavior**: Realistic delays and movement when hovering
14-
- **Timing variations**: Randomized delays to avoid predictable patterns
8+
- **Humanized Keyboard**: Variable typing speed, realistic typos with auto-correction (`humanize=True`)
9+
- **Humanized Scroll**: Physics-based scrolling with momentum, friction, jitter, and overshoot (`humanize=True`)
1510

16-
These features leverage CDP and JavaScript capabilities for maximum realism.
11+
**Coming Soon:**
12+
13+
- **Realistic Mouse Movement Module**: Bezier curve-based mouse paths with natural acceleration/deceleration, overshoot, and correction
14+
- **Automatic random click offsets**: Optional parameter to automatically randomize click positions within elements
15+
- **Hover behavior**: Realistic delays and movement when hovering over elements
1716

1817
## Why Human-Like Interactions Matter
1918

@@ -160,12 +159,19 @@ asyncio.run(click_methods_comparison())
160159

161160
## Realistic Text Input
162161

163-
### Natural Typing with Intervals
162+
Pydoll's keyboard API provides two typing modes to balance speed and stealth.
163+
164+
!!! info "Understanding Typing Modes"
165+
| Mode | Parameters | Behavior | Use Case |
166+
|------|------------|----------|----------|
167+
| **Default** | `humanize=False` | Fixed 50ms intervals, no typos | Speed-critical, low-risk scenarios |
168+
| **Humanized** | `humanize=True` | Variable timing, ~2% typo rate with auto-correction | **Anti-bot evasion** |
169+
170+
The `interval` parameter is deprecated. Use `humanize=True` instead.
164171

165-
The `type_text()` method simulates human typing by sending individual keystrokes. The `interval` parameter adds a **fixed delay** between each keystroke.
172+
### Natural Typing with Humanization
166173

167-
!!! info "Current State: Manual Randomization Required"
168-
Currently, the `interval` parameter uses a **constant delay** for all characters. For maximum realism, you need to manually randomize typing speeds (as shown in the advanced examples below). Future versions will include automatic variable typing speed with built-in randomization.
174+
Use `humanize=True` to simulate realistic human typing with variable speeds and occasional typos that are automatically corrected:
169175

170176
```python
171177
import asyncio
@@ -178,13 +184,11 @@ async def natural_typing():
178184

179185
username_field = await tab.find(id="username")
180186
password_field = await tab.find(id="password")
181-
182-
# Type with fixed intervals (currently)
183-
# Average human typing: 0.1-0.3 seconds per character
184-
await username_field.type_text("[email protected]", interval=0.15)
185-
186-
# Slower typing for complex passwords
187-
await password_field.type_text("MyC0mpl3xP@ssw0rd!", interval=0.12)
187+
188+
# Variable speed: 30-120ms between keystrokes
189+
# ~2% typo rate with realistic correction behavior
190+
await username_field.type_text("[email protected]", humanize=True)
191+
await password_field.type_text("MyC0mpl3xP@ssw0rd!", humanize=True)
188192

189193
asyncio.run(natural_typing())
190194
```
@@ -202,19 +206,16 @@ async def fast_vs_realistic_input():
202206
tab = await browser.start()
203207
await tab.go_to('https://example.com/form')
204208

205-
# Realistic typing for visible fields
206209
username = await tab.find(id="username")
207210
await username.click()
208-
await username.type_text("john_doe", interval=0.12)
211+
await username.type_text("john_doe", humanize=True)
209212

210-
# Fast insertion for hidden or backend fields
211213
hidden_field = await tab.find(id="hidden-token")
212214
await hidden_field.insert_text("very-long-generated-token-12345678")
213215

214-
# Realistic typing for fields that matter
215216
comment = await tab.find(id="comment-box")
216217
await comment.click()
217-
await comment.type_text("This looks like human input!", interval=0.15)
218+
await comment.type_text("This looks like human input!", humanize=True)
218219

219220
asyncio.run(fast_vs_realistic_input())
220221
```
@@ -226,6 +227,17 @@ asyncio.run(fast_vs_realistic_input())
226227

227228
Pydoll provides a dedicated scroll API that waits for scroll completion before proceeding, making your automations more realistic and reliable.
228229

230+
!!! info \"Understanding Scroll Modes\"
231+
Pydoll's scroll API offers **three distinct modes**:
232+
233+
| Mode | Parameters | Behavior | Use Case |
234+
|------|------------|----------|----------|
235+
| **Instant** | `smooth=False` | Teleports to position immediately | Speed-critical operations |
236+
| **Smooth** | `smooth=True` (default) | CSS-based animation, predictable | General browsing simulation |
237+
| **Humanized** | `humanize=True` | Physics engine with momentum, jitter, overshoot | **Anti-bot evasion** |
238+
239+
For bypassing behavioral fingerprinting, always use `humanize=True`.
240+
229241
### Basic Directional Scrolling
230242

231243
Use the `scroll.by()` method to scroll the page in any direction with precise control:
@@ -240,27 +252,24 @@ async def basic_scrolling():
240252
tab = await browser.start()
241253
await tab.go_to('https://example.com/long-page')
242254

243-
# Scroll down 500 pixels (with smooth animation)
244-
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
255+
# Teleports instantly - fastest but easily detectable
256+
await tab.scroll.by(ScrollPosition.DOWN, 1000, smooth=False)
245257

246-
# Scroll up 300 pixels
258+
# CSS-based animation - looks nice but predictable timing
259+
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
247260
await tab.scroll.by(ScrollPosition.UP, 300, smooth=True)
248-
249-
# Scroll right (useful for horizontal scroll pages)
250-
await tab.scroll.by(ScrollPosition.RIGHT, 200, smooth=True)
251-
252-
# Scroll left
253-
await tab.scroll.by(ScrollPosition.LEFT, 200, smooth=True)
254-
255-
# Instant scroll (no animation)
256-
await tab.scroll.by(ScrollPosition.DOWN, 1000, smooth=False)
261+
262+
# Physics engine with Bezier curves - most realistic
263+
# Includes: momentum, friction, jitter, micro-pauses, overshoot
264+
await tab.scroll.by(ScrollPosition.DOWN, 500, humanize=True)
265+
await tab.scroll.by(ScrollPosition.UP, 300, humanize=True)
257266

258267
asyncio.run(basic_scrolling())
259268
```
260269

261270
### Scrolling to Specific Positions
262271

263-
Navigate quickly to the top or bottom of the page:
272+
Navigate to the top or bottom of the page with control over realism:
264273

265274
```python
266275
import asyncio
@@ -274,28 +283,34 @@ async def scroll_to_positions():
274283
# Read the beginning of the article
275284
await asyncio.sleep(2.0)
276285

277-
# Smoothly scroll to the bottom
286+
# Option 1: Smooth scroll (CSS animation, predictable)
278287
await tab.scroll.to_bottom(smooth=True)
279-
280-
# Pause at the bottom
281288
await asyncio.sleep(1.5)
282-
283-
# Return to the top
284289
await tab.scroll.to_top(smooth=True)
290+
291+
# Option 2: Humanized scroll (physics engine, anti-bot evasion)
292+
await tab.scroll.to_bottom(humanize=True)
293+
await asyncio.sleep(1.5)
294+
await tab.scroll.to_top(humanize=True)
285295

286296
asyncio.run(scroll_to_positions())
287297
```
288298

289-
!!! tip "Smooth vs Instant"
290-
- **smooth=True**: Uses browser's smooth animation and waits for `scrollend` event
291-
- **smooth=False**: Instant scrolling for maximum speed when realism isn't critical
299+
!!! tip "Choosing the Right Mode"
300+
- **`smooth=True`**: Good for demos, screenshots, and general automation
301+
- **`humanize=True`**: Essential when facing behavioral fingerprinting or bot detection
302+
- **`smooth=False`**: Maximum speed when stealth is not a concern
292303

293304
### Human-Like Scrolling Patterns
294305

295-
!!! info "Future Enhancement: Built-in Realistic Scrolling"
296-
Currently, you must manually implement random scrolling patterns. Future versions will include a `realistic=True` parameter that automatically adds natural variations in scroll distances, speeds, and pauses to mimic human reading behavior.
306+
Pydoll's scroll engine uses **Cubic Bezier curves** to simulate the physics of human scrolling. This includes:
297307

298-
Simulate natural reading and navigation behavior:
308+
- **Momentum**: Initial burst of speed followed by gradual deceleration.
309+
- **Friction**: Natural slowing down based on "physical" resistance.
310+
- **Micro-pauses**: Brief stops during long scrolls, mimicking reading or eye movement.
311+
- **Overshoot**: Occasional scrolling past the target and correcting back.
312+
313+
This behavior is automatically enabled when you use `humanize=True`.
299314

300315
```python
301316
import asyncio
@@ -313,24 +328,25 @@ async def human_like_scrolling():
313328
await asyncio.sleep(random.uniform(2.0, 4.0))
314329

315330
# Gradually scroll while reading
331+
# The scroll engine handles the physics (acceleration/deceleration)
316332
for _ in range(random.randint(5, 8)):
317333
# Varied scroll distances (simulates reading speed)
318334
scroll_distance = random.randint(300, 600)
319335
await tab.scroll.by(
320336
ScrollPosition.DOWN,
321337
scroll_distance,
322-
smooth=True
338+
humanize=True # Enables Bezier curve physics
323339
)
324340

325341
# Pause to "read" content
326342
await asyncio.sleep(random.uniform(2.0, 5.0))
327343

328344
# Quick scroll to check the end
329-
await tab.scroll.to_bottom(smooth=True)
345+
await tab.scroll.to_bottom(humanize=True)
330346
await asyncio.sleep(random.uniform(1.0, 2.0))
331347

332348
# Scroll back to top to re-read something
333-
await tab.scroll.to_top(smooth=True)
349+
await tab.scroll.to_top(humanize=True)
334350

335351
asyncio.run(human_like_scrolling())
336352
```

docs/pt/deep-dive/fingerprinting/behavioral-fingerprinting.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ Essa interpolação de três níveis produz o mesmo resultado, mas evita polinô
368368
- **[Pyautogui](https://pyautogui.readthedocs.io/)**: Interpolação básica (facilmente detectável)
369369
- **[Humanize.js](https://github.com/HumanSignal/label-studio-frontend/blob/master/src/utils/utilities.js)**: Curvas compostas avançadas
370370

371+
!!! success \"Implementação Pydoll\"
372+
O Pydoll implementa **Curvas de Bezier Cúbicas** para seu motor de scroll, garantindo que todos os movimentos de rolagem sigam perfis naturais de aceleração e desaceleração. Isso é combinado com jitter aleatório, micro-pausas e correção de overshoot para derrotar análise comportamental avançada.
373+
371374
### Entropia do Movimento do Mouse
372375

373376
**O que é Entropia neste Contexto?**

0 commit comments

Comments
 (0)