Skip to main content
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:
  1. Launches a BrowserBox with Chromium
  2. Connects via Playwright or Puppeteer
  3. Navigates to a page and takes a screenshot
  4. Scrapes content from the page

Prerequisites

pip install boxlite playwright

Step 1: Launch a BrowserBox

Create a BrowserBox and get a connection endpoint.
browser.py
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())

Connection modes

BrowserBox has two mutually exclusive connection modes:
ModeMethodProtocolUse with
Playwright Serverplaywright_endpoint()WebSocketPlaywright (all browsers)
Direct CDP/BiDiendpoint()WebSocketPuppeteer, Selenium (chromium/firefox only)

Supported browsers

BrowserWorks with PlaywrightWorks with Puppeteer
chromiumYesYes (CDP)
firefoxYesYes (WebDriver BiDi)
webkitYesNo

Step 2: Take a screenshot

Connect to the browser and capture a screenshot.
screenshot.py
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())

Step 3: Scrape a page

Extract content from a web page using standard DOM queries.
scrape.py
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())

Step 4: Interact with a page

Read content, click links, and handle navigation.
interact.py
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())
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?