The Browser Tool
A managed, isolated cloud browser your agent can drive
- Explain what AgentCore Browser is — the managed `aws.browser.v1` system browser vs a custom browser — and where it sits as one of the two built-in Tools
- Walk the four-step workflow: create a browser, start a session (default 15-min TTL, max 8 h), interact, and monitor/record
- Describe per-session microVM isolation, memory sanitization, and the PUBLIC network mode
- Drive a session from the SDK with the `browser_session` context manager and connect Playwright, browser-use, and Nova Act over the CDP stream
- Use Live View plus `update_browser_stream` take/release-control to keep credentials away from the agent
- Call the OS-level `InvokeBrowser` actions, scope the right `bedrock-agentcore:*` IAM permissions, and stop sessions so they don't bill until TTL
AgentCore Browser is a fully managed, isolated cloud browser your agent drives to navigate, fill forms, click, and scrape JavaScript-heavy sites it could never reach through a plain HTTP fetch. This lesson walks the four-step lifecycle (create browser, start session, interact, monitor), the per-session microVM isolation, the two channels every session exposes (the CDP automation stream and Live View), how to wire Playwright, browser-use, and Nova Act over CDP, the OS-level `InvokeBrowser` actions, and the take-control trick that hides credential entry from the agent.
- 1What the Browser Tool is — and why a fetch() isn't enough
- 2The four-step workflow and the data model
- 3Isolation, scale, and limits
- 4Two channels: the CDP automation stream and Live View
- 5Driving it: Playwright, Nova Act, and browser-use
- 6OS-level control with InvokeBrowser
- 7IAM, recording, Web Bot Auth, and the cost gotcha
What the Browser Tool is — and why a fetch() isn't enough
Most of the web your agent needs is not a clean JSON API. It's a single-page React app that renders nothing until JavaScript runs, a vendor portal behind a login wall, a booking flow with multi-step forms, a dashboard that only exists as a screenshot. A plain requests.get() or even a Gateway OpenAPI target gets you the empty HTML shell and nothing else.
AgentCore Browser is a fully managed, pre-built, cloud-based browser that gives an agent a secure, isolated environment to interact with web applications the way a human does: navigate, fill forms, click, parse JS-rendered content, take screenshots, upload and download files. It is one of the two built-in Tools in AgentCore — the other is the Code Interpreter — and it is deliberately framework- and model-agnostic: you drive it with Playwright, browser-use, Amazon Nova Act, or Strands, and the model behind your agent can be anything.
There are two flavors of the resource:
- System browser — the managed default, identified as
aws.browser.v1(created with--type SYSTEM). No setup; just start a session against it. - Custom browser — created with
--type CUSTOM, where you control session recording, network settings, an execution IAM role, Web Bot Auth, browser profiles, proxies, and extensions.
Keep one distinction crisp from the start. A Browser is the long-lived resource (it has an ARN like arn:aws:bedrock-agentcore:<region>:<account>:browser/*). A Browser session is an ephemeral runtime instance you start against that resource and then interact with. You create a browser rarely; you start and stop sessions constantly.
Key insight
Two built-in Tools, one mental model
Browser and Code Interpreter are the two managed sandboxes AgentCore ships. Both are containerized, isolated, and serverless. The Browser gives the agent eyes and hands on the live web; the Code Interpreter gives it a scratch compute environment. This lesson is the Browser; the OS-level actions and isolation model here rhyme closely with the Code Interpreter lesson.
Note
Preview-vs-GA status is volatile
As of writing, the Browser Tool is generally available (GA Oct 13 2025), but Web Bot Auth is still Preview. Status moves — verify the live browser-tool docs before you depend on any preview feature in production.
The four-step workflow and the data model
Every use of the Browser Tool follows the same four steps:
- Create a Browser Tool. Either use the managed default
aws.browser.v1, or create a custom browser when you need recording, custom network settings, an execution role, Web Bot Auth, profiles, proxies, or extensions. - Start a session. Each session is isolated and has a configurable timeout — default 15 minutes (900 s), max 8 hours. You can run many concurrently.
- Interact. Two channels per session: the WebSocket/CDP "automation" stream (driven by Playwright, browser-use, or Nova Act) for DOM-level work, and the Live View stream for a human to watch or take over.
- Monitor & record. Live View, session recording (custom browsers only), CloudWatch metrics, CloudTrail, and S3 replay.
The resource types map onto two ARN shapes:
| Resource | How you make it | ARN shape |
|---|---|---|
| System browser | --type SYSTEM (the built-in aws.browser.v1) | arn:aws:bedrock-agentcore:<region>:<account>:browser/* |
| Custom browser | --type CUSTOM | arn:aws:bedrock-agentcore:<region>:<account>:browser/* |
Networking. The Browser currently runs in PUBLIC mode — set as networkConfiguration.networkMode="PUBLIC". The GA launch blog references a VPC mode, but the documentation only documents PUBLIC; treat VPC as not-yet-documented and verify the live page before assuming it.
Tip
Reuse the browser, churn the sessions
Creating a browser is a control-plane operation you do once (or rarely). Starting and stopping sessions is the hot path. Model it that way: provision one custom browser per use case (with the recording and network config you want), then open a short-lived session per task and tear it down.
Isolation, scale, and limits
The security story is per-session microVM isolation: each session runs in its own microVM with isolated CPU, memory, and filesystem. When a session completes the microVM is terminated and its memory sanitized, so nothing leaks between sessions or tenants. Scaling is serverless and automatic, and everything is IAM-governed.
The concrete numbers are [VOLATILE] — teach the shape, verify the live quotas page before you design around any single value. As researched:
| Limit | Value (as of writing — verify live) |
|---|---|
| Session TTL (default) | 900 s (15 minutes) |
| Session TTL (max) | 8 hours |
| Concurrent sessions per browser tool | up to 500 |
| Data retention TTL | 30 days |
| Default viewport | 1456 × 819 |
The isolation model is what makes the Browser safe to point at hostile websites: a page can run arbitrary JavaScript, but it runs inside a throwaway microVM with no access to your other sessions, and the whole thing is wiped on completion.
Watch out
Numbers move — link, don't memorize
TTLs, the 500 concurrent-session ceiling, the 30-day retention, and the 1456×819 viewport are all volatile. Frame them in your runbooks as "as of writing — verify against the live AgentCore quotas page", never as fixed constants.
Two channels: the CDP automation stream and Live View
The agent loop is: a natural-language query goes to your framework, the LLM turns it into structured instructions, those become browser actuation commands (Playwright/Puppeteer/Selenium), and those execute over a secure WebSocket using the Chrome DevTools Protocol (CDP) — the page responds, a screenshot comes back, and the loop continues.
Every session exposes its streams under session.streams:
automationStream—wss://.../automation, the CDP channel the agent (Playwright/browser-use/Nova Act) drives.liveViewStream— a human-facing stream you can watch live in the console.
From the SDK, the BrowserClient hands you both. generate_ws_headers() returns the CDP WebSocket URL plus the SigV4-signed headers you must attach to authenticate; generate_live_view_url(expires=120) returns a time-boxed Live View URL.
from bedrock_agentcore.tools.browser_client import browser_session
with browser_session("us-west-2", viewport={"width": 1920, "height": 1080}) as browser:
ws_url, headers = browser.generate_ws_headers() # CDP WebSocket URL + signed headers
live_view = browser.generate_live_view_url(expires=120) # human watch/interact, 120 sThe Live View URL itself is of the form https://bedrock-agentcore.<Region>.amazonaws.com/browser-streams/{browser_id}/sessions/{session_id}/live-view. The samples repo also ships a BrowserViewerServer helper that hosts a small viewer for you.
Take/release control is the safety mechanism that protects credentials. A human watching Live View can take control — and you can hide that moment from the agent by disabling the automation stream before the human types a password, then re-enabling it afterward. You do this with update_browser_stream:
# Hand control to the human: disable the agent's CDP automation stream
client.update_browser_stream(
browserIdentifier="aws.browser.v1",
sessionId=session_id,
streamUpdate={"automationStreamUpdate": {"streamStatus": "DISABLED"}},
)
# ... human enters credentials in Live View; the agent cannot observe the keystrokes ...
# Return control to the agent
client.update_browser_stream(
browserIdentifier="aws.browser.v1",
sessionId=session_id,
streamUpdate={"automationStreamUpdate": {"streamStatus": "ENABLED"}},
)While the automation stream is DISABLED, the agent is blind to the page; only the human (via Live View) is driving. This is the canonical pattern for "the agent does everything except the login".
Key insight
Why disable the stream instead of masking the field?
The agent observes the page through the CDP automation stream — DOM, network, screenshots. If a human types a password while that stream is live, the agent could observe it. Disabling automationStream cuts the agent's view entirely for the duration of credential entry, so secrets never enter the agent's context. Re-enable it the moment the sensitive step is done.
Driving it: Playwright, Nova Act, and browser-use
Because the automation stream is plain CDP, any framework that can attach to a CDP endpoint works — you just have to get the signed headers onto the WebSocket.
Playwright connects with connect_over_cdp, passing the URL and headers from generate_ws_headers(). Screenshots go through a CDP session:
from playwright.sync_api import sync_playwright
with browser_session("us-west-2") as browser:
ws_url, headers = browser.generate_ws_headers()
with sync_playwright() as p:
chromium = p.chromium.connect_over_cdp(ws_url, headers=headers)
context = chromium.contexts[0]
page = context.pages[0]
page.goto("https://example.com")
# Full-page screenshot via the Chrome DevTools Protocol
cdp = context.new_cdp_session(page)
shot = cdp.send("Page.captureScreenshot", {"format": "png", "captureBeyondViewport": True})Amazon Nova Act takes the same CDP endpoint and headers directly. It needs a Nova Act API key and the nova-act PyPI package; there is also an AgentCoreBrowserSessionProvider. AWS published an agentic QA-automation reference built on this (per-test isolated sessions, parallelized with pytest-xdist):
from nova_act import NovaAct
ws_url, headers = browser.generate_ws_headers()
with NovaAct(
cdp_endpoint_url=ws_url,
cdp_headers=headers,
nova_act_api_key=NOVA_ACT_API_KEY,
starting_page="https://example.com",
) as nova:
nova.act("search for a wireless keyboard and add the cheapest to the cart")browser-use also connects over the CDP ws_url plus headers. Watch the version: some versions of browser-use stopped forwarding custom headers to the CDP WebSocket, which breaks AgentCore's header-based auth. Pin a version that forwards headers (see browser-use issue #3111). Strands sits one level up — it orchestrates the agent and lets Playwright actuate (the AWS payments-plus-browser sample is built this way).
Watch out
The header gotcha is the #1 silent failure
AgentCore authenticates the CDP socket via the signed headers from generate_ws_headers(). If your framework (or a regressed framework version) doesn't pass those headers through to the WebSocket, the connection is rejected and it looks like a flaky auth/network problem. Verify the headers actually reach the socket — this is the browser-use #3111 trap.
OS-level control with InvokeBrowser
Some interactions live outside the DOM — native dialogs, OS alerts, keyboard shortcuts, full-desktop screenshots, drag-and-drop. For those you use the second per-session channel: the OS-level InvokeBrowser REST API, which actuates the operating system itself, not just the page.
It's a single endpoint, POST /browsers/{browserIdentifier}/sessions/invoke, with the session passed in the x-amzn-browser-session-id header. Coordinates must satisfy 1 < x < viewportWidth-2 and 1 < y < viewportHeight-2.
The actions:
| Action | Notes |
|---|---|
mouseClick | button LEFT/RIGHT/MIDDLE; clickCount 1–10 |
mouseMove, mouseDrag | coordinate-based |
mouseScroll | deltaX/deltaY in −1000..1000; negative deltaY scrolls down |
keyType | text ≤ 10,000 chars, ASCII-only |
keyPress | presses 1–100 |
keyShortcut | ≤ 5 keys, lowercase key names |
screenshot | PNG only, captures the full OS desktop (not just the page) |
curl -X POST \
"https://bedrock-agentcore.us-west-2.amazonaws.com/browsers/aws.browser.v1/sessions/invoke" \
-H "x-amzn-browser-session-id: $SESSION_ID" \
-H "Content-Type: application/json" \
-d '{
"action": "mouseClick",
"mouseClick": { "x": 720, "y": 410, "button": "LEFT", "clickCount": 1 }
}'Two silent traps to internalize: a keyType with non-ASCII characters is silently skipped, and an invalid key name in keyPress/keyShortcut returns SUCCESS but does nothing. If a shortcut "works" in the API response but the page doesn't react, suspect a bad key name rather than a bug in your logic.
Example
DOM stream vs OS stream — pick the right one
Use the CDP automation stream (Playwright et al.) for everything that is page interaction — clicking elements, filling forms, reading the DOM. Drop to InvokeBrowser only for operating-system concerns the page model can't express: a native file-open dialog, a desktop-level screenshot, a global keyboard shortcut, or a drag-and-drop the DOM API can't fake.
IAM, recording, Web Bot Auth, and the cost gotcha
IAM. The caller (your agent or backend) needs the relevant bedrock-agentcore:* actions, scoped to arn:aws:bedrock-agentcore:<region>:<account>:browser/*:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"bedrock-agentcore:CreateBrowser",
"bedrock-agentcore:GetBrowser",
"bedrock-agentcore:ListBrowsers",
"bedrock-agentcore:DeleteBrowser",
"bedrock-agentcore:StartBrowserSession",
"bedrock-agentcore:GetBrowserSession",
"bedrock-agentcore:ListBrowserSessions",
"bedrock-agentcore:StopBrowserSession",
"bedrock-agentcore:UpdateBrowserStream",
"bedrock-agentcore:ConnectBrowserAutomationStream",
"bedrock-agentcore:ConnectBrowserLiveViewStream"
],
"Resource": "arn:aws:bedrock-agentcore:us-west-2:123456789012:browser/*"
}]
}Note the split: control-plane create/get/list/delete and data-plane start/stop/get/list sessions plus the Connect...Stream and UpdateBrowserStream actions. The two Connect* actions are what gate the automation and Live View WebSockets.
Recording is a custom-browser-only feature. When you create a custom browser you point recording at your own S3 bucket; AgentCore captures DOM, actions, console, and network so you can replay the session in the console. The browser's execution role needs S3 write permissions (s3:PutObject, s3:ListMultipartUploadParts, s3:AbortMultipartUpload), and its trust policy allows bedrock-agentcore.amazonaws.com to sts:AssumeRole, conditioned on aws:SourceAccount/aws:SourceArn.
client.create_browser(
name="checkout-bot",
networkConfiguration={"networkMode": "PUBLIC"},
executionRoleArn="arn:aws:iam::123456789012:role/AgentCoreBrowserExec",
recording={"enabled": True, "s3Location": {"bucket": "my-replays", "prefix": "sessions/"}},
)
# Data plane: start a session against it (or against aws.browser.v1)
client.start_browser_session(
browserIdentifier="aws.browser.v1",
sessionTimeoutSeconds=3600,
viewPort={"height": 819, "width": 1456},
)Web Bot Auth (Preview, [VOLATILE]). A draft IETF protocol (HTTP Message Signatures) that reduces CAPTCHA friction: when enabled, the browser signs each request and adds Signature, Signature-Agent, and Signature-Input headers. Preview vendors that honor it: Cloudflare, HUMAN Security, Akamai, DataDome. Enable it at create time — create_browser(..., browserSigning={'enabled': True}) (CLI --browser-signing '{"enabled": true}'). It's disabled by default, only helps on supported-vendor sites, and site owners can still block you. Since it is Preview, verify status on the live docs before relying on it.
The cost gotcha — stop your sessions. A session bills until its TTL even if you've walked away from it, and you cannot delete a browser that still has active sessions. Always stop sessions explicitly (or rely on the browser_session context manager, which stops on exit). Forgetting this is the most common way to run up a surprise bill.
Watch out
Stop sessions or they bill until TTL
An abandoned session keeps billing for the full timeout — up to 8 hours — and blocks deletion of its parent browser. Wrap interactions in the browser_session context manager so the session is stopped on exit, and treat an explicit stop_browser_session as mandatory cleanup in any non-context-managed code path.
Note
Recording is custom-only
DOM/action/console/network recording to S3 exists only on custom browsers, not the system aws.browser.v1. If you need replayable audit trails, you must provision a custom browser with recording.enabled and an execution role that can write to your bucket.
Try it: Drive a managed browser, hand off a login, and stop the session
Goal: start a session against aws.browser.v1, automate a page with Playwright over the CDP stream, hand control to a human for a sensitive step via Live View, and prove you cleaned up.
Prereqs: AWS creds with the bedrock-agentcore:* browser actions scoped to browser/*, bedrock-agentcore SDK installed, and playwright (pip install playwright && playwright install chromium). Pick a region from the live regions page.
- Start a session. Use the SDK
browser_sessioncontext manager againstaws.browser.v1with a smallsessionTimeoutSeconds(e.g. 300) so an accidental leak is cheap. Print the session id. - Connect Playwright over CDP. Call
generate_ws_headers(), thenchromium.connect_over_cdp(ws_url, headers=headers). Navigate to a JS-rendered public page (e.g. a docs site) and assert that content only present after JS render is visible — proof you're driving a real browser, not a fetch. - Capture a screenshot via CDP. Open
context.new_cdp_session(page)and sendPage.captureScreenshotwithformat=png. Save it locally and eyeball it. - Open Live View and take control. Call
generate_live_view_url(expires=120), open it in your browser, thenupdate_browser_stream(... automationStreamUpdate={"streamStatus":"DISABLED"}). Confirm the agent can no longer drive the page while you click around in Live View — this is the credential-protection pattern. Re-enable withstreamStatus: "ENABLED". - Try one OS-level action. Send an
InvokeBrowsermouseClick(respect1 < x < viewportWidth-2). Then send akeyTypecontaining a non-ASCII character and observe that it's silently skipped — confirming the ASCII-only rule. - Prove cleanup. Let the context manager exit (or call
stop_browser_session). Runlist_browser_sessionsand confirm none are active. Reflect in three sentences: how much would an un-stopped 5-minute session have cost vs an abandoned one billing to the 8-hour max, and where would you reach for a custom browser (recording to S3, Web Bot Auth) instead ofaws.browser.v1?
Key takeaways
- 1AgentCore Browser is a fully managed, isolated cloud browser — one of the two built-in Tools — that lets a framework/model-agnostic agent navigate, fill forms, click, and scrape JS-heavy sites. Use the system `aws.browser.v1` or create a custom browser for recording, network, profiles, proxies, extensions, and Web Bot Auth.
- 2The lifecycle is four steps: create a browser → start a session (default 15-min TTL, max 8 h, many concurrent) → interact → monitor/record. A Browser is the long-lived resource; a Browser session is the ephemeral instance.
- 3Each session runs in its own microVM (isolated CPU/memory/FS), terminated and memory-sanitized on completion. It currently runs in PUBLIC network mode; VPC is referenced in the launch blog but not documented.
- 4Every session has two channels: the CDP automation stream (Playwright `connect_over_cdp`, browser-use, Nova Act — attach the signed headers from `generate_ws_headers()`) and Live View for a human. Disable the automation stream via `update_browser_stream` before a human enters credentials so the agent can't observe them.
- 5Use `InvokeBrowser` (`POST /browsers/{id}/sessions/invoke`, header `x-amzn-browser-session-id`) for OS-level actions: `mouseClick`, `keyType` (ASCII-only), `keyShortcut`, `screenshot` (PNG, full desktop). Non-ASCII `keyType` is silently skipped; bad key names return SUCCESS but do nothing.
- 6Scope `bedrock-agentcore:*` actions (Create/Get/List/Delete Browser, Start/Stop/Get/List BrowserSession, UpdateBrowserStream, ConnectBrowserAutomationStream/ConnectBrowserLiveViewStream) to `browser/*`. Recording to S3 is custom-only and needs an execution role.
- 7Stop sessions or they bill until TTL (and block browser deletion). Web Bot Auth (signs requests for Cloudflare/HUMAN/Akamai/DataDome) is Preview and disabled by default — verify volatile status and limits against the live AWS docs.
Quiz
Lock in what you learned
Check your understanding
0 / 4 answered
1.A human needs to enter a password into a site mid-session, and you must guarantee the agent never observes those keystrokes. What's the right move?
2.Your agent's browser-use-based flow suddenly fails to authenticate against the CDP endpoint after a dependency bump, even though `generate_ws_headers()` returns a URL and headers. What's the most likely cause?
3.Through `InvokeBrowser` you send a `keyShortcut` to trigger a save, and the API returns SUCCESS — but nothing happens on the page. Combined with that, which statement about `InvokeBrowser` is accurate?
4.Your AWS bill for AgentCore Browser is far higher than expected even though your agents finish their tasks in seconds. What's the most likely explanation?
Go deeper
Hand-picked sources to keep learning
Authoritative reference: what it is, system vs custom, the workflow, streams, and integrations.
Create browsers, start/stop sessions, recording config, and the resource-vs-session model. See also browser-managing-sessions.html.
mouseClick/keyType/keyShortcut/screenshot specifics, coordinate bounds, and the ASCII-only / SUCCESS-but-noop gotchas.
Preview CAPTCHA-reduction via HTTP Message Signatures; vendors and enablement. Verify Preview-vs-GA status before depending on it.
[VOLATILE] Live values for session TTLs, concurrent sessions, retention, and viewport — verify before designing around any number.
Architecture deep-dive, the CDP+Live View model, and framework integration walkthroughs (Playwright/Nova Act).