Skip to content

std/browser ​

Drive a headless Chrome over the DevTools protocol: launch it, set the viewport and color scheme, load a page, evaluate JavaScript, and save a PNG screenshot. Built on the std/ws WebSocket client and std/json; there is no driver binary and no npm dependency, only Chrome.

milo
from "std/browser" import { Browser, findChrome }

Example ​

milo
from "std/browser" import { Browser, findChrome }

fn main(): i32 {
    let Some(chrome) = findChrome() else {
        eprint("no Chrome found; set CHROME to its path")
        return 1
    }
    var b = Browser.launch(chrome, 9333)!
    b.setViewport(390, 844, 2.0, true)!          // a phone: 390x844 CSS px at 2x
    b.setColorScheme("dark")!                     // prefers-color-scheme: dark
    b.navigate("https://example.com/")!           // waits for the load event
    print(b.evaluate("document.title")!)          // "Example Domain" (JSON text)
    b.screenshot("phone-dark.png")!
    b.close()
    return 0
}

examples/net/screenshot.milo takes a URL and writes a phone and a desktop shot.

How it works ​

Browser.launch starts Chrome with --headless=new, DevTools bound to 127.0.0.1 on the given port, and a fresh temporary profile; it polls /json/list until the page target appears (10 s at most) and connects to it. Closing or dropping the Browser closes Chrome and removes the profile.

call(method, paramsJson) is the whole protocol: send one command, read until the reply with its id, return the reply's result. Every other method is a few lines over it, and anything the module does not wrap is one call away (b.call("Network.setCookie", ...)). Events that arrive while a reply is awaited are kept in a short log, so waitEvent does not miss one that landed early. One command is in flight at a time.

evaluate returns the value as JSON text ("hi", [1,2], null) and awaits a returned promise; a thrown exception is an Err with its message.

API reference ​

Browser ​

milo
pub struct Browser

A headless Chrome and the DevTools connection to its first page. Closing it (or dropping it) ends the browser and removes its temporary profile.

Fields:

  • child: Child
  • ws: WsConn
  • profile: string
  • nextId: i64
  • events: Vec<string>: Events read while waiting for a reply, oldest first; capped so a chatty page cannot grow it without bound.
  • closed: bool

Browser.call ​

milo
fn Browser.call(self: &mut Browser, method: &string, params: &string): Result<Json>

Send DevTools command method with params (a JSON object, "{}" for none) and return its reply's result object. Errs with the protocol's error message.

Browser.capture ​

milo
fn Browser.capture(self: &mut Browser, fullPage: bool): Result<string>

Capture the viewport as PNG bytes; fullPage captures the whole scrollable page.

Browser.close ​

milo
fn Browser.close(self: Browser): void

End the browser and remove its profile. Also what dropping it does.

Browser.evaluate ​

milo
fn Browser.evaluate(self: &mut Browser, js: &string): Result<string>

Evaluate js in the page, awaiting a returned promise, and return the result as JSON text ("null" for undefined). A thrown exception is an Err with its description.

Browser.launch ​

milo
fn Browser.launch(chrome: &string, port: u16): Result<Browser>

Start chrome headless with DevTools on port (loopback only) and a fresh temporary profile, and connect to its page. Waits up to 10 s for the browser to come up.

Browser.navigate ​

milo
fn Browser.navigate(self: &mut Browser, url: &string): Result<Unit>

Load url and wait (up to 30 s) for its load event.

Browser.screenshot ​

milo
fn Browser.screenshot(self: &mut Browser, path: &string): Result<Unit>

Capture the viewport as a PNG file at path.

Browser.setColorScheme ​

milo
fn Browser.setColorScheme(self: &mut Browser, scheme: &string): Result<Unit>

Answer prefers-color-scheme with scheme ("light" or "dark"; "" restores the default).

Browser.setViewport ​

milo
fn Browser.setViewport(self: &mut Browser, width: i64, height: i64, scale: f64, mobile: bool): Result<Unit>

Emulate a viewport: CSS pixels, device pixel ratio, and whether it is a mobile device (touch, meta viewport). Applies to the next layout; navigate afterwards.

Browser.shutdown ​

milo
fn Browser.shutdown(self: &mut Browser): void

Browser.waitEvent ​

milo
fn Browser.waitEvent(self: &mut Browser, method: &string, timeoutMs: i64): Result<Json>

Wait up to timeoutMs for event method (an event already logged counts) and return its params. Clears the log up to and including it.

Functions ​

findChrome ​

milo
pub fn findChrome(): Option<string>

The Chrome executable: $CHROME when set, else the first standard install location that exists (macOS app bundle, then the usual Linux names). None when there is none.