Computer Use enables programmatic control of desktop environments within sandboxes. It provides mouse, keyboard, screenshot, screen recording, and display operations for automating GUI interactions and testing desktop applications.
Computer Use and VNC work together to enable both manual and automated desktop interactions. VNC provides the visual interface for users to manually interact with the desktop, while Computer Use provides the programmatic API for AI agents to automate operations.
Computer Use is available for Linux. Windows and macOS support is currently in private alpha.
- GUI application testing: automate interactions with native applications, click buttons, fill forms, and validate UI behavior
- Visual testing & screenshots: capture screenshots of applications, compare UI states, and perform visual regression testing
- Desktop automation: automate repetitive desktop tasks, file management through GUI, and complex workflows
Start Computer Use
Section titled “Start Computer Use”Start all computer use processes (Xvfb, xfce4, x11vnc, novnc) in the Sandbox.
result = sandbox.computer_use.start()print("Computer use processes started:", result.message)const result = await sandbox.computerUse.start();console.log('Computer use processes started:', result.message);result = sandbox.computer_use.startputs "Computer use processes started: #{result.message}"err := sandbox.ComputerUse.Start(ctx)if err != nil { log.Fatal(err)}defer sandbox.ComputerUse.Stop(ctx)
fmt.Println("Computer use processes started")var result = sandbox.computerUse.start();System.out.println("Computer use processes started: " + result.getMessage());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/start' \ --request POSTStop Computer Use
Section titled “Stop Computer Use”Stop all computer use processes in the Sandbox.
result = sandbox.computer_use.stop()print("Computer use processes stopped:", result.message)const result = await sandbox.computerUse.stop();console.log('Computer use processes stopped:', result.message);result = sandbox.computer_use.stopputs "Computer use processes stopped: #{result.message}"err := sandbox.ComputerUse.Stop(ctx)if err != nil { log.Fatal(err)}
fmt.Println("Computer use processes stopped")var result = sandbox.computerUse.stop();System.out.println("Computer use processes stopped: " + result.getMessage());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/stop' \ --request POSTGet status
Section titled “Get status”Get the status of all computer use processes.
response = sandbox.computer_use.get_status()print("Computer use status:", response.status)const status = await sandbox.computerUse.getStatus();console.log('Computer use status:', status.status);response = sandbox.computer_use.statusputs "Computer use status: #{response.status}"status, err := sandbox.ComputerUse.GetStatus(ctx)if err != nil { log.Fatal(err)}
fmt.Printf("Computer use status: %v\n", status["status"])var response = sandbox.computerUse.getStatus();System.out.println("Computer use status: " + response.getStatus());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/status'Get process status
Section titled “Get process status”Get the status of a specific VNC process.
xvfb_status = sandbox.computer_use.get_process_status("xvfb")novnc_status = sandbox.computer_use.get_process_status("novnc")const xvfbStatus = await sandbox.computerUse.getProcessStatus('xvfb');const noVncStatus = await sandbox.computerUse.getProcessStatus('novnc');xvfb_status = sandbox.computer_use.get_process_status("xvfb")no_vnc_status = sandbox.computer_use.get_process_status("novnc")curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/status'Restart process
Section titled “Restart process”Restart a specific VNC process.
result = sandbox.computer_use.restart_process("xfce4")print("XFCE4 process restarted:", result.message)const result = await sandbox.computerUse.restartProcess('xfce4');console.log('XFCE4 process restarted:', result.message);result = sandbox.computer_use.restart_process("xfce4")puts "XFCE4 process restarted: #{result.message}"curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/restart' \ --request POSTGet process logs
Section titled “Get process logs”Get logs for a specific VNC process.
logs = sandbox.computer_use.get_process_logs("novnc")print("NoVNC logs:", logs)const logsResp = await sandbox.computerUse.getProcessLogs('novnc');console.log('NoVNC logs:', logsResp.logs);logs = sandbox.computer_use.get_process_logs("novnc")puts "NoVNC logs: #{logs}"curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/logs'Get process errors
Section titled “Get process errors”Get error logs for a specific VNC process.
errors = sandbox.computer_use.get_process_errors("x11vnc")print("X11VNC errors:", errors)const errorsResp = await sandbox.computerUse.getProcessErrors('x11vnc');console.log('X11VNC errors:', errorsResp.errors);errors = sandbox.computer_use.get_process_errors("x11vnc")puts "X11VNC errors: #{errors}"curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/errors'Mouse operations
Section titled “Mouse operations”Click the mouse at the specified coordinates. button is one of left, right, or middle (case-insensitive; defaults to left); other values return an error.
# Single left clickresult = sandbox.computer_use.mouse.click(100, 200)
# Double clickdouble_click = sandbox.computer_use.mouse.click(100, 200, "left", True)
# Right clickright_click = sandbox.computer_use.mouse.click(100, 200, "right")// Single left clickconst result = await sandbox.computerUse.mouse.click(100, 200);
// Double clickconst doubleClick = await sandbox.computerUse.mouse.click(100, 200, 'left', true);
// Right clickconst rightClick = await sandbox.computerUse.mouse.click(100, 200, 'right');# Single left clickresult = sandbox.computer_use.mouse.click(x: 100, y: 200)
# Double clickdouble_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'left', double: true)
# Right clickright_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'right')// Single left clickresult, err := sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, nil, nil)if err != nil { log.Fatal(err)}
// Double clickdoubleClick := trueresult, err = sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, nil, &doubleClick)
// Right clickrightButton := "right"result, err = sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, &rightButton, nil)// Single left clicksandbox.computerUse.click(100, 200);
// Double clicksandbox.computerUse.doubleClick(100, 200);
// Right clicksandbox.computerUse.click(100, 200, "right");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/click' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "button": "left", "double": true, "x": 100, "y": 200}'Move the mouse cursor to the specified coordinates.
result = sandbox.computer_use.mouse.move(100, 200)print(f"Mouse moved to: {result.x}, {result.y}")const result = await sandbox.computerUse.mouse.move(100, 200);console.log(`Mouse moved to: ${result.x}, ${result.y}`);result = sandbox.computer_use.mouse.move(x: 100, y: 200)puts "Mouse moved to: #{result.x}, #{result.y}"result, err := sandbox.ComputerUse.Mouse().Move(ctx, 100, 200)if err != nil { log.Fatal(err)}
fmt.Printf("Mouse moved to: %v, %v\n", result["x"], result["y"])var result = sandbox.computerUse.moveMouse(100, 200);System.out.println("Mouse moved to: " + result.getX() + ", " + result.getY());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/move' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "x": 1, "y": 1}'Drag the mouse from start coordinates to end coordinates.
result = sandbox.computer_use.mouse.drag(50, 50, 150, 150)print(f"Drag ended at {result.x}, {result.y}")const result = await sandbox.computerUse.mouse.drag(50, 50, 150, 150);console.log(`Drag ended at ${result.x}, ${result.y}`);result = sandbox.computer_use.mouse.drag(start_x: 50, start_y: 50, end_x: 150, end_y: 150)puts "Drag ended at #{result.x}, #{result.y}"result, err := sandbox.ComputerUse.Mouse().Drag(ctx, 50, 50, 150, 150, nil)if err != nil { log.Fatal(err)}
fmt.Printf("Dragged to %v, %v\n", result["x"], result["y"])var result = sandbox.computerUse.drag(50, 50, 150, 150);System.out.println("Drag ended at: " + result.getX() + ", " + result.getY());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/drag' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "button": "left", "endX": 200, "endY": 300, "startX": 100, "startY": 100}'Scroll
Section titled “Scroll”Scroll the mouse wheel at the specified coordinates. direction is up or down (other values return an error). amount is the number of scroll wheel ticks to send — one tick is roughly one notch of a physical mouse wheel, which moves a few lines in most apps. Defaults to 1 if omitted.
# Scroll upscroll_up = sandbox.computer_use.mouse.scroll(100, 200, "up", 3)
# Scroll downscroll_down = sandbox.computer_use.mouse.scroll(100, 200, "down", 5)// Scroll upconst scrollUp = await sandbox.computerUse.mouse.scroll(100, 200, 'up', 3);
// Scroll downconst scrollDown = await sandbox.computerUse.mouse.scroll(100, 200, 'down', 5);# Scroll upscroll_up = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'up', amount: 3)
# Scroll downscroll_down = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'down', amount: 5)// Scroll upamount := 3success, err := sandbox.ComputerUse.Mouse().Scroll(ctx, 100, 200, "up", &amount)if err != nil { log.Fatal(err)}
// Scroll downamount = 5success, err = sandbox.ComputerUse.Mouse().Scroll(ctx, 100, 200, "down", &amount)// Scroll up (negative vertical delta maps to "up")sandbox.computerUse.scroll(100, 200, 0, -3);
// Scroll downsandbox.computerUse.scroll(100, 200, 0, 5);curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/scroll' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "amount": 3, "direction": "down", "x": 100, "y": 200}'Get position
Section titled “Get position”Get the current mouse cursor position.
position = sandbox.computer_use.mouse.get_position()print(f"Mouse is at: {position.x}, {position.y}")const position = await sandbox.computerUse.mouse.getPosition();console.log(`Mouse is at: ${position.x}, ${position.y}`);position = sandbox.computer_use.mouse.positionputs "Mouse is at: #{position.x}, #{position.y}"position, err := sandbox.ComputerUse.Mouse().GetPosition(ctx)if err != nil { log.Fatal(err)}
fmt.Printf("Mouse is at: %v, %v\n", position["x"], position["y"])var position = sandbox.computerUse.getMousePosition();System.out.println("Mouse is at: " + position.getX() + ", " + position.getY());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/position'Keyboard operations
Section titled “Keyboard operations”Types arbitrary text, including uppercase letters, symbols, and non-ASCII characters. Newlines (\n, \r, \r\n) are translated into Enter key presses; literal tab and other control characters are rejected.
sandbox.computer_use.keyboard.type("Hello, World!")
# With delay between characterssandbox.computer_use.keyboard.type("Slow typing", 100)await sandbox.computerUse.keyboard.type('Hello, World!');
// With delay between charactersawait sandbox.computerUse.keyboard.type('Slow typing', 100);sandbox.computer_use.keyboard.type(text: "Hello, World!")
# With delay between characterssandbox.computer_use.keyboard.type(text: "Slow typing", delay: 100)err := sandbox.ComputerUse.Keyboard().Type(ctx, "Hello, World!", nil)if err != nil { log.Fatal(err)}
// With delay between charactersdelay := 100err = sandbox.ComputerUse.Keyboard().Type(ctx, "Slow typing", &delay)sandbox.computerUse.typeText("Hello, World!");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/type' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "delay": 1, "text": ""}'Press a key with optional modifiers.
# Press Entersandbox.computer_use.keyboard.press("enter")
# Press Ctrl+Csandbox.computer_use.keyboard.press("c", ["ctrl"])
# Press Ctrl+Shift+Tsandbox.computer_use.keyboard.press("t", ["ctrl", "shift"])// Press Enterawait sandbox.computerUse.keyboard.press('enter');
// Press Ctrl+Cawait sandbox.computerUse.keyboard.press('c', ['ctrl']);
// Press Ctrl+Shift+Tawait sandbox.computerUse.keyboard.press('t', ['ctrl', 'shift']);# Press Entersandbox.computer_use.keyboard.press(key: "enter")
# Press Ctrl+Csandbox.computer_use.keyboard.press(key: "c", modifiers: ["ctrl"])
# Press Ctrl+Shift+Tsandbox.computer_use.keyboard.press(key: "t", modifiers: ["ctrl", "shift"])// Press Entererr := sandbox.ComputerUse.Keyboard().Press(ctx, "enter", nil)if err != nil { log.Fatal(err)}
// Press Ctrl+Cerr = sandbox.ComputerUse.Keyboard().Press(ctx, "c", []string{"ctrl"})
// Press Ctrl+Shift+Terr = sandbox.ComputerUse.Keyboard().Press(ctx, "t", []string{"ctrl", "shift"})// Press Entersandbox.computerUse.pressKey("enter");
// Press Ctrl+Csandbox.computerUse.pressHotkey("ctrl", "c");
// Press Ctrl+Shift+Tsandbox.computerUse.pressHotkey("ctrl", "shift", "t");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/key' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "key": "enter", "modifiers": []}'Hotkey
Section titled “Hotkey”Press a hotkey combination.
# Copysandbox.computer_use.keyboard.hotkey("ctrl+c")
# Pastesandbox.computer_use.keyboard.hotkey("ctrl+v")
# Alt+Tabsandbox.computer_use.keyboard.hotkey("alt+tab")// Copyawait sandbox.computerUse.keyboard.hotkey('ctrl+c');
// Pasteawait sandbox.computerUse.keyboard.hotkey('ctrl+v');
// Alt+Tabawait sandbox.computerUse.keyboard.hotkey('alt+tab');# Copysandbox.computer_use.keyboard.hotkey(keys: "ctrl+c")
# Pastesandbox.computer_use.keyboard.hotkey(keys: "ctrl+v")
# Alt+Tabsandbox.computer_use.keyboard.hotkey(keys: "alt+tab")// Copyerr := sandbox.ComputerUse.Keyboard().Hotkey(ctx, "ctrl+c")if err != nil { log.Fatal(err)}
// Pasteerr = sandbox.ComputerUse.Keyboard().Hotkey(ctx, "ctrl+v")
// Alt+Taberr = sandbox.ComputerUse.Keyboard().Hotkey(ctx, "alt+tab")// Copysandbox.computerUse.pressHotkey("ctrl", "c");
// Pastesandbox.computerUse.pressHotkey("ctrl", "v");
// Alt+Tabsandbox.computerUse.pressHotkey("alt", "tab");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/hotkey' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "keys": "ctrl+c"}'Supported keys
Section titled “Supported keys”keyboard.press() and keyboard.hotkey() are case-insensitive for named keys. The following are supported:
| Category | Keys |
|---|---|
| Modifiers | ctrl, alt, shift, cmd |
| Editing | enter, escape, tab, backspace, delete, space |
| Navigation | home, end, pageup, pagedown, insert, arrow keys (up, down, left, right) |
| Function keys | f1 through f24 |
| Numpad | num0–num9, num_plus, num_minus, num_asterisk, num_slash, num_decimal, num_enter, num_equal, num_lock |
| Letters and digits | a–z (case-insensitive), 0–9 |
| Punctuation | ` - = [ ] \ ; ' , . / |
| Other | capslock, menu |
Common aliases like Return → enter, control → ctrl, command / meta / win → cmd, and option → alt are normalized automatically. Unsupported or malformed inputs return an error, sometimes with a suggested alternative.
Accessibility operations
Section titled “Accessibility operations”Use Linux accessibility operations to inspect the AT-SPI tree and interact with UI elements by node ID. Start Computer Use before calling accessibility methods.
Get tree
Section titled “Get tree”Read an accessibility tree for the focused app, a specific process, or all apps.
# Focused appfocused_tree = sandbox.computer_use.accessibility.get_tree(scope="focused", max_depth=2)
# Specific processprocess_tree = sandbox.computer_use.accessibility.get_tree( scope="pid", pid=1234, max_depth=2,)
# All appsdesktop_tree = sandbox.computer_use.accessibility.get_tree(scope="all", max_depth=2)// Focused appconst focusedTree = await sandbox.computerUse.accessibility.getTree({ scope: 'focused', maxDepth: 2,});
// Specific processconst processTree = await sandbox.computerUse.accessibility.getTree({ scope: 'pid', pid: 1234, maxDepth: 2,});
// All appsconst desktopTree = await sandbox.computerUse.accessibility.getTree({ scope: 'all', maxDepth: 2,});# Focused appfocused_tree = sandbox.computer_use.accessibility.get_tree(scope: "focused", max_depth: 2)
# Specific processprocess_tree = sandbox.computer_use.accessibility.get_tree( scope: "pid", pid: 1234, max_depth: 2)
# All appsdesktop_tree = sandbox.computer_use.accessibility.get_tree(scope: "all", max_depth: 2)maxDepth := 2
// Focused appfocusedScope := "focused"focusedTree, err := sandbox.ComputerUse.Accessibility().GetTree(ctx, &daytona.AccessibilityTreeOptions{ Scope: &focusedScope, MaxDepth: &maxDepth,})if err != nil { log.Fatal(err)}
// Specific processprocessScope := "pid"pid := 1234processTree, err := sandbox.ComputerUse.Accessibility().GetTree(ctx, &daytona.AccessibilityTreeOptions{ Scope: &processScope, PID: &pid, MaxDepth: &maxDepth,})if err != nil { log.Fatal(err)}
// All appsallScope := "all"desktopTree, err := sandbox.ComputerUse.Accessibility().GetTree(ctx, &daytona.AccessibilityTreeOptions{ Scope: &allScope, MaxDepth: &maxDepth,})if err != nil { log.Fatal(err)}// Focused appvar focusedTree = sandbox.computerUse.getAccessibilityTree("focused", null, 2);
// Specific processvar processTree = sandbox.computerUse.getAccessibilityTree("pid", 1234, 2);
// All appsvar desktopTree = sandbox.computerUse.getAccessibilityTree("all", null, 2);# Focused appcurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/tree?scope=focused&maxDepth=2'
# Specific processcurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/tree?scope=pid&pid=1234&maxDepth=2'
# All appscurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/tree?scope=all&maxDepth=2'Find nodes
Section titled “Find nodes”Search the accessibility tree by role, accessible name, state, and scope.
# Find buttons by accessible namebuttons = sandbox.computer_use.accessibility.find_nodes( scope="focused", role="button", name="Submit", name_match="substring", limit=10,)
# Find text entries in a processentries = sandbox.computer_use.accessibility.find_nodes( scope="pid", pid=1234, role="entry", states=["enabled", "focusable"], limit=10,)
# Find visible nodes across all appsvisible_nodes = sandbox.computer_use.accessibility.find_nodes( scope="all", states=["visible"], limit=20,)// Find buttons by accessible nameconst buttons = await sandbox.computerUse.accessibility.findNodes({ scope: 'focused', role: 'button', name: 'Submit', nameMatch: 'substring', limit: 10,});
// Find text entries in a processconst entries = await sandbox.computerUse.accessibility.findNodes({ scope: 'pid', pid: 1234, role: 'entry', states: ['enabled', 'focusable'], limit: 10,});
// Find visible nodes across all appsconst visibleNodes = await sandbox.computerUse.accessibility.findNodes({ scope: 'all', states: ['visible'], limit: 20,});# Find buttons by accessible namebuttons = sandbox.computer_use.accessibility.find_nodes( scope: "focused", role: "button", name: "Submit", name_match: "substring", limit: 10)
# Find text entries in a processentries = sandbox.computer_use.accessibility.find_nodes( scope: "pid", pid: 1234, role: "entry", states: ["enabled", "focusable"], limit: 10)
# Find visible nodes across all appsvisible_nodes = sandbox.computer_use.accessibility.find_nodes( scope: "all", states: ["visible"], limit: 20)limit := 10
// Find buttons by accessible namefocusedScope := "focused"buttonRole := "button"submitName := "Submit"substringMatch := "substring"buttons, err := sandbox.ComputerUse.Accessibility().FindNodes(ctx, &daytona.AccessibilityFindOptions{ Scope: &focusedScope, Role: &buttonRole, Name: &submitName, NameMatch: &substringMatch, Limit: &limit,})if err != nil { log.Fatal(err)}
// Find text entries in a processprocessScope := "pid"pid := 1234entryRole := "entry"entries, err := sandbox.ComputerUse.Accessibility().FindNodes(ctx, &daytona.AccessibilityFindOptions{ Scope: &processScope, PID: &pid, Role: &entryRole, States: []string{"enabled", "focusable"}, Limit: &limit,})if err != nil { log.Fatal(err)}
// Find visible nodes across all appsallScope := "all"visibleLimit := 20visibleNodes, err := sandbox.ComputerUse.Accessibility().FindNodes(ctx, &daytona.AccessibilityFindOptions{ Scope: &allScope, States: []string{"visible"}, Limit: &visibleLimit,})if err != nil { log.Fatal(err)}// Find buttons by accessible namevar buttons = sandbox.computerUse.findAccessibilityNodes( new FindAccessibilityNodesRequest() .scope("focused") .role("button") .name("Submit") .nameMatch("substring") .limit(10));
// Find text entries in a processvar entries = sandbox.computerUse.findAccessibilityNodes( new FindAccessibilityNodesRequest() .scope("pid") .pid(1234) .role("entry") .states(java.util.List.of("enabled", "focusable")) .limit(10));
// Find visible nodes across all appsvar visibleNodes = sandbox.computerUse.findAccessibilityNodes( new FindAccessibilityNodesRequest() .scope("all") .states(java.util.List.of("visible")) .limit(20));# Find buttons by accessible namecurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/find' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "scope": "focused", "role": "button", "name": "Submit", "nameMatch": "substring", "limit": 10}'
# Find text entries in a processcurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/find' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "scope": "pid", "pid": 1234, "role": "entry", "states": ["enabled", "focusable"], "limit": 10}'
# Find visible nodes across all appscurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/find' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "scope": "all", "states": ["visible"], "limit": 20}'Focus node
Section titled “Focus node”Move keyboard focus to a node returned by get_tree or find_nodes.
sandbox.computer_use.accessibility.focus_node("node-id")await sandbox.computerUse.accessibility.focusNode('node-id');sandbox.computer_use.accessibility.focus_node(id: "node-id")if err := sandbox.ComputerUse.Accessibility().FocusNode(ctx, "node-id"); err != nil { log.Fatal(err)}sandbox.computerUse.focusAccessibilityNode("node-id");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/node/focus' \ --request POST \ --header 'Content-Type: application/json' \ --data '{"id":"node-id"}'Invoke node
Section titled “Invoke node”Run a node action, such as pressing a button.
# Invoke the primary actionsandbox.computer_use.accessibility.invoke_node("node-id")
# Invoke a named actionsandbox.computer_use.accessibility.invoke_node("node-id", action="click")// Invoke the primary actionawait sandbox.computerUse.accessibility.invokeNode('node-id');
// Invoke a named actionawait sandbox.computerUse.accessibility.invokeNode('node-id', 'click');# Invoke the primary actionsandbox.computer_use.accessibility.invoke_node(id: "node-id")
# Invoke a named actionsandbox.computer_use.accessibility.invoke_node(id: "node-id", action: "click")// Invoke the primary actionif err := sandbox.ComputerUse.Accessibility().InvokeNode(ctx, "node-id", nil); err != nil { log.Fatal(err)}
// Invoke a named actionaction := "click"if err := sandbox.ComputerUse.Accessibility().InvokeNode(ctx, "node-id", &action); err != nil { log.Fatal(err)}// Invoke the primary actionsandbox.computerUse.invokeAccessibilityNode("node-id");
// Invoke a named actionsandbox.computerUse.invokeAccessibilityNode("node-id", "click");# Invoke the primary actioncurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/node/invoke' \ --request POST \ --header 'Content-Type: application/json' \ --data '{"id":"node-id"}'
# Invoke a named actioncurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/node/invoke' \ --request POST \ --header 'Content-Type: application/json' \ --data '{"id":"node-id","action":"click"}'Set node value
Section titled “Set node value”Write text or value content to nodes that support value changes.
sandbox.computer_use.accessibility.set_node_value("node-id", "hello")await sandbox.computerUse.accessibility.setNodeValue('node-id', 'hello');sandbox.computer_use.accessibility.set_node_value(id: "node-id", value: "hello")if err := sandbox.ComputerUse.Accessibility().SetNodeValue(ctx, "node-id", "hello"); err != nil { log.Fatal(err)}sandbox.computerUse.setAccessibilityNodeValue("node-id", "hello");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/node/value' \ --request POST \ --header 'Content-Type: application/json' \ --data '{"id":"node-id","value":"hello"}'Screenshot operations
Section titled “Screenshot operations”Take full screen
Section titled “Take full screen”Take a screenshot of the entire screen.
screenshot = sandbox.computer_use.screenshot.take_full_screen()print(f"Screenshot size: {screenshot.width}x{screenshot.height}")
# With cursor visiblewith_cursor = sandbox.computer_use.screenshot.take_full_screen(True)const screenshot = await sandbox.computerUse.screenshot.takeFullScreen();console.log(`Screenshot size: ${screenshot.width}x${screenshot.height}`);
// With cursor visibleconst withCursor = await sandbox.computerUse.screenshot.takeFullScreen(true);screenshot = sandbox.computer_use.screenshot.take_full_screenputs "Screenshot size: #{screenshot.width}x#{screenshot.height}"
# With cursor visiblewith_cursor = sandbox.computer_use.screenshot.take_full_screen(show_cursor: true)screenshot, err := sandbox.ComputerUse.Screenshot().TakeFullScreen(ctx, nil)if err != nil { log.Fatal(err)}
fmt.Printf("Screenshot captured, size: %d bytes\n", *screenshot.SizeBytes)
// With cursor visibleshowCursor := truewithCursor, err := sandbox.ComputerUse.Screenshot().TakeFullScreen(ctx, &showCursor)var screenshot = sandbox.computerUse.takeScreenshot();Integer sizeBytes = screenshot.getSizeBytes();System.out.println("Screenshot payload size: " + (sizeBytes != null ? sizeBytes + " bytes" : "n/a"));
// With cursor visiblevar withCursor = sandbox.computerUse.takeScreenshot(true);curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot'Take region
Section titled “Take region”Take a screenshot of a specific region.
from daytona import ScreenshotRegion
region = ScreenshotRegion(x=100, y=100, width=300, height=200)screenshot = sandbox.computer_use.screenshot.take_region(region)print(f"Captured region: {screenshot.region.width}x{screenshot.region.height}")const region = { x: 100, y: 100, width: 300, height: 200 };const screenshot = await sandbox.computerUse.screenshot.takeRegion(region);console.log(`Captured region: ${screenshot.region.width}x${screenshot.region.height}`);region = Daytona::ComputerUse::ScreenshotRegion.new(x: 100, y: 100, width: 300, height: 200)screenshot = sandbox.computer_use.screenshot.take_region(region: region)puts "Captured region: #{screenshot.region.width}x#{screenshot.region.height}"region := types.ScreenshotRegion{X: 100, Y: 100, Width: 300, Height: 200}screenshot, err := sandbox.ComputerUse.Screenshot().TakeRegion(ctx, region, nil)if err != nil { log.Fatal(err)}
fmt.Printf("Captured region: %dx%d\n", screenshot.Width, screenshot.Height)var screenshot = sandbox.computerUse.takeRegionScreenshot(100, 100, 300, 200);Integer sizeBytes = screenshot.getSizeBytes();System.out.println("Captured region, payload size: " + (sizeBytes != null ? sizeBytes + " bytes" : "n/a"));curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region?x=1&y=1&width=1&height=1'Take compressed
Section titled “Take compressed”Take a compressed screenshot of the entire screen.
from daytona import ScreenshotOptions
# Default compressionscreenshot = sandbox.computer_use.screenshot.take_compressed()
# High quality JPEGjpeg = sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="jpeg", quality=95, show_cursor=True))
# Scaled down PNGscaled = sandbox.computer_use.screenshot.take_compressed( ScreenshotOptions(format="png", scale=0.5))// Default compressionconst screenshot = await sandbox.computerUse.screenshot.takeCompressed();
// High quality JPEGconst jpeg = await sandbox.computerUse.screenshot.takeCompressed({ format: 'jpeg', quality: 95, showCursor: true});
// Scaled down PNGconst scaled = await sandbox.computerUse.screenshot.takeCompressed({ format: 'png', scale: 0.5});# Default compressionscreenshot = sandbox.computer_use.screenshot.take_compressed
# High quality JPEGjpeg = sandbox.computer_use.screenshot.take_compressed( options: Daytona::ComputerUse::ScreenshotOptions.new(format: "jpeg", quality: 95, show_cursor: true))
# Scaled down PNGscaled = sandbox.computer_use.screenshot.take_compressed( options: Daytona::ComputerUse::ScreenshotOptions.new(format: "png", scale: 0.5))// Compressed full screen (format, quality 1-100, scale factor)var screenshot = sandbox.computerUse.takeCompressedScreenshot("png", 80, 1.0);
// High quality JPEG at full scalevar jpeg = sandbox.computerUse.takeCompressedScreenshot("jpeg", 95, 1.0);
// Scaled down PNGvar scaled = sandbox.computerUse.takeCompressedScreenshot("png", 80, 0.5);curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/compressed'Take compressed region
Section titled “Take compressed region”Take a compressed screenshot of a specific region.
from daytona import ScreenshotRegion, ScreenshotOptions
region = ScreenshotRegion(x=0, y=0, width=800, height=600)screenshot = sandbox.computer_use.screenshot.take_compressed_region( region, ScreenshotOptions(format="webp", quality=80, show_cursor=True))print(f"Compressed size: {screenshot.size_bytes} bytes")const region = { x: 0, y: 0, width: 800, height: 600 };const screenshot = await sandbox.computerUse.screenshot.takeCompressedRegion(region, { format: 'webp', quality: 80, showCursor: true});console.log(`Compressed size: ${screenshot.size_bytes} bytes`);region = Daytona::ComputerUse::ScreenshotRegion.new(x: 0, y: 0, width: 800, height: 600)screenshot = sandbox.computer_use.screenshot.take_compressed_region( region: region, options: Daytona::ComputerUse::ScreenshotOptions.new(format: "webp", quality: 80, show_cursor: true))puts "Compressed size: #{screenshot.size_bytes} bytes"curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region/compressed?x=1&y=1&width=1&height=1'Screen Recording
Section titled “Screen Recording”Computer Use supports screen recording capabilities, allowing you to capture desktop sessions for debugging, documentation, or automation workflows.
Configure Recording Directory
Section titled “Configure Recording Directory”By default, recordings are saved to ~/.daytona/recordings. You can specify a custom directory by passing the DAYTONA_RECORDINGS_DIR environment variable when creating a sandbox:
from daytona import Daytona, CreateSandboxFromSnapshotParams
daytona = Daytona()sandbox = daytona.create( CreateSandboxFromSnapshotParams( snapshot="daytonaio/sandbox:0.6.0", name="my-sandbox", env_vars={"DAYTONA_RECORDINGS_DIR": "/home/daytona/my-recordings"} ))import { Daytona } from '@daytona/sdk';
const daytona = new Daytona();const sandbox = await daytona.create({ snapshot: 'daytonaio/sandbox:0.6.0', name: 'my-sandbox', envVars: { DAYTONA_RECORDINGS_DIR: '/home/daytona/my-recordings' }});require 'daytona'
daytona = Daytona::Client.newsandbox = daytona.create( snapshot: 'daytonaio/sandbox:0.6.0', name: 'my-sandbox', env_vars: { DAYTONA_RECORDINGS_DIR: '/home/daytona/my-recordings' })import ( "github.com/daytonaio/daytona/pkg/client" "github.com/daytonaio/daytona/pkg/types")
daytona := client.New()envVars := map[string]string{ "DAYTONA_RECORDINGS_DIR": "/home/daytona/my-recordings",}
sandbox, err := daytona.Create(ctx, &types.CreateSandboxParams{ Snapshot: "daytonaio/sandbox:0.6.0", Name: "my-sandbox", EnvVars: envVars,})if err != nil { log.Fatal(err)}import io.daytona.sdk.Daytona;import io.daytona.sdk.Sandbox;import io.daytona.sdk.model.CreateSandboxFromSnapshotParams;
import java.util.Map;
try (Daytona daytona = new Daytona()) { CreateSandboxFromSnapshotParams params = new CreateSandboxFromSnapshotParams(); params.setSnapshot("daytonaio/sandbox:0.6.0"); params.setName("my-sandbox"); params.setEnvVars(Map.of("DAYTONA_RECORDINGS_DIR", "/home/daytona/my-recordings")); Sandbox sandbox = daytona.create(params);}Start Recording
Section titled “Start Recording”Start a new screen recording session with an optional name identifier:
# Start recording with a custom namerecording = sandbox.computer_use.recording.start("test-1")print(f"Recording started: {recording.id}")print(f"File path: {recording.file_path}")// Start recording with a custom nameconst recording = await sandbox.computerUse.recording.start('test-1');console.log(`Recording started: ${recording.id}`);console.log(`File path: ${recording.file_path}`);# Start recording with a custom labelrecording = sandbox.computer_use.recording.start(label: 'test-1')puts "Recording started: #{recording.id}"puts "File path: #{recording.file_path}"// Start recording with a custom namename := "test-1"recording, err := sandbox.ComputerUse.Recording().Start(ctx, &name)if err != nil { log.Fatal(err)}
fmt.Printf("Recording started: %s\n", *recording.Id)fmt.Printf("File path: %s\n", *recording.FilePath)// Start recording with a custom labelvar recording = sandbox.computerUse.startRecording("test-1");System.out.println("Recording started: " + recording.getId());System.out.println("File path: " + recording.getFilePath());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/start' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "name": "test-1"}'Stop Recording
Section titled “Stop Recording”Stop an active recording session by providing the recording ID:
# Stop the recordingstopped_recording = sandbox.computer_use.recording.stop(recording.id)print(f"Recording stopped: {stopped_recording.duration_seconds} seconds")print(f"Saved to: {stopped_recording.file_path}")// Stop the recordingconst stoppedRecording = await sandbox.computerUse.recording.stop(recording.id);console.log(`Recording stopped: ${stoppedRecording.duration_seconds} seconds`);console.log(`Saved to: ${stoppedRecording.file_path}`);# Stop the recordingstopped_recording = sandbox.computer_use.recording.stop(id: recording.id)puts "Recording stopped: #{stopped_recording.duration_seconds} seconds"puts "Saved to: #{stopped_recording.file_path}"// Stop the recordingstoppedRecording, err := sandbox.ComputerUse.Recording().Stop(ctx, *recording.Id)if err != nil { log.Fatal(err)}
fmt.Printf("Recording stopped: %f seconds\n", *stoppedRecording.DurationSeconds)fmt.Printf("Saved to: %s\n", *stoppedRecording.FilePath)// Stop the recordingvar stoppedRecording = sandbox.computerUse.stopRecording(recording.getId());System.out.println("Recording stopped: " + stoppedRecording.getDurationSeconds() + " seconds");System.out.println("Saved to: " + stoppedRecording.getFilePath());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/stop' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "id": "recording-id"}'List Recordings
Section titled “List Recordings”Get a list of all recordings in the sandbox:
recordings_list = sandbox.computer_use.recording.list()print(f"Total recordings: {len(recordings_list.recordings)}")for rec in recordings_list.recordings: print(f"- {rec.name}: {rec.duration_seconds}s ({rec.file_size_bytes} bytes)")const recordingsList = await sandbox.computerUse.recording.list();console.log(`Total recordings: ${recordingsList.recordings.length}`);recordingsList.recordings.forEach(rec => { console.log(`- ${rec.name}: ${rec.duration_seconds}s (${rec.file_size_bytes} bytes)`);});recordings_list = sandbox.computer_use.recording.listputs "Total recordings: #{recordings_list.recordings.length}"recordings_list.recordings.each do |rec| puts "- #{rec.name}: #{rec.duration_seconds}s (#{rec.file_size_bytes} bytes)"endrecordingsList, err := sandbox.ComputerUse.Recording().List(ctx)if err != nil { log.Fatal(err)}
fmt.Printf("Total recordings: %d\n", len(recordingsList.Recordings))for _, rec := range recordingsList.Recordings { fmt.Printf("- %s: %.2fs (%d bytes)\n", *rec.Name, *rec.DurationSeconds, *rec.FileSizeBytes)}var recordingsList = sandbox.computerUse.listRecordings();System.out.println("Total recordings: " + recordingsList.getRecordings().size());for (var rec : recordingsList.getRecordings()) { System.out.println( "- " + rec.getFileName() + ": " + rec.getDurationSeconds() + "s (" + rec.getSizeBytes() + " bytes)" );}curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings'Get Recording
Section titled “Get Recording”Get details about a specific recording:
recording_detail = sandbox.computer_use.recording.get("recording-id")print(f"Recording: {recording_detail.name}")print(f"Status: {recording_detail.status}")print(f"Duration: {recording_detail.duration_seconds}s")const recordingDetail = await sandbox.computerUse.recording.get('recording-id');console.log(`Recording: ${recordingDetail.name}`);console.log(`Status: ${recordingDetail.status}`);console.log(`Duration: ${recordingDetail.duration_seconds}s`);recording_detail = sandbox.computer_use.recording.get(id: 'recording-id')puts "Recording: #{recording_detail.name}"puts "Status: #{recording_detail.status}"puts "Duration: #{recording_detail.duration_seconds}s"recordingDetail, err := sandbox.ComputerUse.Recording().Get(ctx, "recording-id")if err != nil { log.Fatal(err)}
fmt.Printf("Recording: %s\n", *recordingDetail.Name)fmt.Printf("Status: %s\n", *recordingDetail.Status)fmt.Printf("Duration: %.2fs\n", *recordingDetail.DurationSeconds)var recordingDetail = sandbox.computerUse.getRecording("recording-id");System.out.println("Recording: " + recordingDetail.getFileName());System.out.println("Status: " + recordingDetail.getStatus());System.out.println("Duration: " + recordingDetail.getDurationSeconds() + "s");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}'Delete Recording
Section titled “Delete Recording”Delete a recording by ID:
sandbox.computer_use.recording.delete("recording-id")print("Recording deleted successfully")await sandbox.computerUse.recording.delete('recording-id');console.log('Recording deleted successfully');sandbox.computer_use.recording.delete(id: 'recording-id')puts 'Recording deleted successfully'err := sandbox.ComputerUse.Recording().Delete(ctx, "recording-id")if err != nil { log.Fatal(err)}
fmt.Println("Recording deleted successfully")sandbox.computerUse.deleteRecording("recording-id");System.out.println("Recording deleted successfully");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}' \ --request DELETEDownload Recording
Section titled “Download Recording”Download a recording file from the sandbox to your local machine. The file is streamed efficiently without loading the entire content into memory, making it suitable for large recordings.
# Download recording to local filesandbox.computer_use.recording.download(recording.id, "local_recording.mp4")print("Recording downloaded successfully")
# Or with custom pathimport osdownload_path = os.path.join("recordings", f"recording_{recording.id}.mp4")sandbox.computer_use.recording.download(recording.id, download_path)// Download recording to local fileawait sandbox.computerUse.recording.download(recording.id, 'local_recording.mp4');console.log('Recording downloaded successfully');
// Or with custom pathconst downloadPath = `recordings/recording_${recording.id}.mp4`;await sandbox.computerUse.recording.download(recording.id, downloadPath);# Download recording to local filesandbox.computer_use.recording.download(id: recording.id, local_path: 'local_recording.mp4')puts 'Recording downloaded successfully'
# Or with custom pathdownload_path = "recordings/recording_#{recording.id}.mp4"sandbox.computer_use.recording.download(id: recording.id, local_path: download_path)// Download recording to local fileerr := sandbox.ComputerUse.Recording().Download(ctx, recording.GetId(), "local_recording.mp4")if err != nil { log.Fatal(err)}fmt.Println("Recording downloaded successfully")
// Or with custom pathdownloadPath := fmt.Sprintf("recordings/recording_%s.mp4", recording.GetId())err = sandbox.ComputerUse.Recording().Download(ctx, recording.GetId(), downloadPath)import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.StandardCopyOption;
// Download returns a temp file from the API client; copy it to a stable pathvar tempFile = sandbox.computerUse.downloadRecording(recording.getId());Files.copy(tempFile.toPath(), Path.of("local_recording.mp4"), StandardCopyOption.REPLACE_EXISTING);System.out.println("Recording saved to local_recording.mp4");
var downloadPath = Path.of("recordings", "recording_" + recording.getId() + ".mp4");Files.createDirectories(downloadPath.getParent());Files.copy(tempFile.toPath(), downloadPath, StandardCopyOption.REPLACE_EXISTING);curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}/download' \ --output local_recording.mp4Recording Dashboard
Section titled “Recording Dashboard”Every sandbox includes a built-in recording dashboard for managing screen recordings through a web interface. The dashboard allows you to view, download, and delete recordings without writing code.
To access the recording dashboard:
- Navigate to your sandboxes in the Daytona Dashboard
- Click the action menu (three dots) for your sandbox
- Select Screen Recordings from the dropdown menu
The recording dashboard provides:
- List of all recordings with metadata (name, duration, file size, creation time)
- Playback controls for reviewing recordings
- Download functionality to save recordings locally
- Delete options for managing storage
Display operations
Section titled “Display operations”Get info
Section titled “Get info”Get information about the displays.
info = sandbox.computer_use.display.get_info()print(f"Primary display: {info.primary_display.width}x{info.primary_display.height}")print(f"Total displays: {info.total_displays}")for i, display in enumerate(info.displays): print(f"Display {i}: {display.width}x{display.height} at {display.x},{display.y}")const info = await sandbox.computerUse.display.getInfo();console.log(`Primary display: ${info.primary_display.width}x${info.primary_display.height}`);console.log(`Total displays: ${info.total_displays}`);info.displays.forEach((display, index) => { console.log(`Display ${index}: ${display.width}x${display.height} at ${display.x},${display.y}`);});info = sandbox.computer_use.display.infoputs "Primary display: #{info.primary_display.width}x#{info.primary_display.height}"puts "Total displays: #{info.total_displays}"info.displays.each_with_index do |display, i| puts "Display #{i}: #{display.width}x#{display.height} at #{display.x},#{display.y}"endinfo, err := sandbox.ComputerUse.Display().GetInfo(ctx)if err != nil { log.Fatal(err)}
fmt.Printf("Displays: %v\n", info["displays"])var info = sandbox.computerUse.getDisplayInfo();if (info.getDisplays() != null) { for (var display : info.getDisplays()) { System.out.println( "Display " + display.getId() + ": " + display.getWidth() + "x" + display.getHeight() + " at " + display.getX() + "," + display.getY() ); }}curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/info'Get windows
Section titled “Get windows”Get the list of open windows.
windows = sandbox.computer_use.display.get_windows()print(f"Found {windows.count} open windows:")for window in windows.windows: print(f"- {window.title} (ID: {window.id})")const windows = await sandbox.computerUse.display.getWindows();console.log(`Found ${windows.count} open windows:`);windows.windows.forEach(window => { console.log(`- ${window.title} (ID: ${window.id})`);});windows = sandbox.computer_use.display.windowsputs "Found #{windows.count} open windows:"windows.windows.each do |window| puts "- #{window.title} (ID: #{window.id})"endresult, err := sandbox.ComputerUse.Display().GetWindows(ctx)if err != nil { log.Fatal(err)}
fmt.Printf("Open windows: %v\n", result["windows"])var windows = sandbox.computerUse.getWindows();var list = windows.getWindows();if (list != null) { System.out.println("Found " + list.size() + " open windows:"); for (var window : list) { System.out.println("- " + window.getTitle() + " (ID: " + window.getId() + ")"); }}curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/windows'