Quick start
Run a box
Section titled “Run a box”-
Start it.
Terminal window export BROWSERBAY_API_KEY="$(openssl rand -base64 24)" # keep it: your projects present itdocker run -d --name browserbay --restart always --init --stop-timeout 130 \-p 127.0.0.1:8788:8788 -e BROWSERBAY_API_KEY \ghcr.io/degoke/browserbayThat one container is a complete box: the relay and a Chromium node together. It listens on this machine only (
127.0.0.1).--stop-timeout 130is the 120 seconds a stopping node gives slots in use, plus a margin. On Kubernetes, use the Helm chart instead. -
Check it is up.
Terminal window curl http://127.0.0.1:8788/healthcurl -H "Authorization: Bearer $BROWSERBAY_API_KEY" http://127.0.0.1:8788/v1/nodes/healthsays the relay is up./v1/nodesshows the Chromium node and how many slots it has free.
Install a client
Section titled “Install a client”It is published on npm as @degoke/browserbay, already built, so installing it needs no registry setup and no token:
pnpm add @degoke/browserbay playwrightEvery release is also on GitHub Packages. To install from there, point the @degoke scope at https://npm.pkg.github.com in .npmrc and use a personal access token with read:packages.
Use the scoped name. An unscoped npx browserbay is not this package: the command is npx @degoke/browserbay.
pip install "git+https://github.com/degoke/browserbay.git#subdirectory=clients/python" playwrightThe Python client uses only the standard library. See the Python client.
go get github.com/degoke/browserbay/clients/goThe Go client uses only the standard library. See the Go client.
Take a browser and drive it
Section titled “Take a browser and drive it”import { chromium } from 'playwright'import { createBrowserBay } from '@degoke/browserbay/client'
const box = createBrowserBay({ url: 'http://127.0.0.1:8788', apiKey: process.env.BROWSERBAY_API_KEY})
const slot = await box.acquire({ runId: 'task-42', maxLifetimeSeconds: 30 * 60 })try { const browser = await chromium.connectOverCDP(slot.cdpUrl, { headers: slot.headers }) const context = browser.contexts()[0] // your slot's context: use it, do not create another const page = context.pages()[0] ?? (await context.newPage()) await page.goto('https://example.com') console.log(await page.title())} finally { await slot.release()}import osfrom browserbay import BrowserBayfrom playwright.sync_api import sync_playwright
box = BrowserBay("http://127.0.0.1:8788", os.environ["BROWSERBAY_API_KEY"])
with sync_playwright() as p, box.acquire(run_id="task-42", max_lifetime_seconds=1800) as slot: browser = p.chromium.connect_over_cdp(slot.cdp_url, headers=slot.headers) page = browser.contexts[0].new_page() # the slot's own context page.goto("https://example.com") print(page.title())# leaving the with block releases the browserbox, err := browserbay.New(browserbay.Options{ URL: "http://127.0.0.1:8788", APIKey: os.Getenv("BROWSERBAY_API_KEY"),})if err != nil { log.Fatal(err)}
slot, err := box.Acquire(ctx, browserbay.AcquireOptions{ RunID: "task-42", MaxLifetime: 30 * time.Minute,})if err != nil { log.Fatal(err)}defer slot.Release(ctx)
// Hand slot.CDPURL and slot.Headers() to playwright-go, chromedp or a WebSocket library.fmt.Println(slot.CDPURL)acquire waits up to 30 seconds for a free slot and fails with a no-capacity error if the box stays full. The maximum lifetime is the lease: the browser closes itself after that long even if your process crashed. See Concepts for the vocabulary and Drive a browser for Puppeteer and plain DevTools.
- Let a person watch the browser: Live view.
- Put browsers on more than one machine: Relay and nodes, or on Kubernetes with the Helm chart.
- Before you hand slot tokens to anyone: Trust and isolation.