agent()is gone. Nothing in v4 replaces it one-for-one.- The SDK surface moved. Construction, page access, and result shapes changed.
act(), extract(), and observe() still exist and still take natural-language instructions, but their place has changed.
Why agent() is gone
agent() was built for models that couldn’t reliably drive a browser on their own. It wrapped act(), extract(), and observe() in a loop and asked the model to pick one tool per step, which was the right shape for the models available at the time.
Now, that built-in orchestrator is gone. v4 exposes discrete tools and leaves the control flow to you. Keep calling act(), extract(), and observe() where a natural-language instruction beats a selector, but stop treating them as the whole toolset you hand a model.
Two approaches replace it:
- Code mode puts the model in front of the run. A coding assistant writes a Stagehand script, and you run that script. Browserbase recommends starting here.
- Tool calling keeps a model in the loop during the run, driving the browser through the full Stagehand API as its tools.
Code mode
Ask your coding assistant to write a Stagehand script, then run the script. The model writes the code once instead of driving the browser on every run. You get ordinary code: reviewable, diffable, and free of per-step inference. When a site changes, re-run the assistant on the step that broke. Start with AI rules. It carries the rule files and MCP servers that keep generated code on the v4 API instead of the v2 and v3 patterns in training data. Here’s a prompt that produces a working script:- TypeScript
- Python
- Go
page.locator() and page.goto() wherever a selector is stable, and spend a model call only where the page needs judgement. agent() couldn’t make that split, because every step it ran was an inference call.
Tool calling
To keep a model in the loop at runtime, give it the whole Stagehand surface rather than three broad tools. Each method maps to one tool with a narrow contract, so a step names a specific browser operation instead of routing through a sentence of English. Expose the real API:page.snapshot() anchors the loop. It returns formattedTree, the accessibility tree, plus an xpathMap, so the model reads real page structure and hands back a selector you can drive deterministically.
- TypeScript
- Python
- Go
Let a coding assistant do the rest
The rest of this guide is a mapping table, so hand it to a coding assistant. Point it at this page instead of retyping the rules:Recommended migration order
- Get one script constructing and closing cleanly on v4, before changing any instructions.
- Replace page and context access, since it moved.
- Unwrap results: every primitive now returns
{ data, metadata }. - Replace
agent()calls with code mode or tool calling. - Turn on server-side caching once the flow is stable.
Coming from Python or Go
v3 shipped Python and Go as clients for the hosted Stagehand API. You created a session and called methods on it. Python:act(), extract(), and observe() on that instance. Sessions and their IDs are gone from the calling surface, and the package names changed, so this is a rewrite against the new shape rather than a rename pass. The code mode examples show the target in each language.
Breaking changes
These diffs are TypeScript, because v3’s TypeScript SDK is the one whose surface maps onto v4 rename by rename. The v4 side of each diff is the shape for every language.Initialization
The constructor is private andinit() is gone. Get a browser from a factory, then hand it to Stagehand.create():
localBrowser.launch() for a browser on your machine, and localBrowser.connect({ cdpUrl }) or browserbase.connect({ apiKey, sessionId }) to attach to one that’s already running. Stagehand closes only the browsers it launched, so call browser.close() yourself. See browser configuration.
Pages and the browser context
The context moved off the Stagehand instance and onto the browser handle, and page lookups are now async:stagehand.browser.context.
act(), extract(), and observe() moved to the instance
In v3 these hung off the page. In v4 they’re top-level methods on Stagehand, and you pick the target page withoptions.page when it isn’t the active one:
Every primitive returns data and metadata
act(), extract(), and observe() return { data, metadata }. Your value is on data; metadata carries the action ID, cache status, and token usage.
extract() takes positional arguments
extract() with no schema returns { extraction: string }.
Model configuration
modelName and modelClientOptions collapse into one model object:
model entirely on a Browserbase browser and the Model Gateway picks one for you. Pass the same shape to a single call to override it there. See models.
Caching
enableCaching is gone. v4 caches act(), observe(), and extract() results on Browserbase’s servers instead, keyed on the instruction, page content, and options:
browserbase.launch(). See caching.
Logging
verbose and logger become one logging object with a level, a format, and a callback:
debug, info, warn, error, and off. See logging.
Metrics
Metrics became a method:The Browserbase session ID
stagehand.browserbaseSessionID is gone. Create the session yourself when you need its ID, then attach:
deepLocator() folded into locator()
page.deepLocator() is gone, but its behavior isn’t. page.locator() resolves the same selectors in v4, so drop the call and keep the selector:
>> hop notation and deep XPath such as /html/body/iframe[2]//div work unchanged. See Locator.
Quick reference
Troubleshooting
Constructor of class 'Stagehand' is private. Use await Stagehand.create({ browser }).
Property 'context' does not exist on type 'Stagehand'. The context lives on the browser handle: browser.context, or stagehand.browser.context.
Property 'act' does not exist on type 'Page'. act(), extract(), and observe() are methods on the Stagehand instance now. Target a specific tab with options.page.
Property 'length' does not exist on an observe() result. Read .data first.
Your generated script uses v3 APIs. The assistant is drawing on v2 and v3 patterns in its training data. Install the rule files from AI rules.
Property 'deepLocator' does not exist on type 'Page'. Rename the call to page.locator(). The selector stays the same.
A retried step repeats a side effect. You’re retrying act(). Retry observe() instead and pass the resulting action to act() once.
Next steps
AI rules
Set your coding assistant up to write v4 code
Act
Perform one action, or replay an observed one
Observe
Plan actions without performing them
Caching
Cut inference out of a stable flow

