Computer Use (Desktop)
Computer use endpoints let you programmatically control a full Linux desktop running inside a sandbox.
The runtime is based on Ubuntu 22.04 with an XFCE4 desktop at 1440x900 resolution. Firefox ESR, Google Chrome, and VS Code are pre-installed.
For a full endpoint reference, see the Computer Use (Desktop) API.
Desktop access
Section titled “Desktop access”To open the desktop in a browser, see VNC Access.
Display info
Section titled “Display info”Query the current display name and resolution. Useful for calculating coordinates before sending mouse or screenshot commands.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.display_info())import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.displayInfo())await client.close()Resize screen
Section titled “Resize screen”Change the virtual display resolution. Width must be between 320 and 7680, height between 320 and 4320.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.resize_screen(width=1280, height=800))import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.resizeScreen({ width: 1280, height: 800 }))await client.close()List windows
Section titled “List windows”Inspect all open windows on the desktop. Each window includes its position, size, class, title, and whether it is focused.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)for window in sandbox.desktop.windows(): print(f"{window.title} ({window.width}x{window.height}) focused={window.focused}")import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
const windows = await sandbox.desktop.windows()windows.forEach((window) => console.log(window.title, window.width + "x" + window.height, "focused=" + window.focused))await client.close()Screenshots
Section titled “Screenshots”Full screen
Section titled “Full screen”Capture the entire screen. Supports png, jpg, or jpeg format via the format query parameter. JPEG quality can be set with quality (1—100).
from pathlib import Pathfrom leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)screenshot = sandbox.desktop.screenshot(image_format="png")Path("screen.png").write_bytes(screenshot)import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
const bytes = await sandbox.desktop.screenshot({ format: "png" })console.log("screenshot bytes", bytes.byteLength)await client.close()Region
Section titled “Region”Capture a specific region of the screen.
from pathlib import Pathfrom leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)region = sandbox.desktop.screenshot_region( x=0, y=0, width=800, height=600, image_format="jpg", quality=85,)Path("region.jpg").write_bytes(region)import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
const bytes = await sandbox.desktop.screenshotRegion({x: 0,y: 0,width: 800,height: 600,format: "jpg",quality: 85,})
console.log("region bytes", bytes.byteLength)await client.close()Get pointer position
Section titled “Get pointer position”from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.pointer_position())import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.pointerPosition())await client.close()Move pointer
Section titled “Move pointer”Move the cursor to absolute coordinates. Returns the new pointer position.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.move_pointer(x=320, y=240))import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.movePointer(320, 240))await client.close()Click at the current pointer position or at optional x, y coordinates. The button field maps to X11 buttons: 1 (left, default), 2 (middle), 3 (right). Returns the pointer position after the click.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)
sandbox.desktop.click(x=320, y=240, button=1)sandbox.desktop.click(button=3)import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
await sandbox.desktop.click({ x: 320, y: 240, button: 1 })await sandbox.desktop.click({ button: 3 })await client.close()Drag from one coordinate to another. Uses button 1 (left) by default.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print( sandbox.desktop.drag( from_x=100, from_y=200, to_x=400, to_y=200, ))import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.drag({ fromX: 100, fromY: 200, toX: 400, toY: 200 }))await client.close()Scroll
Section titled “Scroll”Scroll at the current pointer position. Direction must be up, down, left, or right. The amount field controls how many scroll steps to perform (1—100, defaults to 1).
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)sandbox.desktop.scroll(direction="down", amount=3)import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
await sandbox.desktop.scroll({ direction: "down", amount: 3 })await client.close()Keyboard
Section titled “Keyboard”Type text
Section titled “Type text”Type a string of text as if entered from the keyboard. Supports up to 50,000 characters.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)sandbox.desktop.type_text(text="hello from Leap0")import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
await sandbox.desktop.typeText("hello from Leap0")await client.close()Press key
Section titled “Press key”Press a single key by its X11 keysym name (e.g. Return, Escape, Tab, BackSpace, space).
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)sandbox.desktop.press_key(key="Return")import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
await sandbox.desktop.pressKey("Return")await client.close()Hotkey
Section titled “Hotkey”Press a multi-key shortcut. Pass an array of keys that will be joined with + and sent as a single xdotool key combination (e.g. ["ctrl", "l"] becomes ctrl+l). Accepts 1—10 keys.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)sandbox.desktop.hotkey(keys=["ctrl", "l"])import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
await sandbox.desktop.hotkey(["ctrl", "l"])await client.close()Recordings
Section titled “Recordings”Screen recordings are captured as MP4 files (H.264/libx264, yuv420p) using ffmpeg at 12 fps. Files are saved inside the sandbox at ~/.cache/leap0-recordings by default (configurable via the LEAP0_RECORDINGS_DIR environment variable). Only one recording can be active at a time.
Start recording
Section titled “Start recording”from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.start_recording())import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.startRecording())await client.close()Stop recording
Section titled “Stop recording”from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.stop_recording())import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.stopRecording())await client.close()Recording status
Section titled “Recording status”Get the state of the current or most recent recording.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.recording_status())import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.recordingStatus())await client.close()List recordings
Section titled “List recordings”from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)for recording in sandbox.desktop.recordings(): print(f"{recording.id}: {recording.size_bytes} bytes")import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
const recordings = await sandbox.desktop.recordings()recordings.forEach((recording) => console.log(recording.id, recording.sizeBytes + " bytes"))await client.close()Get recording
Section titled “Get recording”from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.get_recording("<recording_id>"))import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.getRecording("<recording_id>"))await client.close()Download recording
Section titled “Download recording”Returns the MP4 file as a binary download.
from pathlib import Pathfrom leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)recording = sandbox.desktop.download_recording("<recording_id>")Path("recording.mp4").write_bytes(recording)import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
const bytes = await sandbox.desktop.downloadRecording("<recording_id>")console.log("recording bytes", bytes.byteLength)await client.close()Delete recording
Section titled “Delete recording”Delete a saved recording. Active recordings cannot be deleted. Stop them first. Returns 204 No Content on success.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)sandbox.desktop.delete_recording("<recording_id>")import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
await sandbox.desktop.deleteRecording("<recording_id>")await client.close()Process management
Section titled “Process management”The template runs five processes: xvfb (virtual framebuffer), xfce4 (desktop session), x11vnc (VNC server), novnc (web-based VNC client via websockify), and control (the HTTP API server). The four managed processes (xvfb, xfce4, x11vnc, novnc) can be inspected and restarted through the endpoints below.
Overall status
Section titled “Overall status”from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)print(sandbox.desktop.process_status())import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.processStatus())await client.close()Status stream (SSE)
Section titled “Status stream (SSE)”Subscribe to a live Server-Sent Events stream of process status. The server sends an event immediately on connect, whenever a process status changes (e.g. after a restart), and every 2 seconds as a heartbeat. Each event has the same payload as GET /api/status. The connection stays open until the client disconnects.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)for status in sandbox.desktop.status_stream(): print(status) breakimport { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
for await (const status of sandbox.desktop.statusStream()) {console.log(status)break}
await client.close()Per-process endpoints
Section titled “Per-process endpoints”Inspect or restart individual processes. Replace {name} with xvfb, xfce4, x11vnc, or novnc.
from leap0 import DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client
client = Leap0Client()sandbox = client.sandboxes.create(template_name=DEFAULT_DESKTOP_TEMPLATE_NAME)
print(sandbox.desktop.get_process("x11vnc"))print(sandbox.desktop.restart_process("xfce4"))print(sandbox.desktop.process_logs("novnc"))import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "leap0"
const client = new Leap0Client()const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
console.log(await sandbox.desktop.getProcess("x11vnc"))console.log(await sandbox.desktop.restartProcess("xfce4"))console.log(await sandbox.desktop.processLogs("novnc"))await client.close()