LmCast :: Stay tuned in

The bitter lesson of browser agents

Recorded: Sept. 15, 2026, 4:32 p.m.

Original Summarized

The Bitter Lesson of Browser AgentsBrowser UseAgentsBrowsersShowcaseResourcesPricing115kLog inStart for freeAll articlesEngineering/September 15, 2026The Bitter Lesson of Browser AgentsAs models get better, the browser harness has to change. A lot.Gregor ZunicCo-founder, CTOCopy linkIn this articleDefining state and action spaceReplacing fixed actions with codeThe limits of predefined stateRemoving predefined stateWhy CDP, not Playwright?A simple browser harnessWhat is actually the bitter lesson here?In this articleDefining state and action spaceReplacing fixed actions with codeThe limits of predefined stateRemoving predefined stateWhy CDP, not Playwright?A simple browser harnessWhat is actually the bitter lesson here?
When we launched Browser Use in November 2024, GPT-4o wasn't trained for computer use. Built on next-token prediction, it didn't reliably understand what it could do on a page. We had to spell it out.
As models got better at coding, we moved from predefined state and actions to code: first the model wrote its actions, then its observations. Now it does both through raw CDP, inside an existing agent harness.
Defining state and action space
We defined the state: here's what's on the page, here's what's clickable. Then the action space: click, type, scroll. Every interaction had to fit those rules.
Our early loop: we chose what the model could see and do.
The model picked an action, we ran it and sent back the next state. But browser automation is a game of edge cases. Every exception needed another fix.
Replacing fixed actions with code
Models were getting much better at coding. We experimented with JavaScript execution in September 2025 and persistent notebooks in October. The model could write a program instead of picking actions.
Let it write the actions. Still our page state. Code is illustrative.
Drawing a signature or looping through comments no longer needed a new action. Variables persisted, so the model could inspect results and keep going.

Hermes agent replaced 12 browser tools with browser_exec, powered by our Browser Use CLI. Mean token use fell 60% for Opus 4.8 and 66% for Kimi K3. Both versions solved 18/18 runs per model (six tasks, three runs).

The limits of predefined state
We'd opened up the actions, but we still decided what the model could see. That became the next problem.
A cookie button can be right there on the screen and missing from the state we send. Maybe the accessibility tree doesn't expose it, or our processing drops it. Either way, the model never sees the button.
The button is there. We just failed to show it.
An EHR dropdown might look like this (simplified DevTools tree):
<ehr-app>
#shadow-root (open)
<iframe src="https://ui.example">
#document <!-- other origin -->
<dropdown-menu>
#shadow-root (closed)
<button>Choose...</button>
Our state heuristics couldn't anticipate every website. We'd given the model freedom to act, but it was still looking through our assumptions.
Removing predefined state
What if we let it write the observations, too?
We gave the LLM direct access to CDP, the Chrome DevTools Protocol. No mandatory list of clickable elements. It could write code to inspect the DOM, take a screenshot or look inside one frame.
The model chooses what to inspect. CDP commands are illustrative.
The browser still has state. What disappears is our requirement that everything fit one predefined representation. A screenshot might answer one question. A DOM query might answer the next. The model decides what it needs to see.
Why CDP, not Playwright?
CDP is Chrome's native control protocol. The model can use it directly.
For Chrome, CDP gives the model access beneath Playwright's browser API.
Playwright adds assumptions, such as locators that cannot see closed shadow roots. CDP can inspect those roots directly. Playwright also exposes CDP; we made direct access the default.
A simple browser harness
Pi, Codex and OpenCode already handle the agent loop. Coding agents have millions of users trying all sorts of work. That testing is a reason to reuse their harnesses.
An agent five hours into QA shouldn't fail because of a bug in the loop. We once hit compaction that produced so much context it immediately triggered compaction again. Our customers shouldn't have to discover those bugs.
We add a simple browser tool: persistent code, with text, screenshots and errors coming back to the model.
A CLI or tool call connects the agent to CDP.
From our Agent SDK in January 2026 to Browser Harness in April, this became the direction. Browser Harness, BrowserCode and Browser Use Pi take different approaches. All let the model choose what to see and do.
What is actually the bitter lesson here?
Sutton's bitter lesson favors general methods that improve with more computation. For us:

Reuse a proven agent harness.
Expose the simplest underlying interface the model can use well.
Let the model choose its observations and actions.

Browsers, computers, text, music: the same principle applies. As models change, rethink the harness.Published September 15, 2026Copy linkKeep readingAll articles Guides/Sep 14, 2026Playwright vs Selenium vs Puppeteer: Which To Use?In this article, we'll look at the most popular browser automation tools. We'll compare their use cases, performance, browser support, and language support.Nik TomazicGuides/Sep 7, 2026What is a Headless Browser?Learn what a headless browser is, how it compares to a headful one, its use cases, and the basics of browser automation.Nik TomazicAnnouncements/Sep 3, 2026Browser Use can now pay with your credit card using Stripe Link CLIYou can safely connect your credit card and purchase things with hosted browser agents.Gregor ZunicProductBrowser Use AgentsBrowser InfrastructureResourcesPricingDocumentationDevelopersOpen SourceBrowser HarnessOpenClawCustom ModelsProxiesBlogChangelogSolutionsRemote browser for PlaywrightCAPTCHA solvingAnti-detect browserBrowser for coding agentsMCP serverWeb agent APIForm fillingLogin automationShowcaseAll examplesWhat people runData extractionShopping & checkoutTravel & bookingTesting & QAResearchCompanies & jobsAgent workflowsSocial & outreachGames & real-timeCase studiesCompanyCareersEnterpriseSOC 2TermsPrivacyDPAContactCookie SettingsConnectGitHubTwitterLinkedInDiscordProductBrowser Use AgentsBrowser InfrastructureResourcesPricingDocumentationDevelopersOpen SourceBrowser HarnessOpenClawCustom ModelsProxiesBlogChangelogSolutionsRemote browser for PlaywrightCAPTCHA solvingAnti-detect browserBrowser for coding agentsMCP serverWeb agent APIForm fillingLogin automationShowcaseAll examplesWhat people runData extractionShopping & checkoutTravel & bookingTesting & QAResearchCompanies & jobsAgent workflowsSocial & outreachGames & real-timeCase studiesCompanyCareersEnterpriseSOC 2TermsPrivacyDPAContactCookie SettingsConnectGitHubTwitterLinkedInDiscordView as MarkdownCurrent view: website.↗System status© 2026 Browser UseAI agents and crawlers: read browser-use.com/llms.txt for the product map and llms-full.txt for full context.

As large language models improve, the approach to building browser agents must fundamentally change. Initially, when Browser Use was launched, models like GPT-4o were not inherently trained for computer interaction, necessitating an explicit definition of states and actions. This early iteration involved defining a fixed state space, such as specifying known clickable elements and actions like click or type, forcing the model to adhere to predefined rules for every interaction. The foundational loop was predicated on the model selecting an action, executing it, and receiving the resulting state. However, this system proved inadequate because browser automation is rife with edge cases, requiring constant exception handling.

A critical evolution involved replacing these fixed actions with executable code. As models gained stronger coding capabilities, the strategy shifted from selecting predefined actions to allowing the model to write its own actions and observe its results. By experimenting with JavaScript execution and persistent notebooks, models could generate programs rather than selecting discrete actions. This change allowed the model to handle complex tasks by persisting variables and inspecting results, eliminating the need for enumerating every possible action. This evolution led to significant efficiency gains, as demonstrated by agents utilizing browser execution tools, which substantially reduced token consumption.

The next challenge arose from the limitations of predefined state. Even when actions were opened up, defining the state remained a bottleneck. Assumptions made about the observable state, such as what information was exposed through the accessibility tree, often failed to capture crucial details, such as elements hidden by shadow roots or complex iframe structures. This created a scenario where the model could not perceive elements that were visually present but omitted from the defined state, meaning the agent failed to see necessary elements despite full freedom of action.

To overcome this, the approach shifted toward removing the enforced predefined state. This involved granting the large language model direct access to the Chrome DevTools Protocol (CDP). Instead of relying on pre-defined lists of interactable elements, the model gained the capability to write code to inspect the Document Object Model (DOM), take screenshots, or examine specific frames. The model autonomously decides what to observe and what to act upon, moving away from restrictive heuristics.

The choice of CDP over alternatives like Playwright stems from its nature as Chrome's native control protocol, allowing for direct access to the browser environment that is beneath Playwright's higher-level API. Playwright introduces inherent assumptions, such as locators that may fail to account for dynamic elements like closed shadow roots. CDP’s direct access allows the model to inspect these underlying structures directly, giving it richer situational awareness.

To manage the complexity of agent development, the imperative shifted toward creating a simple, reusable browser harness. This harness serves as a necessary infrastructure to manage the agent loop, ensuring reliability and mitigating the risk of unpredictable bugs within the agent's execution sequence. This infrastructure allows agents to leverage existing frameworks, as coding agents have been widely adopted. The core principle, consistent with Sutton's bitter lesson, is that general methods which improve with more computation should be favored. Therefore, the derived lesson is to reuse proven agent harnesses, expose the simplest underlying interface that the model can effectively utilize, and grant the model the autonomy to determine its observations and actions, a principle applicable across various domains involving computers, text, and multimedia.