Skip to content
Raster
Esc
navigateopen⌘Jpreview
On this page

The browser

Open a URL, enumerate tabs, and drive the rest of it as a desktop.

The image ships a browser on the desktop. Two routes address it directly; everything else about it is the desktop — click it, type in it, screenshot it.

Call What it does
POST /machines/{id}/browser/open open a URL
GET /machines/{id}/browser/tabs enumerate open tabs
await machine.browser.open("https://example.com");
await machine.browser.open("https://example.com", { newWindow: true });

Opening a URL is an input action and takes the lease. It focuses the browser and navigates, which is why it is a product route rather than something you assemble out of a hotkey and typing into an address bar.

Tabs answer, they do not throw

const tabs = await machine.browser.tabs();
if (tabs.supported) {
  for (const tab of tabs.tabs) console.log(tab.title, tab.url);
} else {
  console.log(tabs.reason); // why this image cannot enumerate them
}

Tab enumeration depends on what the image’s browser exposes. When it cannot, the route answers supported: false with a reason rather than failing — an agent that gets a 501 learns nothing it can act on, and one that gets a sentence can fall back to reading the screen.

Driving pages

There is no page-object model, no selector engine and no injected script. A page is pixels and a keyboard:

await machine.browser.open("https://example.com");
await machine.keyboard.press("F6"); // focus the address bar
await machine.keyboard.type("search terms");
await machine.keyboard.press("Return");

const shot = await machine.screen.screenshot({ format: "png" });
await machine.mouse.click({ at: { x: 640, y: 400 } });

That is deliberate: the point of a real desktop is that a site cannot tell it apart from a person’s, and an injected automation surface is exactly the thing that gives that away. If you want a headless browser API, run one inside the machine over a terminal and reach it through a published port.

The browser profile persists

Cookies, logins and extensions live on the disk, so they survive a stop and a start, and they are carried by a snapshot, fork or template. Logging into a site once and saving the machine as a template is the intended way to give every future machine that session.

A secret is the opposite: delivered to tmpfs, and deliberately not carried by a capture.

Was this page helpful?