Browsernode uses playwright (or patchright) to manage its connection with a real browser.
To launch or connect to a browser, pass any playwright / browsernode configuration arguments you want to BrowserSession(...):
import { BrowserSession, Agent } from "browsernode";

const browserSession = new BrowserSession({
    headless: true,
    viewport: { width: 964, height: 647 },
    userDataDir: "~/.config/browsernode/profiles/default",
});

const agent = new Agent({
  task: "fill out the form on this page",
  browserSession: browserSession,
});
The new BrowserSession & BrowserProfile accept all the same arguments that Playwright’s launchPersistentContext(...) takes, giving you full control over browser settings at launch. (see below for the full list)

BrowserSession

  • BrowserSession() is browsernode’s object that tracks a connection to a running browser. It sets up:
    • the playwright, browser, browserContext, and page objects and tracks which tabs the agent/human are focused on
    • methods to interact with the browser window, apply config needed by the Agent, and run the DOMService for element detection
    • it can take a browserProfile=BrowserProfile(...) template containing some config defaults,session-specific config overrides

Browser Connection Parameters

Provide any one of these options to connect to an existing browser. These options are session-specific and cannot be stored in a BrowserProfile(...) template.

wssUrl

wssUrl: string | null = null
WSS URL of the playwright-protocol browser server to connect to. See here for WSS connection instructions.

cdpUrl

cdpUrl: string | null = null
CDP URL of the browser to connect to (e.g. http://localhost:9222). See here for CDP connection instructions.

browserPid

browserPid: number | null = null
PID of a running chromium-based browser process to connect to on localhost. See here for connection via pid instructions.
For web scraping tasks on sites that restrict automated access, we recommend using our cloud or an external browser provider for better reliability. See the Connect to your Browser guide for detailed connection instructions.

Session-Specific Parameters

browserProfile

browserProfile: BrowserProfile = BrowserProfile()
Optional BrowserProfile template containing default config to use for the BrowserSession. (see below for more info)

playwright

playwright: Playwright | null = null
Optional playwright or patchright API client handle to use, the result of (import { chromium as PlaywrightChromium } from "playwright"; PlaywrightChromium) or ( import { chromium as PatchrightChromium } from "patchright"; PatchrightChromium), which spawns a node.js child subprocess that relays commands to the browser over CDP. See here for more detailed usage instructions.

browser

browser: Browser | null = null
Playwright Browser object to use (optional). See here for more detailed usage instructions.

browserContext

browserContext: BrowserContext | null = null
Playwright BrowserContext object to use (optional). See here for more detailed usage instructions.

page aka agentCurrentPage

page: Page | null = null
Foreground Page that the agent is focused on, can also be passed as page=... as a shortcut. See here for more detailed usage instructions.

humanCurrentPage

humanCurrentPage: Page | null = null
Foreground Page that the human is focused on to start, not necessary to set manually.

initialized

initialized: boolean = false
Mark BrowserSession as already initialized, skips launch/connection (not recommended)

params

BrowserSession can also accept all of the parameters below. (the parameters above this point are specific to BrowserSession and cannot be stored in a BrowserProfile template) Extra {...params} passed to BrowserSession(...) act as session-specific overrides to the BrowserProfile(...) template.
baseIphone13 = BrowserProfile(
    storageState='/tmp/auth.json',     # share cookies between parallel browsers
    ...playwright.devices['iPhone 13'],
    timezoneId='UTC',
)
usaPhone = BrowserSession(
    browserProfile=baseIphone13,
    timezoneId='America/New_York',     # kwargs override values in baseIphone13
)
euPhone = BrowserSession(
    browserProfile=baseIphone13,
    timezoneId='Europe/Paris',
)

usaAgent = Agent({task: 'show me todays schedule...', browserSession: usaPhone})
euAgent = Agent({task: 'show me todays schedule...', browserSession: euPhone})
await Promise.all([usaAgent.run(), euAgent.run()])

BrowserProfile

A BrowserProfile is a 📋 config template for a 🎭 BrowserSession(...). It’s basically just a typed + validated version of a dict to hold config. When you find yourself storing or re-using many browser configs, you can upgrade from:
- config = {key: val, key: val, ...}
- BrowserSession({...config})
To this instead:
+ config = BrowserProfile(key=val, key=val, ...)
+ BrowserSession(browserProfile=config)
You don’t ever need to use a BrowserProfile, you can always pass config parameters directly to BrowserSession:
session = BrowserSession(headless=True, storageState='auth.json', viewport={...}, ...)
BrowserProfile is optional, but it provides a number of benefits over a normal Record<string, unknown> for holding config:
  • has type hints and pydantic field descriptions that show up in your IDE
  • validates config at runtime quickly without having to start a browser
  • provides helper methods to autodetect screen size, set up local paths, save/load config as json, and more…
BrowserProfiless are designed to easily be given 🆔 uuids and put in a database + made editable by users. BrowserSessions get their own 🆔 uuids and be linked by 🖇 foreign key to whatever BrowserProfiles they use.This cleanly separates the per-connection rows from the bulky re-usable config and avoids wasting space in your db. This is useful because a user may only have 2 or 3 profiles, but they could have 100k+ sessions within a few months.
BrowserProfile and BrowserSession can both take any of the: The only parameters BrowserProfile can NOT take are the session-specific connection parameters and live playwright objects: cdpUrl, wssUrl, browserPid, page, browser, browserContext, playwright, etc.

Basic Example

import { BrowserProfile } from "browsernode/browser";

const profile = new BrowserProfile(
    stealth: true,
    storageState: '/tmp/google_docs_cookies.json',
    allowedDomains: ['docs.google.com', 'https://accounts.google.com'],
    viewport: { width: 396, height: 774 },
    # ... playwright args / browsernode config args ...
)

const phone1 = new BrowserSession(browserProfile: profile, deviceScaleFactor: 1)
const phone2 = new BrowserSession(browserProfile: profile, deviceScaleFactor: 2)
const phone3 = new BrowserSession(browserProfile: profile, deviceScaleFactor: 3)

browsernode Parameters

These parameters control browsernode-specific features, and are outside the standard playwright set. They can be passed to BrowserSession(...) and/or stored in a BrowserProfile template.

keepAlive

keepAlive: boolean | null = null
If True it wont close the browser after the first agent.run() ends. Useful for running multiple tasks with the same browser instance. If this is left as null and the Agent launched its own browser, the default is to close the browser after the agent completes. If the agent connected to an existing browser then it will leave it open.

stealth

stealth: boolean = false
Set to True to use patchright to avoid bot-blocking. (Might cause issues with some sites, requires manual testing.)

allowedDomains

allowedDomains: list[str] | null = null
List of allowed domains for navigation. If null, all domains are allowed. Example: ['google.com', '*.wikipedia.org'] - Here the agent will only be able to access google.com exactly and wikipedia.org + *.wikipedia.org. Glob patterns are supported:
  • ['example.com'] ✅ will match only https://example.com/* exactly, subdomains will not be allowed. It’s always the most secure to list all the domains you want to give the access to explicitly w/ schemes e.g. ['https://google.com', 'http*://www.google.com', 'https://myaccount.google.com', 'https://mail.google.com', 'https://docs.google.com']
  • ['*.example.com'] ⚠️ CAUTION this will match https://example.com and all its subdomains. Make sure all the subdomains are safe for the agent! abc.example.com, def.example.com, …, useruploads.example.com, admin.example.com

disableSecurity

disableSecurity: boolean = false
⚠️ Setting this to True is NOT RECOMMENDED.
It completely disables all basic browser security features.
This option is for debugging and interacting across cross-origin iFrames when there are no cookies or sensitive data in use. It’s very INSECURE, under no circumstances should you enable this while using real cookies or sensitive data, visiting a single untrusted URL in this mode can immediately compromise all the profile cookies instantly. Consider a less nuclear option like bypassCsp=True instead.

deterministicRendering

deterministicRendering: boolean = false
⚠️ Setting this to True is NOT RECOMMENDED.
It can be glitchy & slow, and it increases chances of getting blocked by anti-bot systems. It’s mostly useful for QA applications.
It’s a shortcut for adding these launch args:
  • --deterministic-mode
  • --js-flags=--random-seed=1157259159
  • --force-color-profile=srgb
  • --font-render-hinting=null
  • --force-device-scale-factor=2
  • --enable-webgl
With these options fonts will look slightly worse than macOS and slightly than Windows, but rendering will be more consistent between OSs and runs. The cost is performance and stability. Software rendering is slower, easier to fingerprint as a bot, and sometimes glitchy. You likely don’t need this option unless you’re trying to do screenshot diffing.

highlightElements

highlightElements: bool = True
Highlight interactive elements on the screen with colorful bounding boxes.

viewportExpansion

viewportExpansion: int = 500
Viewport expansion in pixels. With this you can control how much of the page is included in the context of the LLM:
  • -1: All elements from the entire page will be included, regardless of visibility (highest token usage but most complete).
  • 0: Only elements which are currently visible in the viewport will be included.
  • 500 (default): Elements in the viewport plus an additional 500 pixels in each direction will be included, providing a balance between context and token usage.

includeDynamicAttributes

includeDynamicAttributes: boolean = true
Include dynamic attributes in selectors for better element targeting.

minimumWaitPageLoadTime

minimumWaitPageLoadTime: number = 0.25
Minimum time to wait before capturing page state for LLM input.

waitForNetworkIdlePageLoadTime

waitForNetworkIdlePageLoadTime: number = 0.5
Time to wait for network activity to cease. Increase to 3-5s for slower websites. This tracks essential content loading, not dynamic elements like videos.

maximumWaitPageLoadTime

maximumWaitPageLoadTime: number = 5.0
Maximum time to wait for page load before proceeding.

waitBetweenActions

waitBetweenActions: number = 0.5
Time to wait between agent actions.

cookiesFile

cookiesFile: string | null = null
JSON file path to save cookies to.
This option is DEPRECATED. Use storageState instead, it’s the standard playwright format and also supports localStorage and indexedDB!The library will automatically save a new storageState.json next to any cookiesFile path you provide, just use `storageState=‘path/to/storageState.json’ to switch to the new format:cookiesFile.json: [{cookie}, {cookie}, {cookie}]
⬇️ storage_state.json: {"cookies": [{cookie}, {cookie}, {cookie}], "origins": {... optional localstorage state ...}}
Or run playwright open https://example.com/ --save-storage=storage_state.json and log into any sites you need to generate a fresh storage state file.

profileDirectory

profileDirectory: string = 'Default'
Chrome profile subdirectory name inside of your userDataDir (e.g. Default, Profile 1, Work, etc.). No need to set this unless you have multiple profiles set up in a single userDataDir and need to use a specific one.

windowPosition

windowPosition: Record<string, number> | null = {"width": 0, "height": 0}
Window position from top-left corner.

saveRecordingPath

saveRecordingPath: string | null = null
Directory path for saving video recordings.

tracePath

tracePath: string | null = null
Directory path for saving Agent trace files. Files are automatically named as {tracePath}/{contextId}.zip.

Playwright Launch Options

All the parameters below are standard playwright parameters and can be passed to both BrowserSession and BrowserProfile. They are defined in browsernode/browser/profile.ts. See here for the official Playwright documentation for all of these options.

headless

headless: boolean | null = null
Runs the browser without a visible UI. If null, auto-detects based on display availability. If you set headless=False on a server with no monitor attached, the browser will fail to launch (use xvfb + vnc to give a headless server a virtual display you can remote control). headless=False is recommended for maximum stealth and is required for human-in-the-loop workflows.

channel

channel: BrowserChannel = 'chromium'
Browser channel: ['chromium'] (default when stealth=False), 'chrome' (default when stealth=True), 'chrome-beta', 'chrome-dev', 'chrome-canary', 'msedge', 'msedge-beta', 'msedge-dev', 'msedge-canary' Don’t worry, other chromium-based browsers not in this list (e.g. brave) are still supported if you provide your own executablePath, just set it to chromium for those.

executablePath

executablePath: string | Path | null = null
Path to browser executable for custom installations.

userDataDir

userDataDir: string | Path | null = '~/.config/browsernode/profiles/default'
Directory for browser profile data. Set to null to use an ephemeral temporary profile (aka incognito mode). Multiple running browsers cannot share a single userDataDir at the same time. You must set it to null or provide a unique userDataDir per-session if you plan to run multiple browsers. The browser version run must always be equal to or greater than the version used to create the userDataDir. If you see errors like Failed to parse Extensions or similar and failures when launching, you’re attempting to run an older browser with an incompatible userDataDir that’s already been migrated to a newer schema version.

args

args: string[] = []
Additional command-line arguments to pass to the browser. See here for the full list of available chrome launch options.

ignoreDefaultArgs

ignoreDefaultArgs: list[str] | bool = ['--enable-automation', '--disable-extensions']
List of default CLI args to stop playwright from including when launching chrome. Set it to True to disable all default options (not recommended).

env

env: Record<string, string> = {}
Extra environment variables to set when launching browser. e.g. {'DISPLAY': '1'} to use a specific X11 display.

chromiumSandbox

chromiumSandbox: bool = not IN_DOCKER
Whether to enable Chromium sandboxing (recommended for security). Should always be False when running inside Docker because Docker provides its own sandboxing can conflict with Chrome’s.

devtools

devtools: bool = False
Whether to open DevTools panel automatically (only works when headless=False).

slowMo

slowMo: float = 0
Slow down actions by this many milliseconds.

timeout

timeout: float = 30000
Default timeout in milliseconds for connecting to a remote browser.

acceptDownloads

acceptDownloads: bool = True
Whether to automatically accept all downloads.

proxy

proxy: Record<string, unknown> | null = null
Proxy settings. Example: {"server": "http://proxy.com:8080", "username": "user", "password": "pass"}.

permissions

permissions: string[] = ['clipboard-read', 'clipboard-write', 'notifications']
Browser permissions to grant. See here for the full list of available permission.

storageState

storageState: string | Path | Record<string, unknown> | null = null
Browser storage state (cookies, localStorage). Can be file path or dict. See here for the Playwright storageState documentation on how to use it. This option is only applied when launching a new browser using the default builtin playwright chromium and userDataDir=null is set.
# to create a storage state file, run the following and log into the sites you need once the browser opens:
playwright open https://example.com/ --save-storage=./storageState.json
# then setup a BrowserSession with storageState='./storageState.json' and userDataDir=null to use it

Playwright Timing Settings

These control how the browser waits for CDP API calls to complete and pages to load.

defaultTimeout

defaultTimeout: number | null = null
Default timeout for Playwright operations in milliseconds (e.g. 10000 if you want 10s).

defaultNavigationTimeout

defaultNavigationTimeout: number | null = null
Default timeout for page navigation in milliseconds (e.g. 30000 if you want 30s).

Playwright Viewport Options

Configure browser window size, viewport, and display properties:

userAgent

userAgent: string | null = null
Specific user agent to use in this context. See playwright.devices.

isMobile

isMobile: boolean = false
Whether the meta viewport tag is taken into account and touch events are enabled.

hasTouch

hasTouch: boolean = false
Specifies if viewport supports touch events.

geolocation

geolocation: Record<string, number> | null = null
Geolocation coordinates. Example: {"latitude": 59.95, "longitude": 30.31667}

locale

locale: string | null = null
Specify user locale, for example en-GB, de-DE, etc. Locale will affect the navigator.language value, Accept-Language request header value as well as number and date formatting rules.

timezoneId

timezoneId: string | null = null
Timezone identifier (e.g. 'America/New_York' or 'UTC').

windowSize

windowSize: Record<string, number> | null = null
Browser window size for headful mode. Example: {"width": 1920, "height": 1080}

viewport

viewport: Record<string, number> | null = null
Viewport size with width and height. Example: {"width": 1280, "height": 720}

noViewport

noViewport: boolean | null = not headless
Disable fixed viewport. Content will resize with window. Tip: don’t use this parameter, it’s a playwright standard parameter but it’s redundant and only serves to override the viewport setting above. A viewport is always used in headless mode regardless of this setting, and is never used in headful mode unless you pass viewport={width, height} explicitly.

deviceScaleFactor

deviceScaleFactor: number | null = null
Device scale factor (DPI). Useful for high-resolution screenshots (set it to 2 or 3).

screen

screen: Record<string, number> | null = null
Screen size available to browser. Auto-detected if not specified.

colorScheme

colorScheme: ColorScheme = 'light'
Preferred color scheme: 'light', 'dark', 'no-preference'

contrast

contrast: Contrast = 'no-preference'
Contrast preference: 'no-preference', 'more', 'null'

reducedMotion

reducedMotion: ReducedMotion = 'no-preference'
Reduced motion preference: 'reduce', 'no-preference', 'null'

forcedColors

forcedColors: ForcedColors = 'null'
Forced colors mode: 'active', 'null'

Playwright Security Options

See allowedDomains above too!

offline

offline: boolean = false
Emulate network being offline.

httpCredentials

httpCredentials: Record<string, unknown> | null = null
Credentials for HTTP authentication.

extraHTTPHeaders

extraHTTPHeaders: Record<string, string> = {}
Additional HTTP headers to be sent with every request.

ignoreHTTPSErrors

ignoreHTTPSErrors: boolean = false
Whether to ignore HTTPS errors when sending network requests.

bypassCSP

bypassCSP: boolean = false
Enabling this can increase security risk and makes the bot very easy to fingerprint. (Cloudflare, Datadome, etc. will block you)
Toggles bypassing Content-Security-Policy. Enabling reduces some CSP-related errors that can arise from automation scripts injected into pages with strict policies that forbid inline scripts.

javaScriptEnabled

javaScriptEnabled: boolean = true
Not recommended, untested with browsernode and likely breaks things.
Whether or not to enable JavaScript in the context.

serviceWorkers

serviceWorkers: ServiceWorkers = 'allow'
Whether to allow sites to register Service workers: 'allow', 'block'

baseURL

baseURL: string | null = null
Base URL to be used in page.goto() and similar operations.

strictSelectors

strictSelectors: boolean = false
If true, selector passed to Playwright methods will throw if more than one element matches.

clientCertificates

clientCertificates: ClientCertificate[] = []
Client certificates to be used with requests.

Playwright Recording Options

Note: browsernode also provides some of our own recording-related options not listed below (see above).

recordVideoDir

recordVideoDir: string | null = null
Directory to save .webm video recordings. Playwright Docs: recordVideoDir
This parameter also has an alias saveRecordingPath for backwards compatibility with past versions, but we recommend using the standard Playwright name recordVideoDir going forward.

recordVideoSize

recordVideoSize: Record<string, number> | null = null

Video size. Example: {"width": 1280, "height": 720}

recordHarPath

recordHarPath: string | null = null
Path to save .har network trace files. Playwright Docs: recordHarPath
This parameter also has an alias saveHarPath for backwards compatibility with past versions, but we recommend using the standard Playwright name recordHarPath going forward.

recordHarContent

recordHarContent: RecordHarContent = 'embed'
How to persist HAR content: 'omit', 'embed', 'attach'

recordHarMode

recordHarMode: RecordHarMode = 'full'
HAR recording mode: 'full', 'minimal'

recordHarOmitContent

recordHarOmitContent: boolean = false
Whether to omit request content from the HAR.

recordHarUrlFilter

recordHarUrlFilter: string | RegExp | null = null
URL filter for HAR recording.

downloadsPath

downloadsPath: string | null = '~/.config/browsernode/downloads'
(aliases: downloadsDir, saveDownloadsPath) Local filesystem directory to save browser file downloads to.

tracesDir

tracesDir: string | null = null
Directory to save all-in-one trace files. Files are automatically named as {tracesDir}/{contextId}.zip. Playwright Docs: tracesDir
This parameter also has an alias tracePath for backwards compatibility with past versions, but we recommend using the standard Playwright name tracesDir going forward.

handleSIGHUP

handleSIGHUP: boolean = true
Whether playwright should swallow SIGHUP signals and kill the browser.

handleSIGINT

handleSIGINT: boolean = false
Whether playwright should swallow SIGINT signals and kill the browser.

handleSIGTERM

handleSIGTERM: boolean = false
Whether playwright should swallow SIGTERM signals and kill the browser.

Full Example

import { BrowserSession, BrowserProfile, Agent } from "browsernode";

browserProfile = BrowserProfile(
    headless: false,
    storageState: "path/to/storage_state.json",
    waitForNetworkIdlePageLoadTime: 3.0,
    viewport: { width: 1280, height: 1100 },
    locale: 'en-US',
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36',
    highlightElements: true,
    viewportExpansion: 500,
    allowedDomains: ['*.google.com', 'http*://*.wikipedia.org'],
    userDataDir: null,
)

const browserSession = new BrowserSession(
    browserProfile: browserProfile,
    headless: true,                          # extra kwargs to the session override the defaults in the profile
)

# you can drive a session without the agent / reuse it between agents
await browserSession.start()
const page = await browserSession.getCurrentPage()
await page.goto('https://example.com/first/page')

async function runSearch(): Promise<void> {
    const agent = new Agent({
        task: 'Your task',
        llm: llm,
        page: page,                        // optional: pass a specific playwright page to start on
        browserSession: browserSession,  // optional: pass an existing browser session to an agent
    })
}

Summary

  • BrowserSession (defined in browsernode/src/browser/session.ts) handles the live browser connection and runtime state
  • BrowserProfile (defined in browsernode/src/browser/profile.ts) is a template that can store default config parameters for a BrowserSession(...)
Configuration parameters defined in both scopes consumed by these calls depending on whether we’re connecting/launching:
  • BrowserConnectArgs - args for BrowserType.connect(...)
  • BrowserLaunchArgs - args for BrowserType.launch(...)
  • BrowserNewContextArgs - args for BrowserType.newContext(...)
  • BrowserLaunchPersistentContextArgs - args for BrowserType.launchPersistentContext(...)
  • browsernode’s own internal methods
For more details on Playwright’s browser context options, see their launch args documentation.