Back to blog

Three Generations of Browser Automation: Input Simulation, Protocol Control, and Model Decisions

Browser automation has gone through three generations. Each solved the previous generation’s bottleneck while moving the next bottleneck elsewhere. Understanding what each generation leaves unresolved is more useful than memorizing tool names.

Browser automation has been around for more than two decades, and its dominant approach has changed three times. What is interesting is that each generation solves a different class of problems, and once it does, the bottleneck simply moves somewhere else.

浏览器自动化三代路线:输入模拟、协议驱动与模型决策的关键步骤与判断维度示意图

Generation One: Pretending Someone Is Moving the Mouse at the Operating-System Level

The earliest automation did not really happen inside the browser at all. It operated at the operating-system level. A script moved the mouse and pressed keys, while the browser merely received those inputs.

The advantage was universality: if something appeared on the screen, the script could interact with it, whether it was a web page, a client application, or old desktop software, and the browser did not need to expose any interface. The cost was equally direct. The script recognized screen coordinates, so a change in resolution, a system-scaling adjustment, or a moved window could make the same action click the wrong place. It also had no idea whether the page had actually finished loading, so it had to rely on fixed waits. Parallelism was even harder: one machine had only one mouse and keyboard, so ten environments meant ten machines.

The problem this generation left behind was simple: it could not see the page.

Generation Two: Bypassing the Screen and Talking Directly to the Browser

WebDriver moved automation from the pixel level to the element level: it looked for a particular element on the page instead of the position at pixel 800 on the screen. The same code could drive different browsers and be written in different languages, which is also why it later became a standard in testing.

Later, approaches based on browser debugging protocols took this path much further. The Puppeteer and Playwright family communicates directly with the browser engine and can access internal page state: automatically waiting for elements to be ready, intercepting and rewriting requests, connecting to an already-running browser instance, running headlessly, and opening multiple contexts in parallel. Most capabilities that now feel routine were filled in during this stage.

It solved control and stability but left two other problems. First, scripts were still hard-coded by people. When page structure changed or a selector stopped working, someone had to edit the code, so maintenance costs rose with project size. The second problem was more fundamental: it handled how to operate, not who the activity appeared to come from. Direct protocol control made operation more precise, but changing the communication method did not erase the traces left by automation. Even a highly stable script could still look like a script to others.

Generation Three: People Stop Writing Every Step, and the Problem Moves Again

The third generation changes the decision process rather than the control method. The first two generations required people to specify every step: which button to click, which field to fill in, and in what order. In the model-driven generation, you provide a goal, the model plans the path, and it can find a new entry point when the page is redesigned.

As a result, old details such as how to write selectors or how long to wait gradually become less critical. New problems appear immediately, however.

The key point is that the model itself does not access the web page. The browser still opens the page, loads resources, and maintains the login state. So when a task becomes unstable, the cause is often not that the model made the wrong decision, but the execution environment beneath it: multiple tasks share one browser and contaminate each other’s cookies and cache; fingerprint characteristics are highly similar, making the platform see all those tasks as coming from the same machine; accounts are reused across tasks, so one anomaly affects many others; environments need to be created temporarily and reclaimed afterward, but there is no unified scheduling. The model solves how to do the task and turns where to do it into the bottleneck.

The Extra Layer Added to the Architecture

Looking at all three generations together, the difference is not simply that one is more advanced than another. Each generation has to pick up what the previous one failed to handle. In the first two generations, the environment was not much of a problem because automation ran in the browser on your own machine. At the Agent stage, tasks are batched, concurrent, and unattended, so environments have to be managed explicitly: each task runs in an isolated environment, with fingerprints and sessions kept separate; login state persists across tasks so repeated logins are unnecessary; IP, time zone, and language are matched as a set; and environments are created and reclaimed on demand like computing resources.

PurpleMark operates at this layer, turning browser environments into schedulable resources so the Agent can focus on task logic.

That also makes the choice easier to frame. Enterprise testing stacks and existing script assets can stay on their current path; complex web applications that need request-level control fit the protocol-driven generation; and for tasks planned by a model that also need to run reliably over time, the technologies from the first two generations can still be used, but the environment layer must be solved separately. If your scenario needs the operation to look like it comes from a real user, that is not something an automation framework can provide by itself, regardless of generation.

There is also a boundary beyond the technical path: automation must follow the target platform’s rules and local laws. Something being technically possible does not necessarily make it appropriate for the business.