# Use Playwright with an anti-detect browser

> Use Playwright with an anti-detect browser by starting the profile first and attaching with connectOverCDP. Keep its context; leave the fingerprint alone.

Source: https://mosaicbrowser.com/guides/use-playwright-with-an-anti-detect-browser

## How to use Playwright with an anti-detect browser

To use Playwright with an anti-detect browser, start the profile through the browser's own API, take the DevTools endpoint it returns and attach with chromium.connectOverCDP. Work in the existing context, set no viewport, user agent or locale from Playwright, and stop the profile through the API when done.

![Attach Playwright to a profile that is already running](https://mosaicbrowser.com/covers/use-playwright-with-an-anti-detect-browser.webp)

The mistake almost everyone makes the first time they use Playwright with an anti-detect browser is launching the browser from Playwright. `chromium.launch()` starts a Chromium of Playwright's choosing with Playwright's arguments, and none of the profile comes with it: not the fingerprint, not the proxy, not the cookies. With an anti-detect browser the order is the other way round. The browser starts itself, and Playwright attaches to it.

## Using Playwright with an anti-detect browser: why connectOverCDP

Every Chromium-based anti-detect browser can expose the Chrome DevTools Protocol, and Playwright's `connectOverCDP` "attaches Playwright to an existing browser instance" through it ([Playwright docs](https://playwright.dev/docs/api/class-browsertype#browser-type-connect-over-cdp), read 2 November 2026). The same page carries two warnings worth reading before you rely on it. The connection is "significantly lower fidelity" than Playwright's own protocol, and if the browser was launched without Playwright's curated arguments, "some of Playwright functionality may be broken". In practice the core of a script (pages, locators, clicks, waits) works; some tracing and context features do not.

Mosaic is a desktop app

Email yourself the link and open it on your computer.

[How it works: REST API](https://mosaicbrowser.com/features/rest-api)

## Step by step in Mosaic

Mosaic's [local REST API](https://mosaicbrowser.com/features/rest-api) starts profiles and hands back the endpoint. Make a key on the API screen first.

1. Start the profile: `POST /profiles/:id/start`. The reply carries `wsEndpoint`, `debugPort` and `cdpUrl`. A profile behind a proxy does not start until that proxy has answered, so a dead gateway is a `502` naming it, not a browser quietly browsing from your own address.
2. Attach: `chromium.connectOverCDP(started.wsEndpoint)`.
3. Take the profile's own context: `browser.contexts()[0]`. Do not call `browser.newContext()`. A new context has no cookies, so the site sees a stranger.
4. Use the page that is already open, or open one in that context.
5. Detach, then stop through the API, so Mosaic closes the browser over DevTools and Chromium writes its cookie jar.

```
import { chromium } from 'playwright'

const BASE = 'http://127.0.0.1:7317/api/v1'
const headers = { Authorization: `Bearer ${process.env.MOSAIC_KEY}` }

const started = await fetch(`${BASE}/profiles/${id}/start`, {
  method: 'POST', headers
}).then((r) => r.json())

const browser = await chromium.connectOverCDP(started.wsEndpoint)
const context = browser.contexts()[0]
const page = context.pages()[0] ?? await context.newPage()

await page.goto('https://example.com/account')
console.log(await page.title())

await browser.close()   // on a connected browser: detaches, clears contexts it created
await fetch(`${BASE}/profiles/${id}/stop`, { method: 'POST', headers })

```

For a browser Playwright connected to, `browser.close()` "clears all created contexts belonging to this browser and disconnects from the browser server" ([Playwright docs](https://playwright.dev/docs/api/class-browser), read 2 November 2026). It does not shut Mosaic's browser down; the stop call does.

![Mosaic's API screen, Automation tab, with the Playwright example: start a profile and connectOverCDP to its wsEndpoint](https://mosaicbrowser.com/shots/api-automation.png)
*API › Automation has this example with your port filled in*

## Leave the fingerprint to the browser

Playwright has options that look harmless: `viewport`, `userAgent`, `locale`, `timezoneId`, `geolocation`. On an attached anti-detect browser each one is a second spoof of a value the profile already set, applied through DevTools emulation on top of the engine's own. Two descriptions of one value compose into something neither side predicted, which is the kind of contradiction a consistency scanner looks for.

In Mosaic these values are changed inside [the engine](https://mosaicbrowser.com/features/engine), in C++, so every page, frame and worker sees one machine ([why we built our own Chromium](https://mosaicbrowser.com/blog/why-we-built-our-own-chromium) has the measurements behind that choice). The timezone, languages and geolocation are drawn for the exit the proxy really comes out of. Set none of them from Playwright. If a script needs a different locale, give it a profile that has one.

## The one thing Playwright cannot help sending

Playwright tracks execution contexts by enabling the DevTools `Runtime` domain on each page, and some detectors read that. The rebrowser project describes the technique: "a few lines of JavaScript on the page that are automatically called if Runtime.Enable was used", and says major anti-bot vendors use it ([rebrowser-patches](https://github.com/rebrowser/rebrowser-patches), read 2 November 2026).

We measured it on our own engine against deviceandbrowserinfo, one fresh profile per row. `Page.enable`, `Runtime.evaluate` and `Input.dispatchKeyEvent` left it at `isBot=false`. `Runtime.enable` flipped it to `isBot=true`. When we later kept `Runtime.enable` as a deliberate control in our check, it fired in two of four consecutive runs, so it is a signal some pages see some of the time, not a constant.

Two ways round it if your target checks:

- Mosaic's page routes (`/profiles/:id/page/snapshot`, `/page/click`, `/page/type` and the rest) read and act in an isolated world the page cannot see, and never enable `Runtime`. Clicks travel along a human path and typing has human timing.
- Third-party patches such as rebrowser's change how Playwright gets its execution contexts. We have not measured them, so we only point at them.

## Running many profiles

Start each profile, attach, work, detach and stop, one profile at a time or a few at once, within the concurrency cap in Settings. For work nobody will watch, pass `"offscreen": true` to the start call: the window goes off the screen and the browser stays headed, so it keeps the real GPU and a User-Agent without `HeadlessChrome` in it. The [guide to automating several profiles](https://mosaicbrowser.com/guides/automate-multiple-browser-profiles) covers batches, bulk start and the `{ ok, skipped, failures }` answer.

The REST API is part of Pro, $49 a month with a 14-day free trial, on the [pricing page](https://mosaicbrowser.com/pricing).

## Sources

1. [Playwright docs: BrowserType.connectOverCDP](https://playwright.dev/docs/api/class-browsertype#browser-type-connect-over-cdp), read November 2, 2026
2. [Playwright docs: Browser.close](https://playwright.dev/docs/api/class-browser), read November 2, 2026
3. [rebrowser-patches: Runtime.Enable leak (GitHub)](https://github.com/rebrowser/rebrowser-patches), read November 2, 2026

## Questions

### Should I use launch or connectOverCDP with an anti-detect browser?

connectOverCDP. The anti-detect browser launches itself with the profile's fingerprint, proxy and cookies applied. Launching from Playwright starts a different browser with Playwright's own arguments and none of the profile.

### Why is my Playwright page missing the profile's cookies?

Because the script called browser.newContext(). A new context starts empty. Use browser.contexts()[0], which is the profile's own context with its saved sign-ins.

### Does Playwright make the profile detectable?

It can. Playwright enables the DevTools Runtime domain on the pages it attaches to, and we measured that one call flipping deviceandbrowserinfo's verdict to isBot=true. For pages that check, Mosaic's own page routes read and click without it.

### Can I run the profile headless for Playwright?

We advise against it. A headless Chrome names itself in its User-Agent and drops the real GPU. In Mosaic, start the profile with offscreen instead: the window is parked off the screen and the browser stays headed.

## Related

[How to use Puppeteer with an anti-detect browser](https://mosaicbrowser.com/guides/use-puppeteer-with-an-anti-detect-browser): Use Puppeteer with an anti-detect browser through puppeteer.connect: start the profile, pass its wsEndpoint, set defaultViewport to null, then disconnect.

[How to automate multiple browser profiles](https://mosaicbrowser.com/guides/automate-multiple-browser-profiles): Automate multiple browser profiles by giving each account a persistent profile, starting each from a script and attaching Playwright or Puppeteer over CDP.

[Anti-detect browser REST API: profiles from your scripts](https://mosaicbrowser.com/features/rest-api): Mosaic's anti-detect browser REST API runs on 127.0.0.1 with API keys. Create and start profiles, then attach Puppeteer or Playwright over CDP.

[An anti-detect browser with its own Chromium engine](https://mosaicbrowser.com/features/engine): Mosaic is an anti-detect browser with its own Chromium engine, Tesseract Chrome: stock source plus 64 patches that change fingerprint values in C++.

[Why we built our own Chromium instead of injecting JavaScript](https://mosaicbrowser.com/blog/why-we-built-our-own-chromium): Mosaic changes fingerprint values in C++ inside its own engine. Three measured differences between Chrome and plain Chromium explain why that matters.







## Run this guide on your own accounts

Every Mosaic profile is a fingerprint, a proxy exit and a cookie jar that agree with each other, kept on your computer. Free holds 3 profiles. Pro is $49 a month for any number.

Mosaic is a desktop app

Email yourself the link and open it on your computer.
