Agentic AI AcademyAgentic AI Academy

The Browser Tool

A managed, isolated cloud browser your agent can drive

Intermediate 13 minBuilder
What you'll be able to do
  • 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
At a glance

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.

  1. 1What the Browser Tool is — and why a fetch() isn't enough
  2. 2The four-step workflow and the data model
  3. 3Isolation, scale, and limits
  4. 4Two channels: the CDP automation stream and Live View
  5. 5Driving it: Playwright, Nova Act, and browser-use
  6. 6OS-level control with InvokeBrowser
  7. 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:

  1. 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.
  2. 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.
  3. 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.
  4. Monitor & record. Live View, session recording (custom browsers only), CloudWatch metrics, CloudTrail, and S3 replay.

The resource types map onto two ARN shapes:

ResourceHow you make itARN shape
System browser--type SYSTEM (the built-in aws.browser.v1)arn:aws:bedrock-agentcore:<region>:<account>:browser/*
Custom browser--type CUSTOMarn: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:

LimitValue (as of writing — verify live)
Session TTL (default)900 s (15 minutes)
Session TTL (max)8 hours
Concurrent sessions per browser toolup to 500
Data retention TTL30 days
Default viewport1456 × 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:

  • automationStreamwss://.../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.

python
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 s

The 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:

python
# 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:

python
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):

python
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:

ActionNotes
mouseClickbutton LEFT/RIGHT/MIDDLE; clickCount 1–10
mouseMove, mouseDragcoordinate-based
mouseScrolldeltaX/deltaY in −1000..1000; negative deltaY scrolls down
keyTypetext ≤ 10,000 chars, ASCII-only
keyPresspresses 1–100
keyShortcut≤ 5 keys, lowercase key names
screenshotPNG only, captures the full OS desktop (not just the page)
bash
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/*:

json
{
  "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.

python
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.

  1. Start a session. Use the SDK browser_session context manager against aws.browser.v1 with a small sessionTimeoutSeconds (e.g. 300) so an accidental leak is cheap. Print the session id.
  2. Connect Playwright over CDP. Call generate_ws_headers(), then chromium.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.
  3. Capture a screenshot via CDP. Open context.new_cdp_session(page) and send Page.captureScreenshot with format=png. Save it locally and eyeball it.
  4. Open Live View and take control. Call generate_live_view_url(expires=120), open it in your browser, then update_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 with streamStatus: "ENABLED".
  5. Try one OS-level action. Send an InvokeBrowser mouseClick (respect 1 < x < viewportWidth-2). Then send a keyType containing a non-ASCII character and observe that it's silently skipped — confirming the ASCII-only rule.
  6. Prove cleanup. Let the context manager exit (or call stop_browser_session). Run list_browser_sessions and 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 of aws.browser.v1?

Key takeaways

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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