Launch Options
Launch options configure how each browser session starts and behaves. You pass them as query parameters or as a JSON object on the WebSocket connection URL when connecting via Puppeteer, Playwright, or any CDP client.
These are per-session settings. For server-level configuration (concurrency limits, timeouts, health checks), see the Docker Configuration Reference.
Configuration Methods
There are two ways to pass launch options:
- Query parameters go directly in the connection URL (e.g.,
&headless=false&stealth=true). Best for simple, standalone settings. - The
launchobject is a JSON string passed as a singlelaunchquery parameter. Use it for browser-level options that contain arrays or nested values, likeargs: [...], where brackets and quotes require encoding.
Both methods can be combined. Query parameters take precedence when the same option appears in both.
import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({
browserWSEndpoint: `ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&stealth=true&blockAds=true&timeout=60000`,
});
Quick Examples
These examples connect to an enterprise instance with a launch object that sets a custom window size via Chrome flags.
- Puppeteer
- Playwright CDP
- Playwright Connect
- Python
import puppeteer from "puppeteer-core";
const launch = btoa(JSON.stringify({
args: ["--window-size=1920,1080"],
}));
const browser = await puppeteer.connect({
browserWSEndpoint: `ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch=${launch}`,
});
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.close();
import { chromium } from "playwright-core";
const launch = btoa(JSON.stringify({
args: ["--window-size=1920,1080"],
}));
const browser = await chromium.connectOverCDP(
`ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch=${launch}`
);
const context = browser.contexts()[0] || (await browser.newContext());
const page = await context.newPage();
await page.goto("https://example.com");
await browser.close();
import { chromium } from "playwright-core";
const launch = btoa(JSON.stringify({
args: ["--window-size=1920,1080"],
}));
const browser = await chromium.connect(
`ws://localhost:3000/chromium/playwright?token=YOUR_API_TOKEN_HERE&launch=${launch}`
);
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.close();
import json
import base64
from playwright.sync_api import sync_playwright
launch = base64.b64encode(json.dumps({
"args": ["--window-size=1920,1080"],
}).encode()).decode()
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(
f"ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch={launch}"
)
context = browser.contexts[0] if browser.contexts else browser.new_context()
page = context.new_page()
page.goto("https://example.com")
browser.close()
Launch Object Options
The launch parameter accepts a JSON object with these properties:
| Option | Type | Default | Description |
|---|---|---|---|
args | string[] | [] | Chrome command-line flags passed to the browser process |
headless | boolean | true | Run the browser in headless mode |
stealth | boolean | false | Enable stealth mode to reduce automation detection |
slowMo | number | 0 | Add a delay (in ms) between each operation |
ignoreDefaultArgs | boolean | string[] | false | Remove all or specific default Chrome flags |
acceptInsecureCerts | boolean | false | Accept self-signed and expired TLS certificates |
acceptInsecureCerts replaces the older ignoreHTTPSErrors parameter, which has been renamed and deprecated by the Puppeteer team. Both are accepted for backwards compatibility, but use acceptInsecureCerts in new code.
Encoding the Launch Value
The launch value must be encoded before appending it to the URL. Base64 is the simplest approach because it avoids escaping brackets, quotes, and commas.
Base64 encoding
- JavaScript
- Python
import puppeteer from "puppeteer-core";
const launch = btoa(JSON.stringify({
args: ["--window-size=1280,720"],
headless: true,
}));
const browser = await puppeteer.connect({
browserWSEndpoint: `ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch=${launch}`,
});
import json
import base64
from playwright.sync_api import sync_playwright
launch = base64.b64encode(json.dumps({
"args": ["--window-size=1280,720"],
"headless": True,
}).encode()).decode()
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(
f"ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch={launch}"
)
URL encoding
- JavaScript
- Python
import puppeteer from "puppeteer-core";
const launch = JSON.stringify({
args: ["--window-size=1280,720"],
});
const browser = await puppeteer.connect({
browserWSEndpoint: `ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch=${encodeURIComponent(launch)}`,
});
import json
import urllib.parse
from playwright.sync_api import sync_playwright
launch = json.dumps({
"args": ["--window-size=1280,720"],
})
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(
f"ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&launch={urllib.parse.quote(launch)}"
)
Chrome Flags
Chrome flags are passed via the args array inside the launch object. Enterprise deployments support the full set of Chrome command-line switches, with no flag allowlist.
Before encoding:
{"args": ["--window-size=1920,1080", "--lang=en-US", "--disable-web-security"]}
Common flags:
--window-size=WIDTH,HEIGHTsets the initial browser window dimensions--lang=LOCALEsets the browser UI language--proxy-server=HOST:PORTroutes traffic through a proxy--proxy-bypass-list=HOSTSskips the proxy for specific hosts--disable-web-securitydisables same-origin policy (useful for testing)--user-data-dir=PATHsets a persistent browser profile directory--disable-gpudisables GPU hardware acceleration--disable-dev-shm-usagewrites shared memory files to/tmpinstead of/dev/shm--disable-features=FEATURE1,FEATURE2disables specific Chromium features--enable-features=FEATURE1,FEATURE2enables specific Chromium features
The enterprise image adds WebRTC leak prevention flags to every session automatically. These prevent your server's real IP from leaking through WebRTC:
--webrtc-ip-handling-policy=disable_non_proxied_udp--force-webrtc-ip-handling-policy--disable-features=WebRtcHideLocalIpsWithMdns--enforce-webrtc-ip-permission-check
You do not need to add these yourself.
Query Parameter Options
These parameters go directly in the connection URL as query strings.
| Parameter | Type | Default | Description |
|---|---|---|---|
token | string | — | API authentication token (matches the TOKEN env var) |
timeout | number | 30000 | Session timeout in milliseconds. The server-level TIMEOUT env var sets the upper bound. |
headless | boolean | true | Run the browser in headless mode |
stealth | boolean | false | Enable stealth mode to reduce automation detection |
blockAds | boolean | false | Block ads using the built-in uBlock Origin extension |
blockConsentModals | boolean | false | Block cookie consent modals and banners |
humanlike | boolean | false | Enable humanlike browsing behavior (mouse movements, typing delays) |
record | boolean | false | Record the session for later playback (requires license support) |
replay | boolean | false | Enable session replay (requires license support) |
solveCaptchas | boolean | false | Automatically solve captchas during the session (requires license support) |
Example with multiple query parameters:
import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({
browserWSEndpoint: `ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE&stealth=true&blockAds=true&timeout=120000`,
});
Browser Context Settings
Some browser settings operate at the page or context level and cannot be configured through launch parameters or Chrome flags. These include viewport dimensions, locale, timezone, user agent, and geolocation.
Set these using CDP commands or library-level APIs after connecting, before your first navigation.
- Puppeteer
- Playwright
import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({
browserWSEndpoint: `ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE`,
});
const page = await browser.newPage();
// Configure context-level settings before navigating
await page.setViewport({ width: 1920, height: 1080 });
await page.setUserAgent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
);
const cdp = await page.createCDPSession();
await cdp.send("Emulation.setTimezoneOverride", {
timezoneId: "America/New_York",
});
await cdp.send("Emulation.setLocaleOverride", {
locale: "en-US",
});
await cdp.send("Emulation.setGeolocationOverride", {
latitude: 40.7128,
longitude: -74.006,
accuracy: 100,
});
// Now navigate
await page.goto("https://example.com");
await browser.close();
import { chromium } from "playwright-core";
const browser = await chromium.connectOverCDP(
`ws://localhost:3000/chromium?token=YOUR_API_TOKEN_HERE`
);
// Playwright sets context-level options when creating a new context
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent:
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
locale: "en-US",
timezoneId: "America/New_York",
geolocation: { latitude: 40.7128, longitude: -74.006 },
permissions: ["geolocation"],
});
const page = await context.newPage();
// Now navigate
await page.goto("https://example.com");
await browser.close();
Issue these commands before your first page.goto() call. Any navigation that happens before the overrides are in place will use the browser's default settings.
When stealth mode is active, the enterprise image auto-configures timezone and browser locale based on proxy location data. You only need to set these manually for non-stealth sessions or when you want to override the automatic values.
Automatic CDP Behaviors
The enterprise image intercepts and modifies certain CDP commands behind the scenes:
- Viewport normalization: If a client sends an
Emulation.setDeviceMetricsOverridewith the default 800x600 dimensions, the image resets width and height to 0 (full viewport). This prevents detection via a hardcoded viewport size. - Target filtering:
Target.setDiscoverTargetsresponses filter out worker threads, reducing automation fingerprints visible to page scripts. - Browser close protection:
Browser.closeandBrowser.crashcommands return a success response without terminating the browser process. This prevents client code from accidentally killing a shared session. - Download path enforcement:
Browser.setDownloadBehaviorcalls are redirected to the configured downloads directory.
These behaviors are transparent. You do not need to account for them in your code.
Enterprise vs. BaaS Differences
What enterprise adds
- All Chrome flags: Pass any Chrome command-line switch via
args. BaaS restricts flags to an allowlist. --user-data-dir: Point to a persistent browser profile directory for cookies, cache, and local storage across sessions.- Full
ignoreDefaultArgs: Remove any default Chrome flags without restriction. - Custom extensions and fonts: Mount extensions and font files directly into the container via Docker volumes.
What stays the same
- Launch JSON format: Same JSON structure and encoding methods (base64, URL encoding).
- Core query parameters:
token,timeout,stealth,blockAds,headless, and other standalone params work identically. - Library connection methods: Puppeteer
connect(), PlaywrightconnectOverCDP(), and Playwrightconnect()all work the same way.
What BaaS has that enterprise does not
- Managed residential proxies: The
proxy,proxyCountry,proxyCity,proxyState,proxySticky,proxyLocaleMatch, andproxyPresetparameters are BaaS-only. For enterprise, configure proxies via the--proxy-serverChrome flag or an external proxy service.