BrowserBox runs a full browser (Chromium, Firefox, or WebKit) inside an isolated VM and exposes it via Playwright Server or Chrome DevTools Protocol. You connect with Playwright or Puppeteer from your host — no browser install needed on the host.
What you’ll build
A script that:
Launches a BrowserBox with Chromium
Connects via Playwright or Puppeteer
Navigates to a page and takes a screenshot
Scrapes content from the page
Prerequisites
Python (Playwright)
Node.js (Puppeteer)
pip install boxlite playwright
npm install @boxlite-ai/boxlite puppeteer-core
Use puppeteer-core (not puppeteer) since the browser runs inside the BrowserBox, not on your host.
Step 1: Launch a BrowserBox
Create a BrowserBox and get a connection endpoint.
Python (Playwright)
Node.js (Puppeteer)
import asyncio
from boxlite import BrowserBox, BrowserBoxOptions
async def main ():
opts = BrowserBoxOptions( browser = "chromium" , memory = 2048 , cpu = 2 )
async with BrowserBox(opts) as browser:
ws = await browser.playwright_endpoint()
print ( f "Playwright endpoint: { ws } " )
# → ws://localhost:3000/
if __name__ == "__main__" :
asyncio.run(main())
import { BrowserBox } from '@boxlite-ai/boxlite' ;
async function main () {
const box = new BrowserBox ({ browser: 'chromium' });
try {
const ws = await box . endpoint ();
console . log ( `CDP endpoint: ${ ws } ` );
// → ws://localhost:3000/...
} finally {
await box . stop ();
}
}
main ();
For Puppeteer, use endpoint() which starts the browser with CDP. Do not call start() first — start() launches Playwright Server, which is a different (mutually exclusive) connection mode.
Connection modes
BrowserBox has two mutually exclusive connection modes:
Mode Method Protocol Use with Playwright Server playwright_endpoint()WebSocket Playwright (all browsers) Direct CDP/BiDi endpoint()WebSocket Puppeteer, Selenium (chromium/firefox only)
Supported browsers
Browser Works with Playwright Works with Puppeteer chromiumYes Yes (CDP) firefoxYes Yes (WebDriver BiDi) webkitYes No
Step 2: Take a screenshot
Connect to the browser and capture a screenshot.
Python (Playwright)
Node.js (Puppeteer)
import asyncio
from boxlite import BrowserBox, BrowserBoxOptions
from playwright.async_api import async_playwright
async def main ():
opts = BrowserBoxOptions( browser = "chromium" , memory = 2048 , cpu = 2 )
async with BrowserBox(opts) as browser:
ws = await browser.playwright_endpoint()
async with async_playwright() as p:
# Connect to the browser running inside the VM
b = await p.chromium.connect(ws)
page = await b.new_page()
await page.goto( "https://example.com" )
await page.screenshot( path = "screenshot.png" )
print ( "Screenshot saved to screenshot.png" )
await b.close()
if __name__ == "__main__" :
asyncio.run(main())
import { BrowserBox } from '@boxlite-ai/boxlite' ;
import puppeteer from 'puppeteer-core' ;
async function main () {
const box = new BrowserBox ({ browser: 'chromium' });
try {
const ws = await box . endpoint ();
// Connect to the browser running inside the VM
const instance = await puppeteer . connect ({ browserWSEndpoint: ws });
const page = await instance . newPage ();
await page . goto ( 'https://example.com' );
await page . screenshot ({ path: 'screenshot.png' });
console . log ( 'Screenshot saved to screenshot.png' );
await instance . close ();
} finally {
await box . stop ();
}
}
main ();
Step 3: Scrape a page
Extract content from a web page using standard DOM queries.
Python (Playwright)
Node.js (Puppeteer)
import asyncio
from boxlite import BrowserBox, BrowserBoxOptions
from playwright.async_api import async_playwright
async def main ():
opts = BrowserBoxOptions( browser = "chromium" , memory = 2048 , cpu = 2 )
async with BrowserBox(opts) as browser:
ws = await browser.playwright_endpoint()
async with async_playwright() as p:
b = await p.chromium.connect(ws)
page = await b.new_page()
await page.goto( "https://news.ycombinator.com" )
# Extract the top 5 story titles
titles = await page.eval_on_selector_all(
".titleline > a" ,
"elements => elements.slice(0, 5).map(e => e.textContent)"
)
print ( "Top 5 Hacker News stories:" )
for i, title in enumerate (titles, 1 ):
print ( f " { i } . { title } " )
await b.close()
if __name__ == "__main__" :
asyncio.run(main())
import { BrowserBox } from '@boxlite-ai/boxlite' ;
import puppeteer from 'puppeteer-core' ;
async function main () {
const box = new BrowserBox ({ browser: 'chromium' });
try {
const ws = await box . endpoint ();
const instance = await puppeteer . connect ({ browserWSEndpoint: ws });
const page = await instance . newPage ();
await page . goto ( 'https://news.ycombinator.com' );
// Extract the top 5 story titles
const titles = await page . $$eval (
'.titleline > a' ,
( links ) => links . slice ( 0 , 5 ). map (( a ) => a . textContent )
);
console . log ( 'Top 5 Hacker News stories:' );
titles . forEach (( title , i ) => {
console . log ( ` ${ i + 1 } . ${ title } ` );
});
await instance . close ();
} finally {
await box . stop ();
}
}
main ();
Step 4: Interact with a page
Read content, click links, and handle navigation.
Python (Playwright)
Node.js (Puppeteer)
import asyncio
from boxlite import BrowserBox, BrowserBoxOptions
from playwright.async_api import async_playwright
async def main ():
opts = BrowserBoxOptions( browser = "chromium" , memory = 2048 , cpu = 2 )
async with BrowserBox(opts) as browser:
ws = await browser.playwright_endpoint()
async with async_playwright() as p:
b = await p.chromium.connect(ws)
page = await b.new_page()
await page.goto( "https://example.com" )
# Get page title and content
title = await page.title()
heading = await page.text_content( "h1" )
print ( f "Title: { title } " )
print ( f "Heading: { heading } " )
# Click a link
await page.click( "a" )
print ( f "Navigated to: { page.url } " )
await b.close()
if __name__ == "__main__" :
asyncio.run(main())
import { BrowserBox } from '@boxlite-ai/boxlite' ;
import puppeteer from 'puppeteer-core' ;
async function main () {
const box = new BrowserBox ({ browser: 'chromium' });
try {
const ws = await box . endpoint ();
const instance = await puppeteer . connect ({ browserWSEndpoint: ws });
const page = await instance . newPage ();
await page . goto ( 'https://example.com' );
// Get page title and content
const title = await page . title ();
const heading = await page . $eval ( 'h1' , ( el ) => el . textContent );
console . log ( `Title: ${ title } ` );
console . log ( `Heading: ${ heading } ` );
// Click a link
await page . click ( 'a' );
console . log ( `Navigated to: ${ page . url () } ` );
await instance . close ();
} finally {
await box . stop ();
}
}
main ();
BrowserBox allocates 2 CPUs and 2048 MiB of memory by default. Increase these if your pages are heavy or you’re running multiple tabs.
What’s next?
Connect to an LLM Give your LLM agent the ability to browse the web by combining BrowserBox with function calling.
BrowserBox API reference Full API docs for BrowserBox, BrowserBoxOptions, and connection endpoints.
AI agent integration Production patterns for using BoxLite with AI agents.