# Playwright MCP

> Browser automation and testing via Playwright MCP server. Use when testing web apps, verifying UI changes, checking console errors, filling forms, taking screenshots, or any browser-based interaction. Triggers on "test the app", "check the UI", "open the browser", "take a screenshot", "click the button", "fill the form", "check for console errors".

- Skill: `cheeyutan/playwright-mcp` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add cheeyutan/playwright-mcp`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cheeyutan/playwright-mcp/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: CheeYuTan (https://skillmd.com/u/cheeyutan)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/cheeyutan/playwright-mcp

---


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

1. **Navigate** to the page
2. **Snapshot** to get the accessibility tree with element `ref` values
3. **Identify** the target element's `ref` from the snapshot
4. **Act** (click, type, etc.) using the `ref`
5. **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:

```json
{
  "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:
1. Navigate to the app URL
2. If redirected to login, snapshot to find form fields
3. Fill credentials and submit
4. Wait for redirect back to app
5. Snapshot to verify authenticated state

### 6. Full-Page Screenshots for Long Pages

```json
{
  "fullPage": true,
  "filename": "full-page-capture.png"
}
```

### 7. Element-Specific Screenshots

First snapshot to get the `ref`, then:

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

