When Automation Has to Behave Like a User

For CloakBrowser, humanize=True addresses a different identity surface from the patched Chromium binary: the sequence of actions a page can observe over time. This chapter focuses on what the wrapper actually changes in mouse movement, keyboard input, scrolling, and API dispatch, so a reader can distinguish behavioral plausibility from a claim that the browser has become human. The distinction matters because a slower action is not necessarily a more convincing action, and a convincing action is not necessarily correct or authorized.

Mouse, keyboard, and scroll are event sequences

A normal Playwright call often describes an outcome: click this element, fill this field, or scroll until that content is visible. The browser automation layer may reach that outcome with a compact sequence of low-level events. CloakBrowser’s humanize layer expands the sequence. It stores the original Playwright methods, keeps shared cursor state, and replaces selected interactions with movement, pauses, focus checks, and input events that are intended to resemble ordinary use.

Mouse movement is the clearest example. Instead of teleporting the pointer from its current coordinates to the middle of a target, the wrapper computes an aim point inside the target’s bounding box. Inputs receive a left-biased horizontal point and a wider vertical range; buttons receive a more central point. The choice is randomized within those regions, so repeated actions do not always land on the same pixel.

The path to that point is a cubic Bézier curve. The wrapper chooses two control points along the straight line between the cursor and the target, then shifts them perpendicular to that line. The result bends rather than following a perfectly straight segment. Each step is passed through an ease-in/ease-out function, which changes the speed across the path, and a small wobble is added around the curve. The points are emitted in bursts separated by short pauses. Sometimes the cursor goes slightly beyond the target and corrects back. These details matter because a detector can observe not just where a click lands, but the distribution of motion, speed changes, pauses, and corrections that precede it.

The wrapper also distinguishes between aiming and pressing. It waits for an input- or button-specific delay, sends a mouse-down event, holds for a randomized interval, and then sends mouse-up. The timing parameters are centralized in a configuration object rather than scattered across individual methods. That gives the project one place to tune the behavior and makes the same algorithm available to page, locator, frame, and element-handle paths.

Keyboard input is treated as a sequence rather than a string assignment. The humanized type operation processes characters one at a time, waits between them, and occasionally inserts a longer thinking pause. The default configuration includes a small chance of an ASCII alphanumeric typo: a nearby QWERTY key is pressed, a notice delay passes, Backspace is sent, and the intended character is typed.