Playwright MCP with a persistent browser profile
This one became one of the bigger unlocks in my day-to-day work with agents, and the surprising part is how small the technical change is. I'd been using Cursor and MCP happily for code work, but I kept hitting the same wall on everything browser-based: Apple Developer's multi-step app submission forms, Supabase project setup, ad-campaign dashboards in personal accounts. Every field wanted specific input I had to look up; I kept wishing I could just tell an agent "go set this up in my dashboard". I tried Cursor's built-in browser first — it has Playwright under the hood — but it didn't persist sessions between runs, which killed the whole idea, plus a few flow limitations on top. Then I installed standalone Playwright MCP myself and found the one flag that made all the difference: --user-data-dir.
The config
In .cursor/mcp.json:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest",
"--user-data-dir", ".cursor/data/playwright-user-data",
"--output-dir", ".cursor/data/playwright-mcp"
]
}
}
}--user-data-dir tells Chromium to persist the full profile — cookies, localStorage, IndexedDB, service worker state, logged-in sessions — into a directory you control. That means I can open the browser once, log into whatever service I need (going through captchas, MFA, email verification myself), close it, and the next agent run picks up fully authenticated. --output-dir collects screenshots and traces in one place. Keeping both paths inside .cursor/data/ means they sit beside the workspace and get gitignored naturally.
The flow
The agent's default behaviour is: try the task with the existing session first. If the service redirects to a login page, stop automating and hand the browser to me — the Chromium window is already open, I just log in manually. I reply "logged in" (pick whatever cue word you like) and the agent continues from the current DOM state.
I encoded this as a workspace rule so every agent in the project follows the same pattern:
# .cursor/rules/browser-playwright-auth-flow.mdc
- Try the existing session first.
- If authentication is required, stop and let the user log in manually.
- After the user confirms with "logged in", continue from the current state.Delegating login to a human is deliberate. Login flows change constantly — MFA, captchas, SSO redirects, device verification — and any automation built around them is immediately fragile. Hand off the 30-second manual step, remove the brittle link, keep the rest of the automation solid.
What it actually unlocked
The concrete workflows that stopped being painful for me:
- Publishing apps to Apple Developer. The new-app submission form is long and every field wants specific input. The agent now fills it end-to-end while I review.
- Supabase project setup. Connecting services, configuring auth providers, walking through the schema and policy wizards — things I'd otherwise click through dozens of times.
- Ad-campaign dashboards. Setting up or duplicating campaigns in personal accounts where I don't have an API to hit.
- Any internal-tool dashboard where the only interface is a web UI and I'd be clicking for 20 minutes.
Concretely: Playwright MCP went from "thing I set up and forgot" to the MCP I lean on the most. Fresh-session-every-run was the whole problem; persistence plus a sane human-in-the-loop flow was the whole solution, and it took one flag.