Browser agents: how a language model drives a real browser
· 10 min read
Perception, action spaces, settling, verification and safety boundaries — how an agent operates a browser, and why a real browser beats a headless scraper.
· 9 min read · Lobster Browser team
“Agent” has become one of those words that means whatever the speaker needs it to mean. It is used for a customer-support chatbot, for a script that calls a model in a loop, and for a system that files pull requests without a person watching. That vagueness is expensive: teams argue about the wrong things, buy the wrong tools, and measure nothing.
This post is an attempt to be concrete. By the end you should be able to describe any “agentic” product in terms of four things — its action space, its loop, its memory and its evaluation — and to recognize the ways these systems break.
A chat model is a function. Text goes in, text comes out, and the surrounding program does nothing except display the result. Everything the model can affect is inside its own reply. That is a useful shape for drafting, explaining and summarizing, and it is why the first wave of products were writing tools.
An agent is a loop around that function. The program gives the model a goal and a set of things it may do. The model proposes an action; the program performs it; the result is appended to the conversation; the model is called again. Nothing about the model itself is different. What is different is that its output is now interpreted as an instruction to the world rather than as prose for a person.
goal, tools, budget -> loop:
state = history + observations
action = model(state, tools) # a tool call, or "done"
if action is "done": return answer
result = execute(action) # the only step that touches the world
history = history + [action, result]
budget = budget - cost(action)Everything interesting follows from that one structural change. Errors compound instead of being visible in a single reply. Latency is the sum of many calls rather than one. Cost is unbounded unless someone bounds it. And a mistake can now be a deleted file rather than a wrong sentence.
The single largest practical change is that models became reliable at emitting structured calls against a declared schema, and that the surrounding runtimes became good at validating and executing them. A tool is a name, a description, a typed parameter schema and a function. The model never runs code; it writes a request, and the program decides whether to honor it.
{
"name": "search_orders",
"description": "Find orders for one customer. Read-only.",
"parameters": {
"type": "object",
"properties": {
"customer_id": { "type": "string" },
"since": { "type": "string", "format": "date" }
},
"required": ["customer_id"]
}
}Tool descriptions are prompt text, and they are read far more often than they are written. Most failures that look like reasoning failures are description failures: two tools whose descriptions overlap, a parameter whose meaning is obvious to the author and ambiguous to everyone else, an error message that says “invalid request” and gives the model nothing to correct. Treat the tool surface as an API designed for a careful but literal reader who cannot ask you a question.
A second change is standardization: tool interfaces are increasingly described in a common protocol, so a connector becomes a thing you install rather than a thing you write.
Early agent frameworks made planning a separate, visible stage: produce a numbered plan, then execute it step by step. In practice that is brittle. A plan written before the first observation is a guess, and executing a stale guess is worse than reacting to what is actually on the screen.
What works better is interleaving: the model reasons briefly, acts, observes, and revises. The plan exists, but it lives in the conversation rather than in a data structure. Explicit plans still earn their place when a human must approve the work first, and when a task is long enough that the model needs a written record of intent.
“Memory” gets used for three distinct mechanisms with different failure modes. Keeping them apart makes design arguments much shorter.
| Kind | What it holds | Typical failure |
|---|---|---|
| Working context | The current conversation: goal, actions taken, observations | Overflow. The oldest and most important instruction falls off the end, or a summarization step quietly drops the constraint that mattered. |
| Retrieval | Documents and records fetched on demand from a store | Retrieving plausibly related text instead of the passage that answers the question, then reasoning confidently over it. |
| Durable state | Facts the system chooses to keep across sessions: preferences, prior decisions, identifiers | Staleness and contamination. A fact learned once is applied forever, including after it stops being true. |
Longer context windows have made working context less of a daily constraint, but not a free one: attention over a very long context is not uniform, and a model given fifty pages of history will sometimes answer from page two. The discipline is unchanged — put the goal and the constraints where they cannot be crowded out, keep observations terse, and summarize deliberately rather than by truncation.
The most consistent difference between teams whose agents improve and teams whose agents do not is whether they built an evaluation set before they started tuning prompts. Without one, every change is judged by whether the last demo felt better, which is a measurement with enormous variance and a strong bias toward whoever is talking.
Model-graded evaluation is useful for the parts that resist programmatic checks and dangerous when it is the only signal: judges have preferences, for longer answers and for confident tone. Anchor them with rubrics and human-labeled examples, and never tune against a judge you have not audited.
A loop that can act needs limits enforced by the program, not requested in the prompt: instructions are a preference, permissions are a guarantee. The question is not “how do we stop the model doing the wrong thing” but “what is the worst this credential can do, and is that acceptable unattended?”
Reading a few hundred failed transcripts is more educational than any benchmark. The same shapes recur.
Two have cheap fixes. Silent success is answered by verification: after a write, read it back and compare against the intent. Loops are answered by detection: if the last two observations are identical, stop and escalate.
Task success rate is the headline, and it hides the numbers that decide whether a system is usable. Track these together, per task type, and look at the distribution rather than the mean.
| Measure | Why it matters |
|---|---|
| Task success rate | The only number that maps to user value. Define success per task type, not globally. |
| Steps per task | Rises before success falls. A quiet increase usually means the environment changed. |
| Cost per successful task | Cost per run flatters a system that fails cheaply. |
| Time to first useful output | Decides whether a person waits or leaves. |
| Escalation rate | How often a human is asked. Falling to zero is usually a bad sign, not a good one. |
| Unsafe-action attempts | Blocked attempts are a signal about the prompt and the tool surface, and should be reviewed, not just counted. |
What changed is not that models started to think. It is that they became dependable enough at emitting structured actions to be worth putting inside a loop with real permissions — and that the surrounding engineering caught up enough to make that loop survivable.
So when you next meet a system described as agentic, ask the four questions. What can it do — the action space. How does it decide — the loop and its budget. What does it remember — and which of the three memories is that. How do you know it works — the evaluation set and the transcripts. A system whose owners can answer all four is engineering. A system whose owners can answer none of them is a demonstration.
Named rather than linked, on purpose: specifications move and URLs rot, while a title and an author survive a search.
· 10 min read
Perception, action spaces, settling, verification and safety boundaries — how an agent operates a browser, and why a real browser beats a headless scraper.
· 10 min read
A framework for model selection: capability axes, what benchmarks can and cannot show, latency and cost, reasoning modes, and open-weight versus hosted.
· 10 min read
How anti-detect browsers work: JavaScript overlays versus native engine changes, farbling, per-profile stability, and how to evaluate one honestly.
· 10 min read
What a browser fingerprint is, which surfaces it is built from, why entropy and stability both matter, and why an incoherent disguise is worse than none.