Back to Daytona

Computer Use

apps/docs/src/content/docs/en/computer-use.mdx

0.188.060.6 KB
Original Source

import { TabItem, Tabs } from '@astrojs/starlight/components'

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.

:::caution[Private Alpha] Computer Use for macOS and Windows is currently in private alpha and requires access. To request access, fill out the Windows or macOS access request form. Our team will review your request and reach out with setup instructions. :::

  • 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

Start all computer use processes (Xvfb, xfce4, x11vnc, novnc) in the Sandbox.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
result = sandbox.computer_use.start()
print("Computer use processes started:", result.message)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const result = await sandbox.computerUse.start();
console.log('Computer use processes started:', result.message);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
result = sandbox.computer_use.start
puts "Computer use processes started: #{result.message}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
err := sandbox.ComputerUse.Start(ctx)
if err != nil {
	log.Fatal(err)
}
defer sandbox.ComputerUse.Stop(ctx)

fmt.Println("Computer use processes started")
</TabItem> <TabItem label="Java" icon="seti:java">
java
var result = sandbox.computerUse.start();
System.out.println("Computer use processes started: " + result.getMessage());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/start' \
  --request POST
</TabItem> </Tabs>

Stop Computer Use

Stop all computer use processes in the Sandbox.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
result = sandbox.computer_use.stop()
print("Computer use processes stopped:", result.message)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const result = await sandbox.computerUse.stop();
console.log('Computer use processes stopped:', result.message);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
result = sandbox.computer_use.stop
puts "Computer use processes stopped: #{result.message}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
err := sandbox.ComputerUse.Stop(ctx)
if err != nil {
	log.Fatal(err)
}

fmt.Println("Computer use processes stopped")
</TabItem> <TabItem label="Java" icon="seti:java">
java
var result = sandbox.computerUse.stop();
System.out.println("Computer use processes stopped: " + result.getMessage());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/stop' \
  --request POST
</TabItem> </Tabs>

Get status

Get the status of all computer use processes.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
response = sandbox.computer_use.get_status()
print("Computer use status:", response.status)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const status = await sandbox.computerUse.getStatus();
console.log('Computer use status:', status.status);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
response = sandbox.computer_use.status
puts "Computer use status: #{response.status}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
status, err := sandbox.ComputerUse.GetStatus(ctx)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Computer use status: %v\n", status["status"])
</TabItem> <TabItem label="Java" icon="seti:java">
java
var response = sandbox.computerUse.getStatus();
System.out.println("Computer use status: " + response.getStatus());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/status'
</TabItem> </Tabs>

Get process status

Get the status of a specific VNC process.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
xvfb_status = sandbox.computer_use.get_process_status("xvfb")
novnc_status = sandbox.computer_use.get_process_status("novnc")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const xvfbStatus = await sandbox.computerUse.getProcessStatus('xvfb');
const noVncStatus = await sandbox.computerUse.getProcessStatus('novnc');
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
xvfb_status = sandbox.computer_use.get_process_status("xvfb")
no_vnc_status = sandbox.computer_use.get_process_status("novnc")
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/status'
</TabItem> </Tabs>

Restart process

Restart a specific VNC process.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
result = sandbox.computer_use.restart_process("xfce4")
print("XFCE4 process restarted:", result.message)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const result = await sandbox.computerUse.restartProcess('xfce4');
console.log('XFCE4 process restarted:', result.message);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
result = sandbox.computer_use.restart_process("xfce4")
puts "XFCE4 process restarted: #{result.message}"
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/restart' \
  --request POST
</TabItem> </Tabs>

Get process logs

Get logs for a specific VNC process.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
logs = sandbox.computer_use.get_process_logs("novnc")
print("NoVNC logs:", logs)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const logsResp = await sandbox.computerUse.getProcessLogs('novnc');
console.log('NoVNC logs:', logsResp.logs);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
logs = sandbox.computer_use.get_process_logs("novnc")
puts "NoVNC logs: #{logs}"
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/logs'
</TabItem> </Tabs>

Get process errors

Get error logs for a specific VNC process.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
errors = sandbox.computer_use.get_process_errors("x11vnc")
print("X11VNC errors:", errors)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const errorsResp = await sandbox.computerUse.getProcessErrors('x11vnc');
console.log('X11VNC errors:', errorsResp.errors);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
errors = sandbox.computer_use.get_process_errors("x11vnc")
puts "X11VNC errors: #{errors}"
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/errors'
</TabItem> </Tabs>

Mouse operations

Click

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.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Single left click
result = sandbox.computer_use.mouse.click(100, 200)

# Double click
double_click = sandbox.computer_use.mouse.click(100, 200, "left", True)

# Right click
right_click = sandbox.computer_use.mouse.click(100, 200, "right")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Single left click
const result = await sandbox.computerUse.mouse.click(100, 200);

// Double click
const doubleClick = await sandbox.computerUse.mouse.click(100, 200, 'left', true);

// Right click
const rightClick = await sandbox.computerUse.mouse.click(100, 200, 'right');
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Single left click
result = sandbox.computer_use.mouse.click(x: 100, y: 200)

# Double click
double_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'left', double: true)

# Right click
right_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'right')
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Single left click
result, err := sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, nil, nil)
if err != nil {
	log.Fatal(err)
}

// Double click
doubleClick := true
result, err = sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, nil, &doubleClick)

// Right click
rightButton := "right"
result, err = sandbox.ComputerUse.Mouse().Click(ctx, 100, 200, &rightButton, nil)
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Single left click
sandbox.computerUse.click(100, 200);

// Double click
sandbox.computerUse.doubleClick(100, 200);

// Right click
sandbox.computerUse.click(100, 200, "right");
</TabItem> <TabItem label="API" icon="seti:json">
bash
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
}'
</TabItem> </Tabs>

Move

Move the mouse cursor to the specified coordinates.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
result = sandbox.computer_use.mouse.move(100, 200)
print(f"Mouse moved to: {result.x}, {result.y}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const result = await sandbox.computerUse.mouse.move(100, 200);
console.log(`Mouse moved to: ${result.x}, ${result.y}`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
result = sandbox.computer_use.mouse.move(x: 100, y: 200)
puts "Mouse moved to: #{result.x}, #{result.y}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
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"])
</TabItem> <TabItem label="Java" icon="seti:java">
java
var result = sandbox.computerUse.moveMouse(100, 200);
System.out.println("Mouse moved to: " + result.getX() + ", " + result.getY());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/move' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "x": 1,
  "y": 1
}'
</TabItem> </Tabs>

Drag

Drag the mouse from start coordinates to end coordinates.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
result = sandbox.computer_use.mouse.drag(50, 50, 150, 150)
print(f"Drag ended at {result.x}, {result.y}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const result = await sandbox.computerUse.mouse.drag(50, 50, 150, 150);
console.log(`Drag ended at ${result.x}, ${result.y}`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
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}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
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"])
</TabItem> <TabItem label="Java" icon="seti:java">
java
var result = sandbox.computerUse.drag(50, 50, 150, 150);
System.out.println("Drag ended at: " + result.getX() + ", " + result.getY());
</TabItem> <TabItem label="API" icon="seti:json">
bash
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
}'
</TabItem> </Tabs>

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.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Scroll up
scroll_up = sandbox.computer_use.mouse.scroll(100, 200, "up", 3)

# Scroll down
scroll_down = sandbox.computer_use.mouse.scroll(100, 200, "down", 5)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Scroll up
const scrollUp = await sandbox.computerUse.mouse.scroll(100, 200, 'up', 3);

// Scroll down
const scrollDown = await sandbox.computerUse.mouse.scroll(100, 200, 'down', 5);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Scroll up
scroll_up = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'up', amount: 3)

# Scroll down
scroll_down = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'down', amount: 5)
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Scroll up
amount := 3
success, err := sandbox.ComputerUse.Mouse().Scroll(ctx, 100, 200, "up", &amount)
if err != nil {
	log.Fatal(err)
}

// Scroll down
amount = 5
success, err = sandbox.ComputerUse.Mouse().Scroll(ctx, 100, 200, "down", &amount)
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Scroll up (negative vertical delta maps to "up")
sandbox.computerUse.scroll(100, 200, 0, -3);

// Scroll down
sandbox.computerUse.scroll(100, 200, 0, 5);
</TabItem> <TabItem label="API" icon="seti:json">
bash
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
}'
</TabItem> </Tabs>

Get position

Get the current mouse cursor position.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
position = sandbox.computer_use.mouse.get_position()
print(f"Mouse is at: {position.x}, {position.y}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const position = await sandbox.computerUse.mouse.getPosition();
console.log(`Mouse is at: ${position.x}, ${position.y}`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
position = sandbox.computer_use.mouse.position
puts "Mouse is at: #{position.x}, #{position.y}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
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"])
</TabItem> <TabItem label="Java" icon="seti:java">
java
var position = sandbox.computerUse.getMousePosition();
System.out.println("Mouse is at: " + position.getX() + ", " + position.getY());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/position'
</TabItem> </Tabs>

Keyboard operations

Type

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.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
sandbox.computer_use.keyboard.type("Hello, World!")

# With delay between characters
sandbox.computer_use.keyboard.type("Slow typing", 100)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
await sandbox.computerUse.keyboard.type('Hello, World!');

// With delay between characters
await sandbox.computerUse.keyboard.type('Slow typing', 100);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
sandbox.computer_use.keyboard.type(text: "Hello, World!")

# With delay between characters
sandbox.computer_use.keyboard.type(text: "Slow typing", delay: 100)
</TabItem> <TabItem label="Go" icon="seti:go">
go
err := sandbox.ComputerUse.Keyboard().Type(ctx, "Hello, World!", nil)
if err != nil {
	log.Fatal(err)
}

// With delay between characters
delay := 100
err = sandbox.ComputerUse.Keyboard().Type(ctx, "Slow typing", &delay)
</TabItem> <TabItem label="Java" icon="seti:java">
java
sandbox.computerUse.typeText("Hello, World!");
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/type' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "delay": 1,
  "text": ""
}'
</TabItem> </Tabs>

Press

Press a key with optional modifiers.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Press Enter
sandbox.computer_use.keyboard.press("enter")

# Press Ctrl+C
sandbox.computer_use.keyboard.press("c", ["ctrl"])

# Press Ctrl+Shift+T
sandbox.computer_use.keyboard.press("t", ["ctrl", "shift"])
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Press Enter
await sandbox.computerUse.keyboard.press('enter');

// Press Ctrl+C
await sandbox.computerUse.keyboard.press('c', ['ctrl']);

// Press Ctrl+Shift+T
await sandbox.computerUse.keyboard.press('t', ['ctrl', 'shift']);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Press Enter
sandbox.computer_use.keyboard.press(key: "enter")

# Press Ctrl+C
sandbox.computer_use.keyboard.press(key: "c", modifiers: ["ctrl"])

# Press Ctrl+Shift+T
sandbox.computer_use.keyboard.press(key: "t", modifiers: ["ctrl", "shift"])
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Press Enter
err := sandbox.ComputerUse.Keyboard().Press(ctx, "enter", nil)
if err != nil {
	log.Fatal(err)
}

// Press Ctrl+C
err = sandbox.ComputerUse.Keyboard().Press(ctx, "c", []string{"ctrl"})

// Press Ctrl+Shift+T
err = sandbox.ComputerUse.Keyboard().Press(ctx, "t", []string{"ctrl", "shift"})
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Press Enter
sandbox.computerUse.pressKey("enter");

// Press Ctrl+C
sandbox.computerUse.pressHotkey("ctrl", "c");

// Press Ctrl+Shift+T
sandbox.computerUse.pressHotkey("ctrl", "shift", "t");
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/key' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "key": "enter",
  "modifiers": []
}'
</TabItem> </Tabs>

Hotkey

Press a hotkey combination.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Copy
sandbox.computer_use.keyboard.hotkey("ctrl+c")

# Paste
sandbox.computer_use.keyboard.hotkey("ctrl+v")

# Alt+Tab
sandbox.computer_use.keyboard.hotkey("alt+tab")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript"> ```typescript // Copy await sandbox.computerUse.keyboard.hotkey('ctrl+c');

// Paste await sandbox.computerUse.keyboard.hotkey('ctrl+v');

// Alt+Tab await sandbox.computerUse.keyboard.hotkey('alt+tab');


</TabItem>
<TabItem label="Ruby" icon="seti:ruby">

```ruby
# Copy
sandbox.computer_use.keyboard.hotkey(keys: "ctrl+c")

# Paste
sandbox.computer_use.keyboard.hotkey(keys: "ctrl+v")

# Alt+Tab
sandbox.computer_use.keyboard.hotkey(keys: "alt+tab")
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Copy
err := sandbox.ComputerUse.Keyboard().Hotkey(ctx, "ctrl+c")
if err != nil {
	log.Fatal(err)
}

// Paste
err = sandbox.ComputerUse.Keyboard().Hotkey(ctx, "ctrl+v")

// Alt+Tab
err = sandbox.ComputerUse.Keyboard().Hotkey(ctx, "alt+tab")
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Copy
sandbox.computerUse.pressHotkey("ctrl", "c");

// Paste
sandbox.computerUse.pressHotkey("ctrl", "v");

// Alt+Tab
sandbox.computerUse.pressHotkey("alt", "tab");
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/hotkey' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "keys": "ctrl+c"
}'
</TabItem> </Tabs>

Supported keys

keyboard.press() and keyboard.hotkey() are case-insensitive for named keys. The following are supported:

CategoryKeys
Modifiersctrl, alt, shift, cmd
Editingenter, escape, tab, backspace, delete, space
Navigationhome, end, pageup, pagedown, insert, arrow keys (up, down, left, right)
Function keysf1 through f24
Numpadnum0num9, num_plus, num_minus, num_asterisk, num_slash, num_decimal, num_enter, num_equal, num_lock
Letters and digitsaz (case-insensitive), 09
Punctuation` - = [ ] \ ; ' , . /
Othercapslock, menu

Common aliases like Returnenter, controlctrl, command / meta / wincmd, and optionalt are normalized automatically. Unsupported or malformed inputs return an error, sometimes with a suggested alternative.

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.

:::note[App accessibility support] Accessibility operations read the semantic UI information that applications expose over AT-SPI. Apps or custom widgets that do not expose accessibility objects may return sparse nodes, generic roles, or no actionable nodes; mouse, keyboard, and screenshot operations remain available for those cases. :::

Get tree

Read an accessibility tree for the focused app, a specific process, or all apps.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Focused app
focused_tree = sandbox.computer_use.accessibility.get_tree(scope="focused", max_depth=2)

# Specific process
process_tree = sandbox.computer_use.accessibility.get_tree(
    scope="pid",
    pid=1234,
    max_depth=2,
)

# All apps
desktop_tree = sandbox.computer_use.accessibility.get_tree(scope="all", max_depth=2)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Focused app
const focusedTree = await sandbox.computerUse.accessibility.getTree({
  scope: 'focused',
  maxDepth: 2,
});

// Specific process
const processTree = await sandbox.computerUse.accessibility.getTree({
  scope: 'pid',
  pid: 1234,
  maxDepth: 2,
});

// All apps
const desktopTree = await sandbox.computerUse.accessibility.getTree({
  scope: 'all',
  maxDepth: 2,
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Focused app
focused_tree = sandbox.computer_use.accessibility.get_tree(scope: "focused", max_depth: 2)

# Specific process
process_tree = sandbox.computer_use.accessibility.get_tree(
  scope: "pid",
  pid: 1234,
  max_depth: 2
)

# All apps
desktop_tree = sandbox.computer_use.accessibility.get_tree(scope: "all", max_depth: 2)
</TabItem> <TabItem label="Go" icon="seti:go">
go
maxDepth := 2

// Focused app
focusedScope := "focused"
focusedTree, err := sandbox.ComputerUse.Accessibility().GetTree(ctx, &daytona.AccessibilityTreeOptions{
	Scope:    &focusedScope,
	MaxDepth: &maxDepth,
})
if err != nil {
	log.Fatal(err)
}

// Specific process
processScope := "pid"
pid := 1234
processTree, err := sandbox.ComputerUse.Accessibility().GetTree(ctx, &daytona.AccessibilityTreeOptions{
	Scope:    &processScope,
	PID:      &pid,
	MaxDepth: &maxDepth,
})
if err != nil {
	log.Fatal(err)
}

// All apps
allScope := "all"
desktopTree, err := sandbox.ComputerUse.Accessibility().GetTree(ctx, &daytona.AccessibilityTreeOptions{
	Scope:    &allScope,
	MaxDepth: &maxDepth,
})
if err != nil {
	log.Fatal(err)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Focused app
var focusedTree = sandbox.computerUse.getAccessibilityTree("focused", null, 2);

// Specific process
var processTree = sandbox.computerUse.getAccessibilityTree("pid", 1234, 2);

// All apps
var desktopTree = sandbox.computerUse.getAccessibilityTree("all", null, 2);
</TabItem> <TabItem label="API" icon="seti:json">
bash
# Focused app
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/tree?scope=focused&maxDepth=2'

# Specific process
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/tree?scope=pid&pid=1234&maxDepth=2'

# All apps
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/tree?scope=all&maxDepth=2'
</TabItem> </Tabs>

Find nodes

Search the accessibility tree by role, accessible name, state, and scope.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Find buttons by accessible name
buttons = sandbox.computer_use.accessibility.find_nodes(
    scope="focused",
    role="button",
    name="Submit",
    name_match="substring",
    limit=10,
)

# Find text entries in a process
entries = sandbox.computer_use.accessibility.find_nodes(
    scope="pid",
    pid=1234,
    role="entry",
    states=["enabled", "focusable"],
    limit=10,
)

# Find visible nodes across all apps
visible_nodes = sandbox.computer_use.accessibility.find_nodes(
    scope="all",
    states=["visible"],
    limit=20,
)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Find buttons by accessible name
const buttons = await sandbox.computerUse.accessibility.findNodes({
  scope: 'focused',
  role: 'button',
  name: 'Submit',
  nameMatch: 'substring',
  limit: 10,
});

// Find text entries in a process
const entries = await sandbox.computerUse.accessibility.findNodes({
  scope: 'pid',
  pid: 1234,
  role: 'entry',
  states: ['enabled', 'focusable'],
  limit: 10,
});

// Find visible nodes across all apps
const visibleNodes = await sandbox.computerUse.accessibility.findNodes({
  scope: 'all',
  states: ['visible'],
  limit: 20,
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Find buttons by accessible name
buttons = sandbox.computer_use.accessibility.find_nodes(
  scope: "focused",
  role: "button",
  name: "Submit",
  name_match: "substring",
  limit: 10
)

# Find text entries in a process
entries = sandbox.computer_use.accessibility.find_nodes(
  scope: "pid",
  pid: 1234,
  role: "entry",
  states: ["enabled", "focusable"],
  limit: 10
)

# Find visible nodes across all apps
visible_nodes = sandbox.computer_use.accessibility.find_nodes(
  scope: "all",
  states: ["visible"],
  limit: 20
)
</TabItem> <TabItem label="Go" icon="seti:go">
go
limit := 10

// Find buttons by accessible name
focusedScope := "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 process
processScope := "pid"
pid := 1234
entryRole := "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 apps
allScope := "all"
visibleLimit := 20
visibleNodes, err := sandbox.ComputerUse.Accessibility().FindNodes(ctx, &daytona.AccessibilityFindOptions{
	Scope:  &allScope,
	States: []string{"visible"},
	Limit:  &visibleLimit,
})
if err != nil {
	log.Fatal(err)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Find buttons by accessible name
var buttons = sandbox.computerUse.findAccessibilityNodes(
    new FindAccessibilityNodesRequest()
        .scope("focused")
        .role("button")
        .name("Submit")
        .nameMatch("substring")
        .limit(10)
);

// Find text entries in a process
var 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 apps
var visibleNodes = sandbox.computerUse.findAccessibilityNodes(
    new FindAccessibilityNodesRequest()
        .scope("all")
        .states(java.util.List.of("visible"))
        .limit(20)
);
</TabItem> <TabItem label="API" icon="seti:json">
bash
# Find buttons by accessible name
curl '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 process
curl '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 apps
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/find' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "scope": "all",
  "states": ["visible"],
  "limit": 20
}'
</TabItem> </Tabs>

Focus node

Move keyboard focus to a node returned by get_tree or find_nodes.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
sandbox.computer_use.accessibility.focus_node("node-id")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
await sandbox.computerUse.accessibility.focusNode('node-id');
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
sandbox.computer_use.accessibility.focus_node(id: "node-id")
</TabItem> <TabItem label="Go" icon="seti:go">
go
if err := sandbox.ComputerUse.Accessibility().FocusNode(ctx, "node-id"); err != nil {
	log.Fatal(err)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
sandbox.computerUse.focusAccessibilityNode("node-id");
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/node/focus' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{"id":"node-id"}'
</TabItem> </Tabs>

Invoke node

Run a node action, such as pressing a button.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Invoke the primary action
sandbox.computer_use.accessibility.invoke_node("node-id")

# Invoke a named action
sandbox.computer_use.accessibility.invoke_node("node-id", action="click")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Invoke the primary action
await sandbox.computerUse.accessibility.invokeNode('node-id');

// Invoke a named action
await sandbox.computerUse.accessibility.invokeNode('node-id', 'click');
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Invoke the primary action
sandbox.computer_use.accessibility.invoke_node(id: "node-id")

# Invoke a named action
sandbox.computer_use.accessibility.invoke_node(id: "node-id", action: "click")
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Invoke the primary action
if err := sandbox.ComputerUse.Accessibility().InvokeNode(ctx, "node-id", nil); err != nil {
	log.Fatal(err)
}

// Invoke a named action
action := "click"
if err := sandbox.ComputerUse.Accessibility().InvokeNode(ctx, "node-id", &action); err != nil {
	log.Fatal(err)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Invoke the primary action
sandbox.computerUse.invokeAccessibilityNode("node-id");

// Invoke a named action
sandbox.computerUse.invokeAccessibilityNode("node-id", "click");
</TabItem> <TabItem label="API" icon="seti:json">
bash
# Invoke the primary action
curl '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 action
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/a11y/node/invoke' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{"id":"node-id","action":"click"}'
</TabItem> </Tabs>

Set node value

Write text or value content to nodes that support value changes.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
sandbox.computer_use.accessibility.set_node_value("node-id", "hello")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
await sandbox.computerUse.accessibility.setNodeValue('node-id', 'hello');
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
sandbox.computer_use.accessibility.set_node_value(id: "node-id", value: "hello")
</TabItem> <TabItem label="Go" icon="seti:go">
go
if err := sandbox.ComputerUse.Accessibility().SetNodeValue(ctx, "node-id", "hello"); err != nil {
	log.Fatal(err)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
sandbox.computerUse.setAccessibilityNodeValue("node-id", "hello");
</TabItem> <TabItem label="API" icon="seti:json">
bash
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"}'
</TabItem> </Tabs>

Screenshot operations

Take full screen

Take a screenshot of the entire screen.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
screenshot = sandbox.computer_use.screenshot.take_full_screen()
print(f"Screenshot size: {screenshot.width}x{screenshot.height}")

# With cursor visible
with_cursor = sandbox.computer_use.screenshot.take_full_screen(True)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
const screenshot = await sandbox.computerUse.screenshot.takeFullScreen();
console.log(`Screenshot size: ${screenshot.width}x${screenshot.height}`);

// With cursor visible
const withCursor = await sandbox.computerUse.screenshot.takeFullScreen(true);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
screenshot = sandbox.computer_use.screenshot.take_full_screen
puts "Screenshot size: #{screenshot.width}x#{screenshot.height}"

# With cursor visible
with_cursor = sandbox.computer_use.screenshot.take_full_screen(show_cursor: true)
</TabItem> <TabItem label="Go" icon="seti:go">
go
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 visible
showCursor := true
withCursor, err := sandbox.ComputerUse.Screenshot().TakeFullScreen(ctx, &showCursor)
</TabItem> <TabItem label="Java" icon="seti:java">
java
var screenshot = sandbox.computerUse.takeScreenshot();
Integer sizeBytes = screenshot.getSizeBytes();
System.out.println("Screenshot payload size: " + (sizeBytes != null ? sizeBytes + " bytes" : "n/a"));

// With cursor visible
var withCursor = sandbox.computerUse.takeScreenshot(true);
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot'
</TabItem> </Tabs>

Take region

Take a screenshot of a specific region.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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}`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
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}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
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)
</TabItem> <TabItem label="Java" icon="seti:java">
java
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"));
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region?x=1&y=1&width=1&height=1'
</TabItem> </Tabs>

Take compressed

Take a compressed screenshot of the entire screen.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
from daytona import ScreenshotOptions

# Default compression
screenshot = sandbox.computer_use.screenshot.take_compressed()

# High quality JPEG
jpeg = sandbox.computer_use.screenshot.take_compressed(
    ScreenshotOptions(format="jpeg", quality=95, show_cursor=True)
)

# Scaled down PNG
scaled = sandbox.computer_use.screenshot.take_compressed(
    ScreenshotOptions(format="png", scale=0.5)
)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Default compression
const screenshot = await sandbox.computerUse.screenshot.takeCompressed();

// High quality JPEG
const jpeg = await sandbox.computerUse.screenshot.takeCompressed({
  format: 'jpeg',
  quality: 95,
  showCursor: true
});

// Scaled down PNG
const scaled = await sandbox.computerUse.screenshot.takeCompressed({
  format: 'png',
  scale: 0.5
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Default compression
screenshot = sandbox.computer_use.screenshot.take_compressed

# High quality JPEG
jpeg = sandbox.computer_use.screenshot.take_compressed(
  options: Daytona::ComputerUse::ScreenshotOptions.new(format: "jpeg", quality: 95, show_cursor: true)
)

# Scaled down PNG
scaled = sandbox.computer_use.screenshot.take_compressed(
  options: Daytona::ComputerUse::ScreenshotOptions.new(format: "png", scale: 0.5)
)
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Compressed full screen (format, quality 1-100, scale factor)
var screenshot = sandbox.computerUse.takeCompressedScreenshot("png", 80, 1.0);

// High quality JPEG at full scale
var jpeg = sandbox.computerUse.takeCompressedScreenshot("jpeg", 95, 1.0);

// Scaled down PNG
var scaled = sandbox.computerUse.takeCompressedScreenshot("png", 80, 0.5);
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/compressed'
</TabItem> </Tabs>

Take compressed region

Take a compressed screenshot of a specific region.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
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"
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region/compressed?x=1&y=1&width=1&height=1'
</TabItem> </Tabs>

Screen Recording

Computer Use supports screen recording capabilities, allowing you to capture desktop sessions for debugging, documentation, or automation workflows.

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:

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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"}
    )
)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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' }
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
require 'daytona'

daytona = Daytona::Client.new
sandbox = daytona.create(
  snapshot: 'daytonaio/sandbox:0.6.0',
  name: 'my-sandbox',
  env_vars: { DAYTONA_RECORDINGS_DIR: '/home/daytona/my-recordings' }
)
</TabItem> <TabItem label="Go" icon="seti:go">
go
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)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
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);
}
</TabItem> </Tabs>

Start Recording

Start a new screen recording session with an optional name identifier:

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Start recording with a custom name
recording = sandbox.computer_use.recording.start("test-1")
print(f"Recording started: {recording.id}")
print(f"File path: {recording.file_path}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Start recording with a custom name
const recording = await sandbox.computerUse.recording.start('test-1');
console.log(`Recording started: ${recording.id}`);
console.log(`File path: ${recording.file_path}`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Start recording with a custom label
recording = sandbox.computer_use.recording.start(label: 'test-1')
puts "Recording started: #{recording.id}"
puts "File path: #{recording.file_path}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Start recording with a custom name
name := "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)
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Start recording with a custom label
var recording = sandbox.computerUse.startRecording("test-1");
System.out.println("Recording started: " + recording.getId());
System.out.println("File path: " + recording.getFilePath());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/start' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "test-1"
}'
</TabItem> </Tabs>

Stop Recording

Stop an active recording session by providing the recording ID:

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Stop the recording
stopped_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}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Stop the recording
const stoppedRecording = await sandbox.computerUse.recording.stop(recording.id);
console.log(`Recording stopped: ${stoppedRecording.duration_seconds} seconds`);
console.log(`Saved to: ${stoppedRecording.file_path}`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Stop the recording
stopped_recording = sandbox.computer_use.recording.stop(id: recording.id)
puts "Recording stopped: #{stopped_recording.duration_seconds} seconds"
puts "Saved to: #{stopped_recording.file_path}"
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Stop the recording
stoppedRecording, 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)
</TabItem> <TabItem label="Java" icon="seti:java">
java
// Stop the recording
var stoppedRecording = sandbox.computerUse.stopRecording(recording.getId());
System.out.println("Recording stopped: " + stoppedRecording.getDurationSeconds() + " seconds");
System.out.println("Saved to: " + stoppedRecording.getFilePath());
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/stop' \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "id": "recording-id"
}'
</TabItem> </Tabs>

List Recordings

Get a list of all recordings in the sandbox:

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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)")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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)`);
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
recordings_list = sandbox.computer_use.recording.list
puts "Total recordings: #{recordings_list.recordings.length}"
recordings_list.recordings.each do |rec|
  puts "- #{rec.name}: #{rec.duration_seconds}s (#{rec.file_size_bytes} bytes)"
end
</TabItem> <TabItem label="Go" icon="seti:go">
go
recordingsList, 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)
}
</TabItem> <TabItem label="Java" icon="seti:java">
java
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)"
    );
}
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings'
</TabItem> </Tabs>

Get Recording

Get details about a specific recording:

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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`);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
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"
</TabItem> <TabItem label="Go" icon="seti:go">
go
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)
</TabItem> <TabItem label="Java" icon="seti:java">
java
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");
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}'
</TabItem> </Tabs>

Delete Recording

Delete a recording by ID:

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
sandbox.computer_use.recording.delete("recording-id")
print("Recording deleted successfully")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
await sandbox.computerUse.recording.delete('recording-id');
console.log('Recording deleted successfully');
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
sandbox.computer_use.recording.delete(id: 'recording-id')
puts 'Recording deleted successfully'
</TabItem> <TabItem label="Go" icon="seti:go">
go
err := sandbox.ComputerUse.Recording().Delete(ctx, "recording-id")
if err != nil {
	log.Fatal(err)
}

fmt.Println("Recording deleted successfully")
</TabItem> <TabItem label="Java" icon="seti:java">
java
sandbox.computerUse.deleteRecording("recording-id");
System.out.println("Recording deleted successfully");
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}' \
  --request DELETE
</TabItem> </Tabs>

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.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
# Download recording to local file
sandbox.computer_use.recording.download(recording.id, "local_recording.mp4")
print("Recording downloaded successfully")

# Or with custom path
import os
download_path = os.path.join("recordings", f"recording_{recording.id}.mp4")
sandbox.computer_use.recording.download(recording.id, download_path)
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
// Download recording to local file
await sandbox.computerUse.recording.download(recording.id, 'local_recording.mp4');
console.log('Recording downloaded successfully');

// Or with custom path
const downloadPath = `recordings/recording_${recording.id}.mp4`;
await sandbox.computerUse.recording.download(recording.id, downloadPath);
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
# Download recording to local file
sandbox.computer_use.recording.download(id: recording.id, local_path: 'local_recording.mp4')
puts 'Recording downloaded successfully'

# Or with custom path
download_path = "recordings/recording_#{recording.id}.mp4"
sandbox.computer_use.recording.download(id: recording.id, local_path: download_path)
</TabItem> <TabItem label="Go" icon="seti:go">
go
// Download recording to local file
err := sandbox.ComputerUse.Recording().Download(ctx, recording.GetId(), "local_recording.mp4")
if err != nil {
	log.Fatal(err)
}
fmt.Println("Recording downloaded successfully")

// Or with custom path
downloadPath := fmt.Sprintf("recordings/recording_%s.mp4", recording.GetId())
err = sandbox.ComputerUse.Recording().Download(ctx, recording.GetId(), downloadPath)
</TabItem> <TabItem label="Java" icon="seti:java">
java
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 path
var 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);
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}/download' \
  --output local_recording.mp4
</TabItem> </Tabs>

:::tip[Streaming Downloads] All SDK implementations stream the recording file directly to disk without loading the entire content into memory. This allows you to download large recordings (hundreds of MB or even GB) efficiently without running out of memory.

  • Python: Streams in 64KB chunks using httpx
  • TypeScript: Uses Node.js pipeline() with backpressure handling
  • Ruby: Uses Typhoeus streaming with on_body callbacks
  • Go: Uses io.Copy() with 32KB internal buffer
  • Java: The OpenAPI client streams the response body into a temporary file via OkHttp :::

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:

  1. Navigate to your sandboxes in the Daytona Dashboard
  2. Click the action menu (three dots) for your sandbox
  3. 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

:::tip The recording dashboard runs on a private port and is automatically secured. No additional authentication is required once you access it through the Daytona Dashboard. :::

Display operations

Get info

Get information about the displays.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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}")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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}`);
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
info = sandbox.computer_use.display.info
puts "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}"
end
</TabItem> <TabItem label="Go" icon="seti:go">
go
info, err := sandbox.ComputerUse.Display().GetInfo(ctx)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Displays: %v\n", info["displays"])
</TabItem> <TabItem label="Java" icon="seti:java">
java
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()
        );
    }
}
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/info'
</TabItem> </Tabs>

Get windows

Get the list of open windows.

<Tabs syncKey="language"> <TabItem label="Python" icon="seti:python">
python
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})")
</TabItem> <TabItem label="TypeScript" icon="seti:typescript">
typescript
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})`);
});
</TabItem> <TabItem label="Ruby" icon="seti:ruby">
ruby
windows = sandbox.computer_use.display.windows
puts "Found #{windows.count} open windows:"
windows.windows.each do |window|
  puts "- #{window.title} (ID: #{window.id})"
end
</TabItem> <TabItem label="Go" icon="seti:go">
go
result, err := sandbox.ComputerUse.Display().GetWindows(ctx)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Open windows: %v\n", result["windows"])
</TabItem> <TabItem label="Java" icon="seti:java">
java
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() + ")");
    }
}
</TabItem> <TabItem label="API" icon="seti:json">
bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/windows'
</TabItem> </Tabs>