Playwright MCP — Browser Automation Skill
Automate browser interactions for testing web apps, verifying UI changes, and debugging via the Playwright MCP server.
Tool Reference
Navigation
| Tool | Purpose | Key Args |
|---|---|---|
browser_navigate |
Go to a URL | url (string) |
browser_navigate_back |
Go back in history | — |
browser_tabs |
List/create/close/select tabs | action ("list"|"create"|"close"|"select"), index |
Inspection (Read-Only)
| Tool | Purpose | Key Args |
|---|---|---|
browser_snapshot |
Accessibility snapshot of page (preferred over screenshot for actions) | filename (optional, saves to markdown) |
browser_take_screenshot |
Visual screenshot (PNG/JPEG) | filename, fullPage (bool), element+ref for element screenshot |
browser_console_messages |
Get console logs/errors/warnings | level ("info"|"warning"|"error") |
browser_network_requests |
Get all network requests since page load | includeStatic (bool) |
Interaction
| Tool | Purpose | Key Args |
|---|---|---|
browser_click |
Click an element | element (description), ref (from snapshot), doubleClick, button, modifiers |
browser_type |
Type text into an input | element, ref, text, submit (press Enter after), slowly (char by char) |
browser_fill_form |
Fill multiple form fields at once | fields (array of {ref, value}) |
browser_select_option |
Select dropdown option | element, ref, values (array) |
browser_hover |
Hover over element | element, ref |
browser_drag |
Drag and drop | startElement, startRef, endElement, endRef |
browser_press_key |
Press keyboard key | key (e.g., "ArrowLeft", "Enter", "Escape") |
browser_file_upload |
Upload files | paths (array of absolute paths) |
browser_handle_dialog |
Accept/dismiss dialogs | accept (bool), promptText |
Utilities
| Tool | Purpose | Key Args |
|---|---|---|
browser_evaluate |
Run JavaScript on page | function (JS code string) |
browser_run_code |
Run Playwright code snippet | code (async function with page arg) |
browser_resize |
Resize browser window | width, height |
browser_wait_for |
Wait for condition | time (seconds), text (appear), textGone (disappear) |
browser_close |
Close the page | — |
browser_install |
Install browser binary | — (call if browser not found error) |
Core Workflow: Snapshot → Identify → Act
ALWAYS follow this pattern:
- Navigate to the page
- Snapshot to get the accessibility tree with element
refvalues - Identify the target element's
reffrom the snapshot - Act (click, type, etc.) using the
ref - Verify with another snapshot or screenshot
browser_navigate → browser_snapshot → browser_click (using ref) → browser_snapshot
NEVER guess ref values. Always take a fresh snapshot first.
Best Practices
1. Prefer Snapshot Over Screenshot for Actions
browser_snapshot returns an accessibility tree with ref attributes you can use to interact with elements. browser_take_screenshot is visual-only — you can't extract ref values from it.
Use screenshots for:
- Visual verification (does the UI look right?)
- Saving evidence of test results
- Debugging layout issues
Use snapshots for:
- Finding elements to click/type/interact with
- Verifying text content on the page
- Checking element state (enabled/disabled)
2. Always Check Console Errors After Page Load
browser_navigate → browser_snapshot → browser_console_messages (level: "error")
This catches React crashes, API failures, and JavaScript errors immediately.
3. Wait for Dynamic Content
SPAs (React, Vue, etc.) render asynchronously. After navigation or clicks that trigger data loading:
browser_navigate → browser_wait_for (text: "expected content") → browser_snapshot
Or wait for loading indicators to disappear:
browser_click → browser_wait_for (textGone: "Loading...") → browser_snapshot
4. Form Filling Pattern
For forms with multiple fields, use browser_fill_form instead of individual browser_type calls:
{
"fields": [
{"ref": "input_name_ref", "value": "John Doe"},
{"ref": "input_email_ref", "value": "john@example.com"},
{"ref": "input_date_ref", "value": "2025-12-31"}
]
}
5. Handle Authentication Flows
For OAuth or login pages:
- Navigate to the app URL
- If redirected to login, snapshot to find form fields
- Fill credentials and submit
- Wait for redirect back to app
- Snapshot to verify authenticated state
6. Full-Page Screenshots for Long Pages
{
"fullPage": true,
"filename": "full-page-capture.png"
}
7. Element-Specific Screenshots
First snapshot to get the ref, then:
{
"element": "the data table",
"ref": "table_ref_from_snapshot",
"filename": "table-only.png"
}
Common Testing Workflows
Test a Deployed Web App
1. browser_navigate (url: "https://your-app.databricks.app")
2. browser_snapshot
3. browser_console_messages (level: "error")
4. browser_take_screenshot (filename: "initial-load.png")
5. [interact with the app]
6. browser_console_messages (level: "error") ← check again after interactions
Test a Local Dev Server
1. browser_navigate (url: "http://localhost:3000")
2. browser_wait_for (text: "some expected content")
3. browser_snapshot
4. [test interactions]
Debug a Blank/Crashing Page
1. browser_navigate (url: "...")
2. browser_console_messages (level: "error") ← check for JS errors
3. browser_network_requests ← check for failed API calls
4. browser_take_screenshot ← see what's actually rendered
Multi-Tab Testing
1. browser_tabs (action: "create")
2. browser_navigate (url: "second-page")
3. [test in second tab]
4. browser_tabs (action: "select", index: 0) ← switch back to first tab
Troubleshooting
| Problem | Fix |
|---|---|
| "Browser not installed" error | Call browser_install first |
| Playwright MCP server is down | Restart Cursor or check MCP server config in settings |
ref not found / stale |
Take a fresh browser_snapshot — refs change after page updates |
| Click doesn't work | Verify the ref is from the LATEST snapshot. Element may have re-rendered. |
| Page shows blank after navigation | Check browser_console_messages for JS errors. Common: React hooks violation, missing API data. |
| Form submit doesn't work | Use browser_type with submit: true, or click the submit button separately after filling |
| Timeout waiting for text | The text may be different than expected. Take a snapshot to see actual content. |
| Dialog blocks interaction | Call browser_handle_dialog with accept: true or accept: false |
| Need to test responsive layout | Use browser_resize with mobile dimensions (e.g., 375×812 for iPhone) |
| Screenshot is blank/black | Page may still be loading. Add browser_wait_for before screenshot. |