For AI agents: a documentation index is available at /llms.txt
Skip to main content

Migrate to BAP

BAP borrows Puppeteer's method names in TypeScript and Playwright's in Python, but it isn't a drop-in replacement for either: it runs over BrowserQL instead of a live CDP session, so anything that needs direct browser control has no equivalent. This guide covers what changes, what doesn't carry over, and what BAP adds that neither library has.

Prerequisites
  • An existing Puppeteer or Playwright script
  • A Browserless API token from your account dashboard
  • The BAP Quickstart if you haven't installed and connected yet

Should you migrate?

Migrate to BAP when you want BrowserQL's managed stealth, proxies, and CAPTCHA solving without hand-writing GraphQL, and your script doesn't rely on page.mouse, page.keyboard, frames, or browser contexts. If it does, keep the script as-is and connect it to Browsers as a Service (BaaS) over CDP instead.

Method differences

Page borrows Puppeteer's method names, but some shared methods behave differently:

MethodPuppeteerBAP
$eval(selector, fn)Runs your function against the matched element and returns its resultReturns the text content of the matched selector. No function argument
$$eval(selector, fn)Runs your function against all matched elementsDelegates to mapSelector and returns structured MapSelectorResponse[]
evaluate(fn, ...args)Passes serialized arguments and returns deserialized resultsAccepts a string or function, always returns string | null, and passes no arguments
waitForRequest / waitForResponseAccept a URL string or a predicate functionAccept a URL string or an options object. No predicate functions
scroll()Not on Page. You use mouse.wheel() or evaluate()First-class method with selector and coordinate targeting

What has no BAP equivalent

These Puppeteer APIs have no BAP equivalent, because they need a live CDP session:

  • Input devices: no page.keyboard, page.mouse, or page.touchscreen
  • Frames: no page.frames(), page.mainFrame(), or frame targeting
  • Workers: no page.workers()
  • Function exposure: no exposeFunction()
  • Emulation: no emulate() or emulateCPUThrottling(), though emulateMediaType() is supported
  • Security and cache: no setBypassCSP(), setCacheEnabled(), or setOfflineMode()
  • Coverage, tracing, and accessibility: no page.coverage, page.tracing, or page.accessibility

What BAP adds

BAP adds methods Puppeteer has no equivalent for: html(), text(), markdown(), mapSelector(), check()/uncheck(), reject(), proxy(), solve(), solveImageCaptcha(), liveURL(), reconnect(), switchToWindow(), stopSessionRecording(), preferences(), loadSecret(), fulfill(), and request()/response().

FAQ & Troubleshooting

Can I reuse my existing script unchanged?

Not without changes. BAP covers the subset of Puppeteer or Playwright that BrowserQL can express, so anything using page.mouse, page.keyboard, frames, browser contexts, or page.route() needs rewriting. If you want to run existing scripts unchanged, use BaaS over CDP instead.

Why does evaluate() return a string when my function returns an object?

evaluate() always resolves to a string (or null/None), and it takes no arguments. Serialize inside the page with JSON.stringify() and parse the result yourself.

Next steps

Was this page helpful?