Connecting Playwright
Connect Playwright to a persona through the gateway, or launch the bauta browser yourself with a persona file.
Playwright reaches a persona over CDP. Through the gateway only the connect call changes; you can also launch the bauta browser yourself and hand it a persona file.
Start the gateway
With bauta installed and set up (Getting Started), make a persona and start the gateway:
bauta geo update # the database that places a proxy's exit
bauta persona new shop --from win-intel
bauta serveEach persona is then a CDP endpoint of its own: http://127.0.0.1:9222/persona/<name>.
Connect from Python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp("http://127.0.0.1:9222/persona/shop")
page = browser.new_page()
page.goto("https://example.com")
print(page.evaluate("navigator.platform")) # Win32
browser.close()Connect from Node.js
const { chromium } = require("playwright-core");
const browser = await chromium.connectOverCDP("http://127.0.0.1:9222/persona/shop");
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.close();A client sees only its own persona's pages, as if the browser were its own. A persona keeps its own profile, so
its cookies and storage are there on the next connection. Its browser closes 30 seconds after its last client
leaves; bauta serve --idle changes that.
Launch the bauta browser yourself
Without the gateway, the browser takes a license and a persona file from its environment. The persona and font files below are in a checkout of the bauta-browser repository:
# once: the Windows font environment, which a Linux host presenting as Windows uses (needs fonttools: pip install fonttools)
personas/fonts/fetch.sh
bauta setup # once: a free session now; offers an account (GitHub). Writes ~/.bauta/license
BAUTA_LICENSE=~/.bauta/license \
BAUTA_PLUGIN_CONFIG=$PWD/personas/win-intel.json \
FONTCONFIG_FILE=$PWD/personas/fonts/win.conf \
/path/to/bauta/chrome --user-data-dir="$(mktemp -d)" https://example.com| variable | what it is |
|---|---|
BAUTA_LICENSE | The license file. bauta setup writes it to ~/.bauta/license. |
BAUTA_PLUGIN_CONFIG | The persona file, by absolute path. |
FONTCONFIG_FILE | The font environment that pairs with the persona: personas/fonts/win.conf for win-intel.json. |
/path/to/bauta/chrome is the bauta browser; bauta browser fetch downloads it for this machine.
The browser checks the license and reads the persona once, at launch, and hands the persona to every page it
opens, so the sandbox stays on. It prints [bauta] persona: <file> on stderr. If the page sees the real machine
instead, stderr says why: a license that is missing, expired or not ours, or a persona file that cannot be read or
contradicts itself. A license that expires while the browser runs does not stop it.
From Playwright, pass the same variables to launch():
import os
from playwright.sync_api import sync_playwright
env = dict(os.environ,
BAUTA_LICENSE="/abs/path/license",
BAUTA_PLUGIN_CONFIG="/abs/path/personas/win-intel.json",
FONTCONFIG_FILE="/abs/path/personas/fonts/win.conf")
with sync_playwright() as p:
browser = p.chromium.launch(executable_path="/path/to/bauta/chrome", headless=False, env=env)
page = browser.new_page()
page.goto("https://example.com")
print(page.evaluate("navigator.platform")) # Win32const { chromium } = require("playwright-core");
const env = {
...process.env,
BAUTA_LICENSE: "/abs/path/license",
BAUTA_PLUGIN_CONFIG: "/abs/path/personas/win-intel.json",
FONTCONFIG_FILE: "/abs/path/personas/fonts/win.conf",
};
const browser = await chromium.launch({ executablePath: "/path/to/bauta/chrome", headless: false, env });
const page = await browser.newPage();
await page.goto("https://example.com");
console.log(await page.evaluate("navigator.platform")); // Win32Timezone and locale are launch settings. The gateway sets them from the persona; when you launch the browser
yourself, set TZ, and LANGUAGE and LANG (for example en_US and en_US.UTF-8) in its environment.
navigator.webdriver
Every bundled persona answers navigator.webdriver with false, so an automated launch does not announce itself.
Clicks and user activation
A script you run is the page's, not a person's. page.evaluate and the like give the page no user activation: a
person's click or key, which Chrome requires to open a popup, go fullscreen or write the clipboard. With it, a page
would see an activation that no input came before. For what needs a person, click:
page.click("text=Open")A persona with "humanize": true makes clicks and typing move as a hand does.
The persona's identity is fixed
A client that sets its own User-Agent, viewport, locale or timezone is answered as if it had, but the page keeps the persona's.
Next
- Connecting Puppeteer
- Python and Node.js packages, which make the persona and connect for you
- The gateway