GuideGet Started

Using the Sandbox SDK

Create sandboxes and perform basic interactions with cua-sandbox

Prerequisites: Python 3.12 or 3.13 and a free Cua account at cua.ai for cloud sandboxes.

The Sandbox SDK (cua-sandbox) lets you create and control sandboxes — take screenshots, run shell commands, click, type, and more. Use it to verify your sandbox works before adding AI agents.

Installation

pip install cua

Or with uv:

uv pip install cua

Create a Sandbox

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.linux()) as sb:
        result = await sb.shell.run("uname -s")
        print(result.stdout)  # "Linux"

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires CUA_API_KEY environment variable.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.linux(kind="vm")) as sb:
        result = await sb.shell.run("uname -s")
        print(result.stdout)  # "Linux"

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires CUA_API_KEY environment variable.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.macos()) as sb:
        result = await sb.shell.run("sw_vers")
        print(result.stdout)

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires CUA_API_KEY environment variable. Works on any host OS — no Mac needed.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.windows()) as sb:
        result = await sb.shell.run("ver")
        print(result.stdout)

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires CUA_API_KEY environment variable.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.linux(), local=True) as sb:
        result = await sb.shell.run("uname -s")
        print(result.stdout)  # "Linux"

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires Docker. No API key needed.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.macos(), local=True) as sb:
        result = await sb.shell.run("sw_vers")
        print(result.stdout)

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires macOS host with Lume installed.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.windows(), local=True) as sb:
        result = await sb.shell.run("ver")
        print(result.stdout)

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires a Windows or Linux host with QEMU installed.

import asyncio
from cua import Sandbox, Image

async def main():
    async with Sandbox.ephemeral(Image.android(), local=True) as sb:
        result = await sb.shell.run("getprop ro.build.version.release")
        print(result.stdout)  # "14"

        screenshot = await sb.screenshot()
        with open("screenshot.png", "wb") as f:
            f.write(screenshot)

asyncio.run(main())

Requires Android SDK (emulator + platform-tools) or QEMU. No API key needed.

Common Operations

Shell Commands

result = await sb.shell.run("echo hello")
print(result.stdout)      # "hello\n"
print(result.returncode)  # 0
print(result.success)     # True

Screenshots

png_bytes = await sb.screenshot()
with open("screenshot.png", "wb") as f:
    f.write(png_bytes)

Mouse & Keyboard

# Click
await sb.mouse.click(100, 200)          # left click
await sb.mouse.right_click(100, 200)    # right click
await sb.mouse.double_click(100, 200)   # double click
await sb.mouse.move(100, 200)           # move without clicking
await sb.mouse.scroll(100, 200, dy=3)   # scroll

# Keyboard
await sb.keyboard.type("Hello, world!")
await sb.keyboard.press("Return")
await sb.keyboard.press("ctrl+c")

Persistent Sandboxes

For long-running workflows, create a named sandbox instead of ephemeral:

# Launch via CLI: cua sb launch ubuntu:24.04 --local --json
# → {"name": "my-sandbox-name", "status": "ready"}

# Connect from Python
from cua import Sandbox

async with Sandbox.connect("my-sandbox-name", local=True) as sb:
    await sb.shell.run("echo connected")

Or manage the full lifecycle in Python:

from cua import Sandbox, Image

# Create and keep running
sb = await Sandbox.create(Image.linux(), local=True)
await sb.shell.run("echo running")
# ... do more work ...
await sb.delete()

Image Types

ImageDescription
Image.linux()Ubuntu 24.04 container (default)
Image.linux(kind="vm")Ubuntu 24.04 full VM
Image.macos()macOS (latest)
Image.windows()Windows 11
Image.from_registry("ghcr.io/...")Custom OCI image

Next Steps

Was this page helpful?