npm.io
1.0.0 • Published yesterday

@browserless.io/bap-ts

Licence
MIT
Version
1.0.0
Deps
1
Size
236 kB
Vulns
0
Weekly
0

browser-automation-protocol

⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠇⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠧⡇⠀⠀⠒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⡤⡆⠦⠆⢀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠧⣷⣆⠅⢦⠀⠀⠀⠀⠀⠀⠀⠀⠠⠀⠈⠀⠀⠀⠀⠀⢤⣤⣆⢇⣶⣤⡤⡯⣦⣌⡡⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠷⣿⣷⣆⣐⡆⠀⠀⠀⠀⢀⠤⠊⠀⠀⢀⣠⣾⢯⣦⣴⣜⣺⣾⣿⣤⠟⠋⣷⢛⡣⠭⠢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠯⣿⣷⢫⡯⠄⠀⠀⢀⠐⠁⠀⠀⠀⠠⣤⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣙⣷⡗⢤⡤⠀⠈⣰⠶⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣩⣿⡏⠉⠉⠀⢠⡔⠁⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠑⣏⠶⡉⠖⣡⠂⣈⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣮⣿⣧⣤⣤⠖⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⢉⡻⣿⣿⣿⣿⣿⣿⣿⣿⠟⠓⠈⠅⠈⠀⠀⠘⢒⣽⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣿⡿⠛⠉⠀⠀⠀⣀⠔⢀⡴⣃⠀⠀⢀⠷⠲⡄⠸⠟⢋⣿⣿⣿⣿⣿⡇⠀⠀⠀⠐⠁⠀⠀⠂⠀⠀⠰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⡆⣷⣆⡐⠶⠤⢤⣷⣀⣀⣩⢐⣟⣥⠜⣤⣀⣠⣤⠀⠈⠉⢀⣹⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⢃⣿⣞⣫⡔⢆⡸⡿⣿⣿⣄⣰⣿⠁⢀⣛⠿⣻⣿⣿⣧⣬⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⢀
⢼⣿⣟⢿⣧⣾⣵⣷⣿⣿⣟⡿⢿⣶⣞⣍⡴⢿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⣠⠈⠀⢀⣀⣼
⠋⣿⣟⡛⢿⣿⣿⣿⣿⣿⣭⣿⣿⣿⣿⣯⣽⣿⣿⣿⣿⠟⠛⠿⢽⣿⣿⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣀⢀⡠⣤⣤⣰⣿⠟⠁⠀⠀⡼⢾⣿
⣻⣿⣟⣇⠈⣉⣯⠿browserless⣿⠿⠃⠀⠀⠀⠀⠀⠻⣿⣿⣿⣿⣴⣶⣤⣤⣤⣤⣴⣴⣴⣶⣦⣦⣤⣦⣀⣦⣤⣶⣿⣿⣿⣿⣿⣿⣿⠿⠁⠀⠀⡀⣤⣬⣾⣿
⡝⣿⣿⣇⣤⣶⣿⣷⣾⣭⡿⠻⢿⣿⣿⣿⣿⠿⠃⠀⠀⠀⠀⡄⠀⠀⠀⢊⡻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠋⢻⣿bap⣟⢿⠟⢉⠀⡀⢤⣴⣿⣿⣿⠿⠻
⡁⣻⣿⣿⣿⣿⣷⣿⣿⣿⣿⠾⣿⡿⠞⠁⠀⠀⠀⠀⠀⠔⠫⡅⠀⠀⠀⠀⠁⣀⠀⠈⠻⣿⣿⣿⣿⣻⢟⣁⣄⡄⣀⠙⠻⣿⣿⡿⠿⠛⡋⠕⠂⢀⣀⣄⣓⣳⢿⠟⢛⣩⠴⠈⠀
⠂⡁⠈⠛⠛⠛⠛⠋⠁⠀⠈⠈⡀⠀⠀⠀⠀⢀⠘⠀⠀⠀⠆⠀⡀⡢⣀⣆⠄⠈⠨⢦⡀⣈⠙⠛⠿⢿⣿⣿⣿⣿⣿⡿⡿⠿⠟⠆⠒⠁⠀⢶⣾⠿⠟⠛⢉⣀⣠⡶⠚⠁⠀⠀⣠
⠀⡇⡄⣀⡀⠀⠀⠀⠀⠀⠀⠀⢬⠠⠀⡀⠀⠋⠁⠀⡀⠀⠀⡀⠆⢱⣿⣿⣧⣧⣄⠛⣿⣞⣵⣤⣷⣄⠀⠀⠀⠐⠀⠀⠀⠀⠀⠈⠉⠁⠁⠀⠠⢤⣶⣾⣿⡿⠋⢀⣀⣰⣶⣾⣿
⡀⡆⠀⡉⡁⢿⣉⢀⠀⣰⣷⣿⣟⠠⡽⢂⡀⡄⠀⠰⣖⢱⢖⢂⡆⠈⣿⣿⣿⣿⣿⣶⣄⡙⠻⢿⣿⣿⣷⣦⣀⠀⠠⣤⣀⡀⢈⣓⣶⣶⣿⣿⣿⣿⣿⠟⠉⠀⠀⠀⣉⣭⣽⣿⣿
⡇⣯⣿⣿⣿⣾⣿⣿⣿⠿⠟⡡⢞⣹⠾⢻⣚⣛⢺⠞⢋⣭⣾⣧⡃⢄⡈⢿⣿⣿⣿⣿⣿⣿⣯⣿⣮⣽⣿⣿⣿⣿⣷⣬⣽⣿⣿⣿⣽⡿⣿⡿⠟⠋⢀⣀⣐⣺⣿⣿⣟⣫⣭⣿⣿
⢳⣿⣿⣿⣿⣿⣿⣿⣿⣤⣿⣿⣿⣿⣿⣦⠒⠉⢁⡀⠀⣙⣛⢿⣷⣶⣅⠀⠙⠻⣿⣿⣿⣿⣟⡚⠛⠻⠞⠿⠿⡿⡿⠯⠁⠟⣊⠾⠝⢋⣁⣀⣤⣤⣿⣿⣿⡿⠿⠿⠻⠛⠻⠻⠿
⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣐⣾⡿⡟⢶⠾⢋⢹⠿⢿⣿⣿⣷⣦⡈⠙⠛⠿⠿⢿⣶⣶⣶⣶⣶⢶⠟⠚⠀⠁⠀⠀⠙⠛⠛⠛⠛⠛⠋⠉⠁⠀⠀⠀⠀⠀⢀⠀⠀

A Puppeteer-like TypeScript SDK for Browserless. Browser Automation Protocol wraps the BrowserQL GraphQL-over-WebSocket API with a familiar, strongly-typed interface. Enjoy a puppeteer-like experience, with the best-in-class browser automation engine.

If you're going to surf, you might as well surf the Browser Automation Protocol

Table of Contents

Install

npm install @browserless.io/bap-ts

Quick Start

import Browserless from "@browserless.io/bap-ts";

const browser = Browserless.connect({
  browserWSEndpoint: "wss://production-sfo.browserless.io/chromium/bql",
  token: "your-api-token",
});

const page = await browser.newPage();
await page.goto("https://example.com");

const title = await page.title();
console.log(title); // "Example Domain"

await browser.close();

Browser & Node

The library is isomorphic. In Node it uses the ws package; bundlers targeting the browser (Vite, webpack, esbuild, Rollup) automatically pick the native WebSocket build via the browser export condition — no ws and no Node built-ins end up in the bundle.

Two platform differences:

  • screenshot() / pdf() resolve to a Uint8Array (in Node the value is a Buffer, which is a Uint8Array).
  • The path option on screenshot() / pdf() writes to disk in Node only; in the browser it rejects — use the returned bytes instead.

In the browser, take the Uint8Array and turn it into something renderable or downloadable with a Blob:

import { Browserless } from "@browserless.io/bap-ts";

const browser = Browserless.connect({
  browserWSEndpoint: "wss://production-sfo.browserless.io/chromium/bql",
  token: import.meta.env.VITE_BROWSERLESS_TOKEN,
});

const page = await browser.newPage();
await page.goto("https://example.com");

// No `path` — use the returned bytes directly
const bytes = await page.screenshot({ type: "png" });

// Show it in an <img>
const url = URL.createObjectURL(new Blob([bytes], { type: "image/png" }));
document.querySelector("img")!.src = url;

// …or trigger a download
const pdf = await page.pdf({ format: "a4" });
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([pdf], { type: "application/pdf" }));
a.download = "page.pdf";
a.click();

await browser.close();

The browser must be able to reach the Browserless WebSocket endpoint directly — make sure your endpoint allows the token and origin you connect from.

Examples

Take a Screenshot
const browser = Browserless.connect({
  browserWSEndpoint: "wss://production-sfo.browserless.io/chromium/bql",
  token: "your-api-token",
});

const page = await browser.newPage();
await page.goto("https://example.com");

// Returns a Uint8Array, optionally writes to disk (Node only)
await page.screenshot({ path: "screenshot.png" });

// Full-page screenshot as WebP
await page.screenshot({
  path: "full.webp",
  type: "webp",
  fullPage: true,
  quality: 80,
});

await browser.close();
Generate a PDF
const page = await browser.newPage();
await page.goto("https://example.com");

await page.pdf({
  path: "page.pdf",
  format: "a4",
  printBackground: true,
  landscape: true,
});

await browser.close();
Fill Out a Form
const page = await browser.newPage();
await page.goto("https://example.com/login");

await page.type("#username", "user@example.com");
await page.type("#password", "secret", { delay: [100, 200] });
await page.click("#submit");

await page.waitForNavigation({ waitUntil: "networkIdle" });
console.log(await page.url());

await browser.close();
Query the DOM
const page = await browser.newPage();
await page.goto("https://example.com");

// Single element
const heading = await page.$("h1");
console.log(heading?.innerText);

// Multiple elements
const links = await page.$("a");
for (const link of links) {
  console.log(link.innerHTML);
}

// Extract text from a selector
const text = await page.$eval(".content");
console.log(text);

// Map over multiple elements
const items = await page.$eval("ul li");
for (const item of items) {
  console.log(item.innerText);
}
Wait for Elements and Navigation
const page = await browser.newPage();
await page.goto("https://example.com/spa");

// Wait for an element to appear
await page.waitForSelector(".loaded-content", {
  visible: true,
  timeout: 10000,
});

// Wait for a specific network request
await page.waitForRequest("https://api.example.com/data");

// Wait for a specific response status
await page.waitForResponse({
  url: "https://api.example.com/data",
  statuses: [200],
});
Run JavaScript in the Page
const page = await browser.newPage();
await page.goto("https://example.com");

// Pass a string
const result = await page.evaluate("document.title");
console.log(result);

// Pass a function
const dims = await page.evaluate(() => {
  return JSON.stringify({
    width: window.innerWidth,
    height: window.innerHeight,
  });
});
console.log(dims);
Set Viewport, Headers, and Cookies
const page = await browser.newPage();

// Mobile viewport
await page.setViewport({
  width: 375,
  height: 812,
  mobile: true,
  deviceScaleFactor: 3,
});

// Custom headers
await page.setExtraHTTPHeaders({
  "Accept-Language": "en-US",
  "X-Custom": "value",
});

// Set cookies before navigating
await page.setCookie(
  { name: "session", value: "abc123", domain: ".example.com" },
  { name: "prefs", value: "dark", domain: ".example.com" },
);

await page.goto("https://example.com");

// Read cookies back
const cookies = await page.cookies();
console.log(cookies);
Block Requests
const page = await browser.newPage();

// Block images and stylesheets
await page.reject({
  type: ["image", "stylesheet"],
  operator: "or",
});

await page.goto("https://example.com");
Use a Proxy
const page = await browser.newPage();

await page.proxy({
  country: "US",
  state: "California",
  sticky: true,
});

await page.goto("https://example.com");
Solve CAPTCHAs
const page = await browser.newPage();
await page.goto("https://example.com/protected");

const result = await page.solve({
  type: "cloudflare",
  timeout: 30000,
});

console.log(result.solved); // true
Get a Live URL for Debugging
const page = await browser.newPage();
await page.goto("https://example.com");

const { liveURL } = await page.liveURL({
  interactable: true,
  type: "png",
});

console.log(`Watch live: ${liveURL}`);
Reconnect to a Session
const page = await browser.newPage();
await page.goto("https://example.com");

const session = await page.reconnect({ timeout: 60000 });
console.log(session.browserWSEndpoint);
// Use this endpoint to connect a new browser to the same session
Error Handling
import Browserless, {
  BrowserQLError,
  ConnectionError,
  TimeoutError,
} from "@browserless.io/bap-ts";

try {
  const browser = Browserless.connect({
    browserWSEndpoint: "wss://production-sfo.browserless.io/chromium/bql",
    token: "your-api-token",
  });
  const page = await browser.newPage();
  await page.goto("https://example.com", { timeout: 5000 });
} catch (error) {
  if (error instanceof TimeoutError) {
    console.error("Operation timed out");
  } else if (error instanceof ConnectionError) {
    console.error("WebSocket connection failed");
  } else if (error instanceof BrowserQLError) {
    console.error("GraphQL errors:", error.errors);
  }
}

API Reference

Browserless.connect(options)

Creates a Browser instance. The WebSocket connection opens when you call newPage().

Option Type Description
browserWSEndpoint string WebSocket URL (e.g. wss://production-sfo.browserless.io/chromium/bql)
token string? API token
timeout number? Default timeout in ms (default: 30000)
Browser
Method Returns Description
newPage() Promise<Page> Opens a WebSocket and returns a new Page
getPages() Page[] Returns all non-closed pages
close() Promise<void> Closes all pages
Page
Navigation
Method Returns
goto(url, options?) Promise<HTTPResponse | null>
goBack(options?) Promise<HTTPResponse | null>
goForward(options?) Promise<HTTPResponse | null>
reload(options?) Promise<HTTPResponse | null>
setContent(html, options?) Promise<HTTPResponse | null>
waitForNavigation(options?) Promise<HTTPResponse>
Interaction
Method Returns
click(selector, options?) Promise<ClickResponse>
hover(options?) Promise<HoverResponse>
scroll(options?) Promise<ScrollResponse>
type(selector, text, options?) Promise<TypeResponse>
check(selector, options?) Promise<ClickResponse>
uncheck(selector, options?) Promise<ClickResponse>
select(selector, ...values) Promise<SelectResponse>
Content
Method Returns
content() Promise<string>
html(options?) Promise<HTMLResponse>
text(options?) Promise<TextResponse>
title() Promise<string>
url() Promise<string>
screenshot(options?) Promise<Uint8Array>
pdf(options?) Promise<Uint8Array>
Scripts & Styles
Method Returns
addScriptTag(options?) Promise<AddScriptTagResponse>
addStyleTag(options?) Promise<AddStyleTagResponse>

Pass url to load from a URL, or content for inline source.

Note: inline content must be a single line. The BrowserQL server rejects multi-line content with SyntaxError: Invalid or unexpected token. For multi-line scripts, host them and use url, or collapse the source to one line first (e.g. bundle with minification) when it has no newline-sensitive syntax such as // comments or multi-line template literals.

Selectors
Method Returns
$(selector, options?) Promise<ElementHandle | null>
$(selector, options?) Promise<ElementHandle[]>
$eval(selector) Promise<string>
$eval(selector, options?) Promise<MapSelectorResponse[]>
mapSelector(selector, options?) Promise<MapSelectorResponse[]>
waitForSelector(selector, options?) Promise<WaitForSelectorResponse>
Wait
Method Returns
waitForTimeout(ms) Promise<void>
waitForRequest(urlOrOptions?) Promise<WaitForRequestResponse>
waitForResponse(urlOrOptions?) Promise<WaitForResponseResponse>
Settings
Method Returns
setUserAgent(ua) Promise<UserAgentResponse>
setViewport(options) Promise<ViewportResponse>
setCookie(...cookies) Promise<CookieResponse>
cookies() Promise<StandardCookie[]>
setExtraHTTPHeaders(headers) Promise<HTTPHeadersResponse>
setJavaScriptEnabled(enabled) Promise<JavaScriptResponse>
evaluate(content, options?) Promise<string | null>
Network
Method Returns
request(options?) Promise<RequestResponse[]>
response(options?) Promise<ResponseResponse[]>
reject(options?) Promise<RejectResponse>
proxy(options) Promise<ProxyResponse>
Session
Method Returns
reconnect(options?) Promise<ReconnectionResponse>
liveURL(options?) Promise<LiveURLResponse>
stopSessionRecording() Promise<StopSessionRecordingResponse>
switchToWindow(options?) Promise<SwitchWindowResponse>
solve(options?) Promise<CaptchaResponse>
solveImageCaptcha(options) Promise<CaptchaResponse>
close() Promise<void>
ElementHandle
Property / Method Type
innerHTML string | null
innerText string | null
id string | null
className string | null
localName string | null
outerHTML string | null
childElementCount number | null
click(options?) Promise<ClickResponse>
hover() Promise<void>
type(text, options?) Promise<TypeResponse>
screenshot(options?) Promise<Uint8Array>
textContent() Promise<string>

Browser Automation Protocol vs Puppeteer

Browser Automation Protocol's Page class borrows Puppeteer's naming conventions so the API feels familiar, but there are important differences in architecture, scope, and behavior.

Architecture

Puppeteer controls a local Chrome instance over the Chrome DevTools Protocol (CDP) via a WebSocket. Browser Automation Protocol is a GraphQL client — every method builds a mutation, sends it over a single WebSocket to the Browserless BQL server, and waits for the response. There is no direct CDP connection. This means a massive reduction in the amount and size of messages being sent over the network, making scripting performance much faster.

Because this client builds on top of our BrowserQL service, it also means all the languages we support are (mostly) compiled from the BrowserQL mutation specification. This means all clients are treated equally, operate the same, and will perform similarly.

Shared Methods

These methods exist in both libraries with similar signatures:

Category Methods
Navigation goto, goBack, goForward, reload, setContent, waitForNavigation
Interaction click, type, select, hover
Content content, title, url, screenshot, pdf
Selectors $, $, waitForSelector
Evaluate evaluate
Settings setUserAgent, setViewport, setCookie, cookies, setExtraHTTPHeaders, setJavaScriptEnabled
Wait waitForTimeout, waitForRequest, waitForResponse
Lifecycle close
Complete Method Reference

Every Page method and its source BrowserQL mutation. This table is generated from src/mutations.graphql by npm run codegen, so it stays in sync with the schema:

Method Source mutation Returns Puppeteer-named
$ querySelector ElementHandle | null
$ querySelectorAll ElementHandle[]
$eval mapSelector MapSelectorResponse[]
$eval text string
addScriptTag addScriptTag AddScriptTagResponse
addStyleTag addStyleTag AddStyleTagResponse
authenticate authenticate HTTPResponse | null
check checkbox ClickResponse
click click ClickResponse
close void
content html string
cookies cookies StandardCookie[]
emulateMediaType emulateMediaType EmulateMediaTypeResponse
evaluate evaluate string | null
fulfill fulfill FulfillResponse
goBack back HTTPResponse | null
goForward forward HTTPResponse | null
goto goto HTTPResponse | null
hover hover HoverResponse
html html HTMLResponse
liveURL liveURL LiveURLResponse
loadSecret loadSecret LoadSecretResponse
mapSelector mapSelector MapSelectorResponse[]
markdown markdown MarkdownResponse
pdf pdf Uint8Array
preferences preferences DefaultResponse
proxy proxy ProxyResponse
reconnect reconnect ReconnectionResponse
reject reject RejectResponse
reload reload HTTPResponse | null
request request RequestResponse[]
response response ResponseResponse[]
screenshot screenshot Uint8Array
scroll scroll ScrollResponse
select select SelectResponse
send T
setContent content HTTPResponse | null
setCookie cookies CookieResponse
setExtraHTTPHeaders setExtraHTTPHeaders HTTPHeadersResponse
setJavaScriptEnabled javaScriptEnabled JavaScriptResponse
setUserAgent userAgent UserAgentResponse
setViewport viewport ViewportResponse
solve solve CaptchaResponse
solveImageCaptcha solveImageCaptcha CaptchaResponse
stopSessionRecording stopSessionRecording StopSessionRecordingResponse
switchToWindow switchToWindow SwitchWindowResponse
text text TextResponse
title title string
type type TypeResponse
uncheck checkbox ClickResponse
url url string
waitForEvent waitForEvent WaitForEvent
waitForFunction waitForFunction WaitForFunction
waitForNavigation waitForNavigation HTTPResponse
waitForRequest waitForRequest WaitForRequestResponse
waitForResponse waitForResponse WaitForResponseResponse
waitForSelector waitForSelector WaitForSelectorResponse
waitForTimeout waitForTimeout void
Behavioral Differences
Method Puppeteer Browser Automation Protocol
$eval(selector, fn) Runs a function in the browser with the matched element as the argument and returns the result Returns the text content of the matched selector (no function argument)
$eval(selector, fn) Runs a function in the browser with all matched elements as an array argument Delegates to mapSelector — returns structured MapSelectorResponse[] with element properties
scroll() Not available on Page — you use mouse.wheel() or evaluate First-class method with selector targeting and coordinate support
evaluate(fn, ...args) Passes serialized arguments to the function and returns deserialized results Accepts a string or function but always returns string | null — no argument passing
waitForRequest / waitForResponse Accept a URL string or a predicate function Accept a URL string or an options object (no predicate functions)
Not in Browser Automation Protocol

Browser Automation Protocol does not include Puppeteer's event system or lower-level primitives. These might be added in a later release:

  • Events — no EventEmitter, no page.on('request' | 'response' | 'console' | 'dialog' | ...) event listeners
  • Input devices — no page.keyboard, page.mouse, page.touchscreen
  • Frames — no page.frames(), page.mainFrame(), or frame targeting
  • Workers — no page.workers()
  • Function exposure — no exposeFunction()
  • Emulation — no emulate() or emulateCPUThrottling() (emulateMediaType() is supported)
  • Security/Cache — no setBypassCSP(), setCacheEnabled(), setOfflineMode()
  • Coverage/Tracing — no page.coverage, page.tracing
  • Accessibility — no page.accessibility
Browser Automation Protocol-Only Features

These methods have no equivalent in Puppeteer:

Method Description
html(options?) Extract HTML with optional selector targeting and cleaning
text(options?) Extract text with optional selector targeting and cleaning
check(selector) / uncheck(selector) Checkbox helpers
mapSelector(selector, options?) Map over matched elements and return structured properties
reject(options?) Block network requests by type, URL, or method
proxy(options) Route traffic through a proxy with geo-targeting
solve(options?) Solve CAPTCHAs (Cloudflare, reCAPTCHA, etc.)
solveImageCaptcha(options) Solve image-based CAPTCHAs with selector targeting
liveURL(options?) Get a shareable live-view URL for debugging
reconnect(options?) Get a new WebSocket endpoint to reconnect to the same session
switchToWindow(options?) Switch between browser tabs/windows
stopSessionRecording() Stop recording the current session
preferences(options?) Dismiss cookie banners and preference dialogs
request(options?) / response(options?) Query captured network traffic with filters

How It Works

Browser Automation Protocol communicates with Browserless over a single WebSocket connection per page. Each method call constructs a GraphQL mutation, sends it as a JSON message, and waits for the response. Operations are queued and executed serially, matching BrowserQL's server-side concurrency model. Browser and page state persists across calls on the same connection.