---
title: Computer Use
description: Programmatic control of desktop environments within Daytona sandboxes.
---
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](/docs/en/vnc-access) 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** and **Windows**. **macOS** support is currently in private alpha.
Computer Use for macOS is currently in private alpha and requires access. To request access, fill out the [macOS access request form](https://docs.google.com/forms/d/e/1FAIpQLSc9xlGZ49OjWNkyzDPC9Ip3InMRR0ZXY3tcoD-PFQj3ck6gzQ/viewform?usp=sharing&ouid=103304973264148733944). 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.
```python
result = sandbox.computer_use.start()
print("Computer use processes started:", result.message)
```
```typescript
const result = await sandbox.computerUse.start();
console.log('Computer use processes started:', result.message);
```
```ruby
result = sandbox.computer_use.start
puts "Computer use processes started: #{result.message}"
```
```go
err := sandbox.ComputerUse.Start(ctx)
if err != nil {
log.Fatal(err)
}
defer sandbox.ComputerUse.Stop(ctx)
fmt.Println("Computer use processes started")
```
```java
var result = sandbox.computerUse.start();
System.out.println("Computer use processes started: " + result.getMessage());
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/start' \
--request POST
```
## Stop Computer Use
Stop all computer use processes in the Sandbox.
```python
result = sandbox.computer_use.stop()
print("Computer use processes stopped:", result.message)
```
```typescript
const result = await sandbox.computerUse.stop();
console.log('Computer use processes stopped:', result.message);
```
```ruby
result = sandbox.computer_use.stop
puts "Computer use processes stopped: #{result.message}"
```
```go
err := sandbox.ComputerUse.Stop(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("Computer use processes stopped")
```
```java
var result = sandbox.computerUse.stop();
System.out.println("Computer use processes stopped: " + result.getMessage());
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/stop' \
--request POST
```
## Get status
Get the status of all computer use processes.
```python
response = sandbox.computer_use.get_status()
print("Computer use status:", response.status)
```
```typescript
const status = await sandbox.computerUse.getStatus();
console.log('Computer use status:', status.status);
```
```ruby
response = sandbox.computer_use.status
puts "Computer use status: #{response.status}"
```
```go
status, err := sandbox.ComputerUse.GetStatus(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Computer use status: %v\n", status["status"])
```
```java
var response = sandbox.computerUse.getStatus();
System.out.println("Computer use status: " + response.getStatus());
```
```bash
# Status of the computer use system
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/status'
# Status of all computer use processes
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process-status'
```
## Get process status
Get the status of a specific VNC process.
```python
xvfb_status = sandbox.computer_use.get_process_status("xvfb")
novnc_status = sandbox.computer_use.get_process_status("novnc")
```
```typescript
const xvfbStatus = await sandbox.computerUse.getProcessStatus('xvfb');
const noVncStatus = await sandbox.computerUse.getProcessStatus('novnc');
```
```ruby
xvfb_status = sandbox.computer_use.get_process_status("xvfb")
no_vnc_status = sandbox.computer_use.get_process_status("novnc")
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/status'
```
## Restart process
Restart a specific VNC process.
```python
result = sandbox.computer_use.restart_process("xfce4")
print("XFCE4 process restarted:", result.message)
```
```typescript
const result = await sandbox.computerUse.restartProcess('xfce4');
console.log('XFCE4 process restarted:', result.message);
```
```ruby
result = sandbox.computer_use.restart_process("xfce4")
puts "XFCE4 process restarted: #{result.message}"
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/restart' \
--request POST
```
## Get process logs
Get logs for a specific VNC process.
```python
logs = sandbox.computer_use.get_process_logs("novnc")
print("NoVNC logs:", logs)
```
```typescript
const logsResp = await sandbox.computerUse.getProcessLogs('novnc');
console.log('NoVNC logs:', logsResp.logs);
```
```ruby
logs = sandbox.computer_use.get_process_logs("novnc")
puts "NoVNC logs: #{logs}"
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/logs'
```
## Get process errors
Get error logs for a specific VNC process.
```python
errors = sandbox.computer_use.get_process_errors("x11vnc")
print("X11VNC errors:", errors)
```
```typescript
const errorsResp = await sandbox.computerUse.getProcessErrors('x11vnc');
console.log('X11VNC errors:', errorsResp.errors);
```
```ruby
errors = sandbox.computer_use.get_process_errors("x11vnc")
puts "X11VNC errors: #{errors}"
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/process/{processName}/errors'
```
## 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.
```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")
```
```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');
```
```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')
```
```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)
```
```java
// Single left click
sandbox.computerUse.click(100, 200);
// Double click
sandbox.computerUse.doubleClick(100, 200);
// Right click
sandbox.computerUse.click(100, 200, "right");
```
```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
}'
```
### Move
Move the mouse cursor to the specified coordinates.
```python
result = sandbox.computer_use.mouse.move(100, 200)
print(f"Mouse moved to: {result.x}, {result.y}")
```
```typescript
const result = await sandbox.computerUse.mouse.move(100, 200);
console.log(`Mouse moved to: ${result.x}, ${result.y}`);
```
```ruby
result = sandbox.computer_use.mouse.move(x: 100, y: 200)
puts "Mouse moved to: #{result.x}, #{result.y}"
```
```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"])
```
```java
var result = sandbox.computerUse.moveMouse(100, 200);
System.out.println("Mouse moved to: " + result.getX() + ", " + result.getY());
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/move' \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"x": 1,
"y": 1
}'
```
### Drag
Drag the mouse from start coordinates to end coordinates.
```python
result = sandbox.computer_use.mouse.drag(50, 50, 150, 150)
print(f"Drag ended at {result.x}, {result.y}")
```
```typescript
const result = await sandbox.computerUse.mouse.drag(50, 50, 150, 150);
console.log(`Drag ended at ${result.x}, ${result.y}`);
```
```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}"
```
```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"])
```
```java
var result = sandbox.computerUse.drag(50, 50, 150, 150);
System.out.println("Drag ended at: " + result.getX() + ", " + result.getY());
```
```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
}'
```
### 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.
```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)
```
```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);
```
```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)
```
```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)
```
```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);
```
```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
}'
```
### Get position
Get the current mouse cursor position.
```python
position = sandbox.computer_use.mouse.get_position()
print(f"Mouse is at: {position.x}, {position.y}")
```
```typescript
const position = await sandbox.computerUse.mouse.getPosition();
console.log(`Mouse is at: ${position.x}, ${position.y}`);
```
```ruby
position = sandbox.computer_use.mouse.position
puts "Mouse is at: #{position.x}, #{position.y}"
```
```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"])
```
```java
var position = sandbox.computerUse.getMousePosition();
System.out.println("Mouse is at: " + position.getX() + ", " + position.getY());
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/mouse/position'
```
## 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.
```python
sandbox.computer_use.keyboard.type("Hello, World!")
# With delay between characters
sandbox.computer_use.keyboard.type("Slow typing", 100)
```
```typescript
await sandbox.computerUse.keyboard.type('Hello, World!');
// With delay between characters
await sandbox.computerUse.keyboard.type('Slow typing', 100);
```
```ruby
sandbox.computer_use.keyboard.type(text: "Hello, World!")
# With delay between characters
sandbox.computer_use.keyboard.type(text: "Slow typing", delay: 100)
```
```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)
```
```java
sandbox.computerUse.typeText("Hello, World!");
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/type' \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"delay": 1,
"text": ""
}'
```
### Press
Press a key with optional modifiers.
```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"])
```
```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']);
```
```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"])
```
```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"})
```
```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");
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/key' \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"key": "enter",
"modifiers": []
}'
```
### Hotkey
Press a hotkey combination.
```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")
```
```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');
```
```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")
```
```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")
```
```java
// Copy
sandbox.computerUse.pressHotkey("ctrl", "c");
// Paste
sandbox.computerUse.pressHotkey("ctrl", "v");
// Alt+Tab
sandbox.computerUse.pressHotkey("alt", "tab");
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/keyboard/hotkey' \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"keys": "ctrl+c"
}'
```
### 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
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.
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.
```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)
```
```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,
});
```
```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)
```
```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)
}
```
```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);
```
```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'
```
### Find nodes
Search the accessibility tree by role, accessible name, state, and scope.
```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,
)
```
```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,
});
```
```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
)
```
```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)
}
```
```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)
);
```
```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
}'
```
### Focus node
Move keyboard focus to a node returned by `get_tree` or `find_nodes`.
```python
sandbox.computer_use.accessibility.focus_node("node-id")
```
```typescript
await sandbox.computerUse.accessibility.focusNode('node-id');
```
```ruby
sandbox.computer_use.accessibility.focus_node(id: "node-id")
```
```go
if err := sandbox.ComputerUse.Accessibility().FocusNode(ctx, "node-id"); err != nil {
log.Fatal(err)
}
```
```java
sandbox.computerUse.focusAccessibilityNode("node-id");
```
```bash
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
Run a node action, such as pressing a button.
```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")
```
```typescript
// Invoke the primary action
await sandbox.computerUse.accessibility.invokeNode('node-id');
// Invoke a named action
await sandbox.computerUse.accessibility.invokeNode('node-id', 'click');
```
```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")
```
```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)
}
```
```java
// Invoke the primary action
sandbox.computerUse.invokeAccessibilityNode("node-id");
// Invoke a named action
sandbox.computerUse.invokeAccessibilityNode("node-id", "click");
```
```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"}'
```
### Set node value
Write text or value content to nodes that support value changes.
```python
sandbox.computer_use.accessibility.set_node_value("node-id", "hello")
```
```typescript
await sandbox.computerUse.accessibility.setNodeValue('node-id', 'hello');
```
```ruby
sandbox.computer_use.accessibility.set_node_value(id: "node-id", value: "hello")
```
```go
if err := sandbox.ComputerUse.Accessibility().SetNodeValue(ctx, "node-id", "hello"); err != nil {
log.Fatal(err)
}
```
```java
sandbox.computerUse.setAccessibilityNodeValue("node-id", "hello");
```
```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"}'
```
## Screenshot operations
### Take full screen
Take a screenshot of the entire screen.
```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)
```
```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);
```
```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)
```
```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)
```
```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);
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot'
```
### Take region
Take a screenshot of a specific region.
```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}")
```
```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}`);
```
```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}"
```
```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)
```
```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"));
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region?x=1&y=1&width=1&height=1'
```
### Take compressed
Take a compressed screenshot of the entire screen.
```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)
)
```
```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
});
```
```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)
)
```
```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);
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/compressed'
```
### Take compressed region
Take a compressed screenshot of a specific region.
```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="jpeg", quality=80, show_cursor=True)
)
print(f"Compressed size: {screenshot.size_bytes} bytes")
```
```typescript
const region = { x: 0, y: 0, width: 800, height: 600 };
const screenshot = await sandbox.computerUse.screenshot.takeCompressedRegion(region, {
format: 'jpeg',
quality: 80,
showCursor: true
});
console.log(`Compressed size: ${screenshot.size_bytes} bytes`);
```
```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: "jpeg", quality: 80, show_cursor: true)
)
puts "Compressed size: #{screenshot.size_bytes} bytes"
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/screenshot/region/compressed?x=1&y=1&width=1&height=1'
```
## 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:
```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"}
)
)
```
```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' }
});
```
```ruby
require 'daytona'
daytona = Daytona::Daytona.new
sandbox = daytona.create(Daytona::CreateSandboxFromSnapshotParams.new(
snapshot: 'daytonaio/sandbox:0.6.0',
env_vars: { 'DAYTONA_RECORDINGS_DIR' => '/home/daytona/my-recordings' }
))
```
```go
import (
"github.com/daytona/clients/sdk-go/pkg/daytona"
"github.com/daytona/clients/sdk-go/pkg/types"
)
client, err := daytona.NewClient()
if err != nil {
log.Fatal(err)
}
sandbox, err := client.Create(ctx, types.SnapshotParams{
SandboxBaseParams: types.SandboxBaseParams{
Name: "my-sandbox",
EnvVars: map[string]string{
"DAYTONA_RECORDINGS_DIR": "/home/daytona/my-recordings",
},
},
Snapshot: "daytonaio/sandbox:0.6.0",
})
if err != nil {
log.Fatal(err)
}
```
```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);
}
```
### Start Recording
Start a new screen recording session with an optional name identifier:
```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}")
```
```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}`);
```
```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}"
```
```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)
```
```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());
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/start' \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"name": "test-1"
}'
```
### Stop Recording
Stop an active recording session by providing the recording ID:
```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}")
```
```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}`);
```
```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}"
```
```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)
```
```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());
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/stop' \
--request POST \
--header 'Content-Type: application/json' \
--data '{
"id": "recording-id"
}'
```
### List Recordings
Get a list of all recordings in the sandbox:
```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)")
```
```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)`);
});
```
```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
```
```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)
}
```
```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)"
);
}
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings'
```
### Get Recording
Get details about a specific recording:
```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")
```
```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`);
```
```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"
```
```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)
```
```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");
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}'
```
### Delete Recording
Delete a recording by ID:
```python
sandbox.computer_use.recording.delete("recording-id")
print("Recording deleted successfully")
```
```typescript
await sandbox.computerUse.recording.delete('recording-id');
console.log('Recording deleted successfully');
```
```ruby
sandbox.computer_use.recording.delete(id: 'recording-id')
puts 'Recording deleted successfully'
```
```go
err := sandbox.ComputerUse.Recording().Delete(ctx, "recording-id")
if err != nil {
log.Fatal(err)
}
fmt.Println("Recording deleted successfully")
```
```java
sandbox.computerUse.deleteRecording("recording-id");
System.out.println("Recording deleted successfully");
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}' \
--request DELETE
```
### 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.
```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)
```
```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);
```
```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)
```
```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)
```
```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);
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/recordings/{id}/download' \
--output local_recording.mp4
```
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 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
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
### Configure desktop resolution
By default, the virtual desktop runs at **1024x768**. Choose a different resolution by passing the `VNC_RESOLUTION` environment variable when creating a sandbox. Use the `x` format; widths from 640 to 7680 pixels and heights from 480 to 4320 pixels are supported.
```python
from daytona import Daytona, CreateSandboxFromSnapshotParams
daytona = Daytona()
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(
env_vars={"VNC_RESOLUTION": "1920x1080"}
)
)
```
```typescript
import { Daytona } from '@daytona/sdk';
const daytona = new Daytona();
const sandbox = await daytona.create({
envVars: { VNC_RESOLUTION: '1920x1080' }
});
```
```ruby
require 'daytona'
daytona = Daytona::Daytona.new
sandbox = daytona.create(Daytona::CreateSandboxFromSnapshotParams.new(
env_vars: { 'VNC_RESOLUTION' => '1920x1080' }
))
```
```go
import (
"github.com/daytona/clients/sdk-go/pkg/daytona"
"github.com/daytona/clients/sdk-go/pkg/types"
)
client, err := daytona.NewClient()
if err != nil {
log.Fatal(err)
}
sandbox, err := client.Create(ctx, types.SnapshotParams{
SandboxBaseParams: types.SandboxBaseParams{
EnvVars: map[string]string{
"VNC_RESOLUTION": "1920x1080",
},
},
})
if err != nil {
log.Fatal(err)
}
```
```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.setEnvVars(Map.of("VNC_RESOLUTION", "1920x1080"));
Sandbox sandbox = daytona.create(params);
}
```
You can also bake a resolution into a snapshot image with `ENV VNC_RESOLUTION=1920x1080` in its Dockerfile. A value passed at creation takes precedence over the image's `ENV`, which takes precedence over the `1024x768` default. Invalid values fall back to the default.
The virtual display's framebuffer is allocated when the X server starts, so the resolution can only be set when creating the sandbox. Restarting display processes or stopping and starting the sandbox keeps the original geometry; create a new sandbox to use a different resolution.
Pick the resolution to match what your agent assumes. Agents that emit normalized coordinates scale them by an assumed screen size, so a desktop that differs from that assumption displaces every click. Verify the live geometry with [Get info](#get-info) below.
`VNC_RESOLUTION` applies to Linux container sandboxes (the default sandbox class). Linux VM and Windows sandboxes currently run at a fixed resolution. Creating a sandbox with custom environment variables also bypasses pre-warmed sandbox pools, so allocation can take slightly longer.
### Get info
Get information about the displays.
```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}")
```
```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}`);
});
```
```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
```
```go
info, err := sandbox.ComputerUse.Display().GetInfo(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Displays: %v\n", info["displays"])
```
```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()
);
}
}
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/info'
```
### Get windows
Get the list of open windows.
```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})")
```
```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})`);
});
```
```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
```
```go
result, err := sandbox.ComputerUse.Display().GetWindows(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Open windows: %v\n", result["windows"])
```
```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() + ")");
}
}
```
```bash
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/computeruse/display/windows'
```