7-Step Guide: Wire AI Agents to Antidetect Profiles via Playwright MCP
Picture a typical agent run: scrape competitor pricing from three e-commerce sites. It fires up Playwright MCP, hits the first URL, gets a Cloudflare challenge page, retries twice, and gives up. Blocked. On all three sites. The agent's code is fine. Its antidetect browser setup is missing.
This is the gap nobody talks about when demoing agentic browsing. The agent can plan, reason, and execute. But it's driving a browser that screams "I'm automated" to every detection system on the web.
The fix isn't patching the browser from JavaScript — that's a losing game. You route the agent through a browser whose fingerprint is patched at the engine level. That's what we're wiring up: an AI agent connected to antidetect profiles via Playwright MCP.
What We're Building
By the end of this tutorial, you'll have:
- A Playwright MCP server configured to use antidetect browser profiles
- An AI agent (Claude, GPT-4, or any MCP-compatible model) that browses through a real fingerprint instead of a stock automation browser
- A pattern for running multiple agents on isolated profiles simultaneously
The agent navigates, clicks, takes screenshots and extracts text on sites that would block stock Playwright in seconds. No stealth plugins. No JavaScript overrides. Native fingerprint protection at the Chromium level. (Worth the setup time — the CDP connection logic is the fiddly part, everything else is copy-paste.)
Prerequisites
- Node.js 20+ installed
- JustBrowser with at least one profile configured (the seven-day trial works fine — profiles are unlimited on the plan, trial included)
- Basic familiarity with MCP (Model Context Protocol) servers
- An MCP-compatible AI client (Claude Desktop, Cursor, or your own integration)
If you need background on how antidetect browsers integrate with Playwright at the protocol level, the Playwright/Puppeteer stealth guide covers the fundamentals. Not required reading, but helpful context.
Step 1: Understand the Architecture
Here's how the pieces connect:
AI Agent (Claude/GPT-4)
↓ MCP protocol
Playwright MCP Server
↓ CDP WebSocket
Antidetect Browser Profile (JustBrowser)
↓ HTTP/TLS
Target Website
The standard Playwright MCP server launches chromium.launch() — a stock browser that detection services flag instantly. We're replacing that with a CDP connection to a pre-launched antidetect profile.
The profile handles fingerprinting (canvas, WebGL, audio, fonts, Client Hints, all 40+ parameters). The MCP server handles agent tool calls. The agent just browses — oblivious to the fingerprint magic happening underneath.
This separation matters. The agent's prompt doesn't change. Its capabilities don't change. Only its browser backend changes. Swap between stock Playwright and antidetect mode by changing one endpoint. I wish more automation tools worked this way — most don't.
Step 2: Set Up Your Antidetect Profile
Open JustBrowser and create a profile for agent browsing. Some things to configure:
Fingerprint: Pick a common hardware profile. Intel UHD 620 for laptops, M2 for Mac, RTX 3060 for desktop. Avoid exotic GPUs — rarity is a signal. The WebGL fingerprinting guide explains why this matters.
Proxy: Assign a residential or ISP proxy geo-matched to your fingerprint's locale. A Windows profile claiming US timezone routed through a German datacenter IP is an obvious mismatch.
Cookies: For sites requiring login, pre-authenticate in the profile and save the session. The agent inherits those cookies — it won't need to log in every run.
Note your profile's ID. You'll use it to launch via REST API.
Step 3: Launch the Profile via REST API
JustBrowser's one plan ($9.99/month or $99.99/year, unlimited profiles) includes REST API access, and so does the trial. The API runs locally — bound to 127.0.0.1, port configurable — and every request needs a bearer token pulled from the app's AI tab.
Launch your profile programmatically:
async function launchProfile(profileId) {
const response = await fetch(`http://127.0.0.1:36542/api/v1/profiles/${profileId}/start`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.JUSTBROWSER_TOKEN}`
},
body: JSON.stringify({ headless: false })
});
const body = await response.json();
if (!response.ok) throw new Error(body.error.code); // branch on error.code, not the message
return { cdpUrl: body.data.cdp_url };
}
// Returns something like:
// { cdpUrl: "ws://127.0.0.1:PORT/devtools/browser/<guid>" }
That cdp_url is a standard Chrome DevTools Protocol URL. Any tool that speaks CDP can connect — including Playwright. Leave the body out and you get a headless browser by default; headless: false is what gets you a window you can actually watch.
Keep the profile running. The MCP server will connect to it. When you're done, end the session with POST /profiles/{id}/stop — browser.close() only disconnects Playwright and leaves the profile running.
Step 4: Create a Custom MCP Server
A stock Playwright MCP setup launches its own browser. We'll write a small server that connects to our pre-launched profile instead.
In a new folder, run npm install @modelcontextprotocol/sdk playwright, then create antidetect-mcp-server.mjs:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { chromium } from 'playwright';
const CDP_ENDPOINT = process.env.CDP_ENDPOINT; // the cdp_url returned in Step 3
let browser;
let page;
const server = new Server({
name: 'antidetect-playwright',
version: '1.0.0',
}, {
capabilities: {
tools: {}
}
});
async function ensureBrowser() {
if (!browser) {
// Connect to antidetect profile instead of launching stock browser
browser = await chromium.connectOverCDP(CDP_ENDPOINT);
const context = browser.contexts()[0]; // never newContext() — that spins up an incognito context outside the profile
page = context.pages()[0] || await context.newPage();
}
return page;
}
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'navigate',
description: 'Navigate to a URL',
inputSchema: {
type: 'object',
properties: {
url: { type: 'string', description: 'URL to navigate to' }
},
required: ['url']
}
},
{
name: 'screenshot',
description: 'Take a screenshot of the current page',
inputSchema: { type: 'object', properties: {} }
},
{
name: 'click',
description: 'Click an element',
inputSchema: {
type: 'object',
properties: {
selector: { type: 'string', description: 'CSS selector' }
},
required: ['selector']
}
},
{
name: 'get_text',
description: 'Extract text content from the page',
inputSchema: {
type: 'object',
properties: {
selector: { type: 'string', description: 'CSS selector (optional)' }
}
}
}
]
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const p = await ensureBrowser();
switch (name) {
case 'navigate':
await p.goto(args.url, { waitUntil: 'networkidle' });
return { content: [{ type: 'text', text: `Navigated to ${args.url}` }] };
case 'screenshot':
const buffer = await p.screenshot({ type: 'png' });
return {
content: [{
type: 'image',
data: buffer.toString('base64'),
mimeType: 'image/png'
}]
};
case 'click':
await p.click(args.selector);
return { content: [{ type: 'text', text: `Clicked ${args.selector}` }] };
case 'get_text':
const text = args.selector
? await p.locator(args.selector).textContent()
: await p.evaluate(() => document.body.innerText);
return { content: [{ type: 'text', text }] };
default:
throw new Error(`Unknown tool: ${name}`);
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
The critical line is chromium.connectOverCDP(CDP_ENDPOINT). Instead of chromium.launch(), we connect to the already-running antidetect profile. Same Playwright API. Different browser.
(Fair warning: I've oversimplified the error handling here. Production code needs reconnection logic, timeouts, the whole works. But this gets you a working demo.)
Step 5: Wire Up Your AI Client
For Claude Desktop, add the server to your MCP config (claude_desktop_config.json):
{
"mcpServers": {
"antidetect-browser": {
"command": "node",
"args": ["/path/to/antidetect-mcp-server.mjs"],
"env": {
"CDP_ENDPOINT": "paste the cdp_url your Step 3 start call returned"
}
}
}
}
Restart Claude Desktop. The agent now has navigate, screenshot, click, and get_text tools that execute against your antidetect profile.
For Cursor or other MCP clients, the configuration is similar — point to your custom server with the CDP endpoint as an environment variable.
Step 6: Test Against a Protected Site
Ask your agent to browse a public page on a site you know has bot detection. Something like:
Navigate to example-store.com, screenshot the homepage, and extract the prices from the pricing section.
With stock Playwright, you'd often get a Cloudflare challenge page or an immediate block. With the antidetect profile, the site sees a Windows user with Intel UHD graphics, a US residential IP and a consistent fingerprint instead of a stock automation browser. If you still hit a challenge, check the proxy first (see Common Errors below).
Step 7: Scale to Multiple Agents
Each antidetect profile is isolated. Different fingerprint, different cookies, different proxy. To run multiple agents:
const profiles = ['profile-1-id', 'profile-2-id', 'profile-3-id'];
async function spawnAgents() {
const agents = await Promise.all(profiles.map(async (profileId) => {
const { cdpUrl } = await launchProfile(profileId);
const browser = await chromium.connectOverCDP(cdpUrl);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
return { profileId, browser, page };
}));
return agents;
}
Each agent operates independently. One can browse Amazon, another eBay, another a competitor site. Zero cross-contamination. If one session fails, the others keep running.
For teams running research automation — ad verification, price monitoring, OSINT — the same pattern extends to more concurrent agents as long as your machine has the memory for the browser processes.
Annoying truth: managing this many profiles gets messy. You'll want a naming convention and some automation around profile creation. It's an easy mistake to make — connect to the wrong profile and lose an hour debugging an agent that's "acting weird" for no reason at all.
Common Errors and Fixes
Error: "Failed to connect to browser"
Cause: The profile isn't running, or the CDP endpoint is wrong.
Fix: Verify the profile is launched via REST API. Check that CDP_ENDPOINT matches the cdp_url returned by the start call, and that your bearer token is valid. A rejected call comes back with a non-2xx status and an {"error": {"code", "message"}} body, so check error.code before reading data.
Error: "Page crashed" or "Target closed"
Cause: The profile was stopped externally, or a navigation caused an unhandled error.
Fix: Wrap page operations in try/catch. Re-connect to the CDP endpoint if the browser process died. Consider implementing a health check that pings the profile before each agent task.
Error: Agent gets blocked despite antidetect setup
Cause: Usually proxy quality, not fingerprint. Datacenter IPs are burned on most protected sites. This is the one that trips people up most.
Fix: Switch to residential or ISP proxies. Verify the proxy geo matches your profile's timezone. Test the profile manually on CreepJS. The JA4+ TLS fingerprinting guide covers the network-layer side. If the profile was started headless, remember its screen and viewport follow headless defaults — start it with {"headless": false} when the session must look like a person's browser.
Error: "Context or page not found"
Cause: Your profile has no open pages, or the context was closed.
Fix: The ensureBrowser() function in our example handles this by creating a page if none exists. Make sure you're not calling context.close() or page.close() elsewhere in your code without re-initializing.
Next Steps
Once your agent is browsing reliably through antidetect profiles:
-
Add more tools — form filling, scrolling, waiting for selectors, JavaScript evaluation. The MCP server pattern extends naturally.
-
Build agent-specific profiles — each recurring task gets its own profile with pre-warmed cookies and appropriate fingerprint. JustBrowser's cookie warm-up and profile aging apply to agent profiles too.
-
Monitor detection rates — if blocks increase, test your profile against FingerprintJS and CreepJS. Detection tools update constantly.
The agentic browsing wave is just starting. MCP gives agents browser control. Antidetect browsers give them access to the protected web. Put them together and you've got agents that can actually do the work — not just demo well on toy sites.
Look, I'm not going to pretend this setup is trivial. It's not. But once it's running, your agents can browse the real web, not just the parts that don't have bot detection.
Frequently Asked Questions
What is Playwright MCP and why do AI agents need it?
Playwright MCP is a Model Context Protocol server that gives AI agents browser control capabilities. The MCP standard lets agents call tools like navigate, click, and screenshot through a structured interface. Without MCP, agents would need custom browser automation code for each task. With MCP, the agent requests actions and the server handles execution — but the default server uses a stock browser that gets detected and blocked on protected sites.
Why do AI agents get blocked when browsing the web?
AI agents using stock Playwright browsers trigger the same detection signals as any headless automation: navigator.webdriver flags, missing plugins, SwiftShader WebGL rendering, inconsistent Client Hints, and robotic behavioral patterns. Sites running Cloudflare, DataDome, or PerimeterX fingerprint these signals and block or CAPTCHA the session within seconds. The agent itself isn't detected — its browser is.
How does routing through antidetect profiles fix agent detection?
Antidetect browsers like JustBrowser modify Chromium at the C++ level to produce genuine fingerprints. When you connect Playwright MCP to an antidetect profile instead of a stock browser, the agent's actions execute in a browser with real canvas hashes, proper WebGL rendering, and consistent identity parameters, so the browser's fingerprint stops being the giveaway. Proxy quality and the agent's behaviour still matter.
Can I run multiple AI agents on different antidetect profiles simultaneously?
Yes. Each antidetect profile runs as a separate browser process with its own fingerprint, cookies, and proxy. Launch profiles via REST API, get their CDP endpoints, and point each agent's MCP server at a different endpoint. The agents operate in complete isolation — different fingerprints, different IPs, different browsing histories. Scale by adding profiles.
Try JustBrowser
Native Chromium antidetect browser — not extension-based. Real C++ engine patches at the canvas / WebGL / audio / font / screen layer, 40+ identity parameters. Local REST API + CDP for Playwright, Puppeteer, Selenium. 7-day free trial, card required — then $9.99/month or $99.99/year, unlimited profiles, free team seats.
Get started → · How it differs from Multilogin / GoLogin / AdsPower
Related Posts
Ready to manage multiple accounts?
Seven days free, then $9.99/month — one plan, everything included.