Skip to content

Chrome ​

The chrome template runs Chromium on a VNC display, with the remote DevTools protocol (CDP) on port 9222.

Setup ​

bash
pip install ovrin
export OVRIN_API_KEY="ovrin_..."

Drive it from your machine ​

sandbox.devtools() returns the browser's DevTools WebSocket on the control plane and the header it takes, under the names Playwright uses:

python
import ovrin
from playwright.sync_api import sync_playwright

client = ovrin.Client()  # reads OVRIN_API_KEY
sandbox = client.sandboxes.create(template="chrome", timeout=900)

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(**sandbox.devtools())
    page = browser.contexts[0].new_page()
    page.goto("https://example.com")
    print(page.title())       # Example Domain
    page.screenshot(path="example.png")

sandbox.kill()
ts
const { endpointURL, headers } = await sandbox.devtools();
const browser = await chromium.connectOverCDP(endpointURL, { headers });
  • Your API key is the lock. DevTools itself checks nothing; the connection goes through the control plane, which takes your key and the sandbox's scope.
  • From a script or an agent, not a web page. A page cannot set the Authorization header, and Chromium refuses DevTools connections that carry an Origin.
  • Use devtools() rather than /json/version yourself. Chrome names its WebSocket after the address it was reached on, which for a sandbox is the sandbox's own; devtools() swaps in one you can reach.

This needs a deployment that serves Ovrin's Chrome image: GET /capabilities then reports the chrome template as available. On upstream's image, reported as degraded with devtools_loopback_only, DevTools answers inside the sandbox only, so drive it from there, as below.

Drive it from inside the sandbox ​

python
import ovrin

client = ovrin.Client()  # reads OVRIN_API_KEY

sandbox = client.sandboxes.create(template="chrome", timeout=900)

sandbox.files.write("/workspace/drive.py", """
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp("http://localhost:9222")
    page = browser.contexts[0].new_page()
    page.goto("https://example.com")
    print(page.title())
    page.screenshot(path="/workspace/example.png")
""")

result = sandbox.run("python /workspace/drive.py", timeout=300)
print(result.stdout)          # Example Domain

png = sandbox.files.read_bytes("/workspace/example.png")
open("example.png", "wb").write(png)

sandbox.kill()

Publishing a port ​

For a service the sandbox serves on 0.0.0.0, sandbox.endpoint(port) returns its public URLs:

python
endpoint = sandbox.endpoint(8080)
print(endpoint["url"])            # HTTP
print(endpoint["websocket_url"])  # WebSocket

The console's endpoint panel shows the same two. Both take your API key in an Authorization header, so they are for scripts and agents rather than a browser tab — see WebSocket endpoints.

Chrome or Playwright? ​

chromeplaywright
What runsChromium with CDP on 9222Headless Chromium plus the Playwright library
Best forAttaching to a live browser, DevTools workScripted navigation, scraping, screenshots