Runtime

How to take a screenshot in a cloud sandbox

Start the sandbox's desktop and call sbx.desktop.screenshot() for PNG bytes, or run Playwright's page.screenshot() for a full page.

On Runtime a screenshot is one call, taken inside a microVM that is thrown away afterwards. The page you capture runs in its own Firecracker machine, so a hostile site or a broken app never touches your server, and each capture can start from a clean browser. A new sandbox ran its first command 351 ms after the create request at the median on 24 September 2026 (speed), and one that waits on a page load costs $0.03125 an hour at 2 vCPU and 4 GiB, because Runtime bills the CPU it uses (pricing).

Capture the screen

TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ diskMiB: 8192 });await sbx.desktop.start({ width: 1440, height: 900 }); // the first start installs itawait sbx.desktop.open("https://example.com");await writeFile("example.png", await sbx.desktop.screenshot());
Pythonfrom withruntime import Sandboxwith Sandbox.create(disk_mib=8192) as sbx:    sbx.desktop.start(width=1440, height=900)    sbx.desktop.open("https://example.com")    with open("example.png", "wb") as file:        file.write(sbx.desktop.screenshot())
Terminalruntime sandbox desktop "${id}" startruntime sandbox desktop "${id}" open https://example.comruntime sandbox desktop "${id}" screenshot example.png

The screenshot is the whole screen at the size you started it with: the browser window, its address bar and anything else open. The first start in a sandbox installs the desktop (about 90 seconds and 1 GB of disk, once), and Firefox follows in the background; open waits for it.

Capture an app running in the same sandbox

An app an agent just built can be photographed without exposing it to the internet. Start it with spawn, which keeps it running, and point the desktop's browser at localhost:

TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 1800 });await sbx.files.upload("./site", "/workspace/site");await sbx.spawn("python3 -m http.server 3000", { cwd: "/workspace/site" });await sbx.desktop.start({ width: 1280, height: 800 });await sbx.desktop.open("http://localhost:3000");await writeFile("home.png", await sbx.desktop.screenshot());
Pythonfrom withruntime import Sandboxwith Sandbox.create(disk_mib=8192, timeout_seconds=1800) as sbx:    sbx.files.upload("./site", "/workspace/site")    sbx.spawn("python3 -m http.server 3000", cwd="/workspace/site")    sbx.desktop.start(width=1280, height=800)    sbx.desktop.open("http://localhost:3000")    with open("home.png", "wb") as file:        file.write(sbx.desktop.screenshot())

To look at the app yourself as well, share port 3000 as a private HTTPS preview.

A full-page capture with Playwright

The desktop captures what fits on the screen. For the whole length of a page, or for thousands of pages from a script, use a headless browser. With an image named playwright built as in the Playwright guide, a capture is one script:

TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";const script = `import { chromium } from "playwright";const browser = await chromium.launch();const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });await page.goto(process.argv[2], { waitUntil: "networkidle" });await page.screenshot({ path: "full.png", fullPage: true });await browser.close();`;await using sbx = await Sandbox.create({ image: "playwright" });await sbx.files.write("/workspace/full.mjs", script);await sbx.exec(["node", "full.mjs", "https://example.com"], { check: true, timeoutMs: 120_000 });await writeFile("full.png", await sbx.files.read("/workspace/full.png"));

Many pages at once

Each capture can have a sandbox of its own, so no two pages share cookies, storage or a crashed browser. A paid account runs 100 sandboxes at once to start with, and the free trial eight:

TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";const urls = ["https://example.com", "https://example.org", "https://example.net"];await Promise.all(  urls.map(async (url, i) => {    await using sbx = await Sandbox.create({ diskMiB: 8192 });    await sbx.desktop.start();    await sbx.desktop.open(url);    await writeFile(`page-${i}.png`, await sbx.desktop.screenshot());  }),);

A create past the account's limit waits for room for up to two minutes rather than failing, so a batch larger than the limit queues (errors and retries).

Which way to take it

Way Captures Best for
sbx.desktop.screenshot() The whole screen, as PNG Agents that act on what they see
runtime sandbox desktop <id> screenshot <file> The same, from a terminal Scripts and quick checks
runtime_sandbox_desktop_screenshot The same, as an MCP tool result Agents connected to Runtime's MCP
Playwright page.screenshot() One page, visible area or full length Pages in bulk, visual tests
sbx.desktop.recordings An MP4 of the screen over time Showing what happened between shots

Mistakes and how Runtime handles them

  • A disk too small for a browser. The default 4 GiB sandbox had about 2.5 GiB free on 24 September 2026, and the desktop and Firefox take about 1.5 GB. Ask for diskMiB: 8192.
  • Capturing before the page draws. open starts Firefox on the address and returns; it does not wait for a slow page to load. Wait for a known element with Playwright, or take another screenshot after a pause.
  • A server started with exec. It ends with its command, and the browser then shows an error page. spawn keeps it running.
  • Trial ports. A trial sandbox reaches ports 80 and 443 only, which covers ordinary websites; a paid sandbox reaches any port.

Start

Terminalnpx withruntime sandbox run --trial --keep -- echo ready

New accounts get 50 free sandbox hours, no card.

Facts on this page were checked on 25 September 2026.