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 |
|---|
chromium | Yes | Yes (CDP) |
firefox | Yes | Yes (WebDriver BiDi) |
webkit | Yes | 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?