Skip to Content
Getting StartedBot Script

Getting Started with Bot Script

Automate BotBrowser without Playwright or Puppeteer using --bot-script and the Chrome Debugger API.


Prerequisites

  • BotBrowser binary installed on your system. See INSTALLATION.md for platform-specific setup.
  • A profile file (.enc for production, .json for local development). Download from GitHub Releases or use the profiles in profiles/.
  • A JavaScript file containing your automation logic.
  • No Node.js, Playwright, or Puppeteer installation required.

Quick Start

1. Create a bot script

Save the following as my-script.js:

console.log("Bot script loaded."); if (typeof chrome !== "undefined" && chrome.debugger) { console.log("chrome.debugger API is available."); // Find all browser targets chrome.debugger.getTargets(function (targets) { targets.forEach(function (target) { if (target.type === "page") { console.log("Found page:", target.url); } }); }); } else { console.log("ERROR: chrome.debugger API not available."); }

2. Launch BotBrowser with the script

# Windows chrome.exe --bot-profile="C:\path\to\profile.enc" --bot-script="C:\path\to\my-script.js" # macOS /Applications/Chromium.app/Contents/MacOS/Chromium \ --bot-profile="path/to/profile.enc" \ --bot-script="path/to/my-script.js" # Ubuntu chromium-browser \ --bot-profile="path/to/profile.enc" \ --bot-script="path/to/my-script.js"

That is it. BotBrowser loads the profile, opens a browser window, and executes your script in a privileged context.

For multi-identity workflows, --bot-script can also be passed through Per-Context Fingerprint when creating a BrowserContext. Use this when each context needs its own framework-less automation bootstrap.


How It Works

The --bot-script flag tells BotBrowser to execute a JavaScript file in a privileged, non-extension context immediately after startup. This context provides:

  1. Full chrome.debugger API access. You can attach to any browser target (page, iframe, service worker) and send Chrome DevTools Protocol (CDP) commands directly.

  2. No framework artifacts. Because no external framework is loaded, the page context remains clean. There are no Playwright bindings, no Puppeteer protocol hooks, and no framework-introduced artifacts in the page context.

  3. Early execution. The script runs before the first page navigation completes, allowing you to set up CDP listeners, intercept network requests, or configure protections before any page code executes.

  4. Standard browser APIs. You have access to console, setTimeout, setInterval, fetch, and other standard APIs alongside the chrome.* extension APIs.

  5. Context-scoped bootstrap. When used with Per-Context Fingerprint, a bot script can be associated with a newly created BrowserContext so automation setup follows the selected context profile.


Common Scenarios

Attaching to a page and sending CDP commands

chrome.debugger.getTargets(function (targets) { const pageTarget = targets.find((t) => t.type === "page"); if (!pageTarget) return; chrome.debugger.attach({ targetId: pageTarget.id }, "1.3", function () { if (chrome.runtime.lastError) { console.log("Attach failed:", chrome.runtime.lastError.message); return; } // Enable the Page domain chrome.debugger.sendCommand( { targetId: pageTarget.id }, "Page.enable", {}, function () { console.log("Page domain enabled."); } ); // Navigate to a URL chrome.debugger.sendCommand( { targetId: pageTarget.id }, "Page.navigate", { url: "https://example.com" }, function () { console.log("Navigation started."); } ); }); });

Per-context bot script bootstrap

Create a BrowserContext with a profile and bot script in the same call:

const client = await browser.newBrowserCDPSession(); const { browserContextId } = await client.send("Target.createBrowserContext", { botbrowserFlags: [ "--bot-profile=path/to/profile.enc", "--bot-script=path/to/context-bootstrap.js" ] });

Create pages after the context is created so the script and profile are available from the start of the workflow.

Interacting with iframe content

Bot scripts can monitor for embedded iframes and interact with them using CDP input events:

let activeTargets = new Set(); function startMonitoring() { chrome.debugger.getTargets(function (targets) { targets.forEach(function (target) { if (target.type === "iframe" && !activeTargets.has(target.id)) { activeTargets.add(target.id); interactWithFrame(target.id); } }); setTimeout(startMonitoring, 2000); }); } function interactWithFrame(targetId) { chrome.debugger.attach({ targetId: targetId }, "1.3", function () { if (chrome.runtime.lastError) { activeTargets.delete(targetId); return; } // Click within the iframe at a specific coordinate setTimeout(function () { chrome.debugger.sendCommand( { targetId: targetId }, "Input.dispatchMouseEvent", { type: "mousePressed", x: 30, y: 30, button: "left", clickCount: 1 } ); setTimeout(function () { chrome.debugger.sendCommand( { targetId: targetId }, "Input.dispatchMouseEvent", { type: "mouseReleased", x: 30, y: 30, button: "left", clickCount: 1 } ); activeTargets.delete(targetId); }, 100); }, 500); }); } startMonitoring();

Human-like mouse movement

async function moveMouse(targetId, fromX, fromY, toX, toY, steps) { for (let i = 0; i <= steps; i++) { const progress = i / steps; const x = fromX + (toX - fromX) * progress + Math.random() * 0.7; const y = fromY + (toY - fromY) * progress + Math.random() * 0.7; await new Promise((resolve) => { chrome.debugger.sendCommand( { targetId: targetId }, "Input.dispatchMouseEvent", { type: "mouseMoved", x: x, y: y, modifiers: 0, buttons: 0 }, resolve ); }); await new Promise((r) => setTimeout(r, 12 + Math.random() * 18)); } }

Typing with realistic cadence

async function typeText(targetId, text) { for (const ch of text) { await new Promise((resolve) => { chrome.debugger.sendCommand( { targetId: targetId }, "Input.insertText", { text: ch }, resolve ); }); await new Promise((r) => setTimeout(r, 35 + Math.random() * 45)); } }

Available APIs

Bot scripts run in a privileged isolated page context. The following APIs are available:

APIDescription
chrome.debugger.getTargets()List all browser targets (pages, iframes, workers)
chrome.debugger.attach()Attach the debugger to a target
chrome.debugger.detach()Detach from a target
chrome.debugger.sendCommand()Send any CDP command to an attached target
chrome.runtime.lastErrorCheck for errors after API calls
console.log()Log messages (visible in the terminal)
setTimeout() / setInterval()Standard timing functions

For the full list of CDP commands you can send via chrome.debugger.sendCommand(), see the Chrome DevTools Protocol documentation.


When to Use Bot Script vs Frameworks

ConsiderationBot ScriptPlaywright / Puppeteer
DependenciesNoneNode.js + npm packages
Page context cleanlinessNo framework artifacts at allRequires cleanup (Playwright bindings)
API styleCallback-based Chrome extension APIsPromise-based, high-level APIs
Page selectorsManual CDP queriesBuilt-in page.$(), page.click(), etc.
Multi-page workflowsManual target managementBuilt-in context and page management
Best forSimple interactions, lightweight single-page tasksComplex multi-page workflows, testing, data collection

Use bot script when:

  • You need the cleanest possible page context with zero framework artifacts.
  • Your task is a focused interaction (clicking a button, filling a form).
  • You want zero external dependencies.
  • You need the earliest possible intervention before page load.

Use Playwright or Puppeteer when:

  • You need high-level page interaction APIs (selectors, screenshots, PDF generation).
  • You are building complex multi-step workflows.
  • You need built-in waiting and retry mechanisms.
  • You are integrating with a test framework.

Troubleshooting / FAQ

ProblemSolution
”chrome.debugger API not available”Ensure you are using --bot-script, not loading the script another way.
Script does not executeUse an absolute path for --bot-script. Relative paths resolve from the binary’s directory.
Context-scoped script does not runPass --bot-script in botbrowserFlags when creating the BrowserContext, then create pages after that context exists.
chrome.runtime.lastError on attachAnother debugger may already be attached. Call chrome.debugger.detach() first, then retry.
Target not foundTargets appear asynchronously. Use setTimeout to poll chrome.debugger.getTargets() until the target appears.
No output visibleConsole output from bot scripts appears in the terminal where BotBrowser was launched.

Next Steps


Related documentation: Installation | Bot Script Examples | Chrome Debugger API | Chrome DevTools Protocol


Legal Disclaimer & Terms of UseResponsible Use Guidelines. BotBrowser is for authorized fingerprint protection and privacy research only.

Updated