Install
$ agentstack add skill-jesamkim-oh-my-skills-agentcore-browser ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
AgentCore Browser — CDP over AWS Managed Chrome
Automate a cloud-hosted Chrome 144 browser through Bedrock AgentCore. The browser runs entirely on AWS — no local Chrome, no X server, no Playwright install. You talk to it via CDP commands over a SigV4-authenticated WebSocket.
When to Use This Skill vs agent-browser
Try agent-browser first. It is faster (local execution, no network RTT) and free. Switch to this skill when:
| Situation | Why this skill wins | |-----------|-------------------| | No local Chrome / headless server | Browser runs on AWS, nothing to install | | agent-browser CLI not installed | Only needs boto3 + websockets (Python) | | Python agent pipeline (Strands, LangGraph) | Native async/await, no shell subprocess | | AWS VPC-internal sites | VPC network mode reaches private ALBs | | Need session persistence across runs | Browser Profile API saves cookies/storage | | agent-browser --headed display issues | Not applicable — always headless on AWS |
Prerequisites
pip install boto3 websockets
AWS credentials must have bedrock-agentcore:* and bedrock-agentcore-control:* permissions.
Quick Start
Step 0: Create a Browser Resource (one-time)
import boto3
control = boto3.client("bedrock-agentcore-control", region_name="us-east-1")
resp = control.create_browser(
name="myBrowser",
description="Experiment browser",
networkConfiguration={"networkMode": "PUBLIC"},
)
browser_id = resp["browserId"] # e.g. "myBrowser-O9bw0JnQyc"
Or use the helper:
from scripts.browser_client import AgentCoreBrowser
browser_id = AgentCoreBrowser.create_browser("myBrowser", region="us-east-1")
Step 1: Connect and Navigate
import asyncio
from scripts.browser_client import AgentCoreBrowser
async def main():
browser = AgentCoreBrowser(browser_id="myBrowser-xxxxx", region="us-east-1")
await browser.start("my_session")
await browser.navigate("https://example.com")
title = await browser.get_title()
print(f"Page title: {title}")
await browser.screenshot("/tmp/page.png")
await browser.stop()
asyncio.run(main())
Core Workflow
Every automation follows this pattern:
- Navigate —
await browser.navigate(url) - Extract —
await browser.evaluate(js)orawait browser.get_page_text() - Interact —
await browser.click(selector)/await browser.type_text(selector, text) - Capture —
await browser.screenshot(path) - Stop —
await browser.stop()(always call this to avoid charges)
API Reference
Lifecycle
| Method | Description | |--------|-------------| | AgentCoreBrowser.create_browser(name, region) | Create a browser resource (class method, one-time) | | AgentCoreBrowser.list_browsers(region) | List existing browser resources | | browser.start(name) | Start session, connect WebSocket, attach to page | | browser.stop() | Close WebSocket and stop session | | browser.destroy_browser() | Delete the browser resource |
Navigation
| Method | Description | |--------|-------------| | navigate(url, wait=2.0) | Go to URL, wait for load | | wait_for_selector(selector, timeout=10) | Poll until element exists |
Data Extraction
| Method | Description | |--------|-------------| | evaluate(expression) | Run JavaScript, return value | | get_text(selector) | Get element's innerText | | get_page_text() | Get full page text | | get_html(selector) | Get element's outerHTML | | get_url() | Current page URL | | get_title() | Current page title |
Interaction
| Method | Description | |--------|-------------| | click(selector) | Click element by CSS selector | | type_text(selector, text) | Type text char-by-char (CDP key events) | | select_option(selector, value) | Select dropdown option |
Capture
| Method | Description | |--------|-------------| | screenshot(path=None) | PNG screenshot, optionally save to file |
Patterns
Form Submission
await browser.navigate("https://httpbin.org/forms/post")
await browser.type_text('input[name="custname"]', "Test User")
await browser.type_text('input[name="custemail"]', "test@example.com")
await browser.evaluate(
"document.querySelector('input[name=\"size\"][value=\"medium\"]').checked = true"
)
await browser.evaluate("document.querySelector('form').submit()")
await asyncio.sleep(2)
result = await browser.get_page_text()
Web Scraping (JS-rendered pages)
await browser.navigate("https://finance.naver.com/marketindex/")
rate = await browser.evaluate(
"document.querySelector('.head_info .value')?.innerText"
)
print(f"USD/KRW: {rate}")
Wait for Dynamic Content
await browser.navigate("https://spa-app.example.com")
found = await browser.wait_for_selector(".data-table", timeout=15)
if found:
data = await browser.evaluate("document.querySelector('.data-table').innerText")
Important Notes
Cost Management
Sessions are billed by duration. Always call browser.stop() in a finally block:
browser = AgentCoreBrowser(browser_id="...", region="us-east-1")
try:
await browser.start("task")
# ... work ...
finally:
await browser.stop()
IP Restrictions
The browser runs on AWS IP ranges. Some sites block AWS IPs:
- weather.go.kr (Korean Met Administration) — returns error page
- accuweather.com — returns 403 Access Denied
Sites that work well from AWS:
- naver.com, finance.naver.com — fully functional
- httpbin.org — fully functional
- wttr.in — fully functional
- Most SaaS/enterprise tools — generally accessible
Form Input
Setting element.value = "..." via JS alone does not trigger browser input events on all form frameworks. The type_text() method uses CDP Input.dispatchKeyEvent to simulate real keystroke events, which works reliably across React, Vue, and plain HTML forms.
CDP Protocol
The automation stream speaks Chrome DevTools Protocol v1.3 (JSON-RPC over WebSocket). Any CDP command works — the methods above are convenience wrappers. For advanced use:
result = await browser._send(
"Network.enable", session_id=browser._cdp_session_id
)
Browser Profile Persistence
Save and restore session state (cookies, localStorage) across sessions:
# Save after login
client = boto3.client("bedrock-agentcore", region_name="us-east-1")
client.save_browser_session_profile(
profileIdentifier="my_profile",
browserIdentifier=browser_id,
sessionId=session_id,
)
# Reuse in next session
resp = client.start_browser_session(
browserIdentifier=browser_id,
name="resumed",
profileConfiguration={"profileIdentifier": "my_profile"},
...
)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: jesamkim
- Source: jesamkim/oh-my-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.