Originally published at claudeguide.io/claude-agent-playwright
Claude Agent SDK + Playwright: Browser Automation Patterns
Combining Claude Agent SDK with Playwright gives you browser automation that can reason — not just click a fixed sequence of selectors, but decide what to do next based on what it sees on the page. Claude reads the page, decides which actions to take, calls Playwright tools to execute them, and interprets the results in 2026. This guide covers the integration patterns, the tool definitions that make it work reliably, and the error recovery that keeps it production-grade.
Architecture Overview
Claude acts as the reasoning layer. Playwright acts as the execution layer. You expose Playwright operations as Claude tools.
User goal → Claude (plan + reason) → Tool call → Playwright (execute) → Claude reads result → next step
The key design decision: keep each Playwright tool narrow and reliable. Don't build one do_everything_on_page tool — build click_element, fill_input, get_page_text, wait_for_element. Claude decides which combination to call.
Setting Up the Integration
pip install anthropic playwright
playwright install chromium
import anthropic
import json
import asyncio
from playwright.async_api import async_playwright, Page, Browser
client = anthropic.Anthropic()
# Global browser state
browser: Browser = None
page: Page = None
async def init_browser(headless: bool = True):
"""Initialize Playwright browser."""
global browser, page
playwright = await async_playwright().start()
browser = await playwright.chromium.launch(headless=headless)
page = await browser.new_page()
return page
async def close_browser():
global browser
if browser:
await browser.close()
Defining Playwright Tools for Claude
PLAYWRIGHT_TOOLS = [
{
"name": "navigate_to",
"description": "Navigate the browser to a URL. Use when you need to load a new page.",
"input_schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The full URL to navigate to, including https://"
}
},
"required": ["url"]
}
},
{
"name": "get_page_content",
"description": "Get the visible text content of the current page. Use to understand what's on screen before taking action.",
"input_schema": {
"type": "object",
"properties": {
"max_chars": {
"type": "integer",
"description": "Maximum characters to return (default 5000)",
"default": 5000
}
}
}
},
{
"name": "click_element",
"description": "Click an element on the page. Provide a CSS selector or text to find the element.",
"input_schema": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "CSS selector OR text content of the element to click. For text: use 'text=Submit' format."
},
"wait_after_ms": {
"type": "integer",
"description": "Milliseconds to wait after clicking (default 500)",
"default": 500
}
},
"required": ["selector"]
}
},
{
"name": "fill_input",
"description": "Fill a text input or textarea with a value.",
"input_schema": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "CSS selector for the input field"
},
"value": {
"type": "string",
"description": "Text to type into the field"
},
"clear_first": {
"type": "boolean",
"description": "Clear existing content before typing (default true)",
"default": True
}
},
"required": ["selector", "value"]
}
},
{
"name": "take_screenshot",
"description": "Take a screenshot of the current page state. Use when you need to see the current visual state to decide next action.",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "File path to save screenshot (e.g., /tmp/screenshot.png)"
}
},
"required": ["path"]
}
},
{
"name": "wait_for_selector",
"description": "Wait for an element to appear on the page. Use after navigation or after clicking something that triggers loading.",
"input_schema": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "CSS selector to wait for"
},
"timeout_ms": {
"type": "integer",
"description": "Maximum wait time in ms (default 5000)",
"default": 5000
}
},
"required": ["selector"]
}
},
{
"name": "get_element_text",
"description": "Get the text content of a specific element. More precise than get_page_content when you need a specific value.",
"input_schema": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "CSS selector for the element"
}
},
"required": ["selector"]
}
},
{
"name": "extract_table",
"description": "Extract data from an HTML table as JSON. Use for scraping tabular data.",
"input_schema": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "CSS selector for the table element",
"default": "table"
},
"max_rows": {
"type": "integer",
"description": "Maximum rows to extract",
"default": 100
}
}
}
}
]
Tool Execution Functions
python
async def execute_playwright_tool(tool_name: str, tool_input: dict) -
[→ Get the Agent SDK Cookbook — $49](https://shoutfirst.gumroad.com/l/ogxhmy?utm_source=claudeguide&utm_medium=article&utm_campaign=claude-agent-playwright)
*30-day money-back guarantee. Instant download.*
Top comments (0)