> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Mobile device

> A cloud Android phone, beside the sandbox and the browser: look at its screen, tap, type, open a link, watch it live.

The computer suite has three members. The [sandbox](/docs/computer/sandbox) is a Linux micro-VM with a shell and a filesystem; the [browser](/docs/computer/browser) is a managed remote browser opened beside it; a **mobile device** is a cloud **phone**: a screen, touch input and an app lifecycle. It is its own resource: it needs no sandbox, and nothing about it is a shell.

## An Android phone

| Field | Value |
| - | - |
| `platform` | `android` — the one platform offered today; `ios` is refused with `400 validation_failed` |
| `os_version` | `13`, `14` or `15` (default `15`) |
| `model` | `phone` |
| Available | on demand, billed by the minute |

## What you get

* A cloud phone, usually ready in **about a minute**, placed in the `us`, `eu` or `as` jurisdiction you ask for. `POST` waits up to about 45 seconds and answers with whatever is true then, usually `creating`; poll `GET` until it is `ready`.
* Seven actions: `screenshot`, `element_tree`, `tap` (by coordinates or by an element's text, id or accessibility label), `type`, `press_key`, `scroll`, `open_url`.
* A **realtime view** of the screen in the dashboard, beside the controls, started on demand.
* Apps installed when it starts, named by package (`com.example.app`) from the platform's curated app catalogue.

## How it ends — timers, not pause

There is no pause. A device lives until you delete it or one of two timers fires, both set at create:

| Timer | Default | Range | What it is |
| - | - | - | - |
| `idle_timeout_minutes` | 10 | 1–180 | Ends the device after this long with nobody acting on it. Any action resets it: from the API, the agent, or a person watching **Live**. |
| `max_duration_minutes` | 120 | 1–1440 | A hard ceiling on its life, whatever happens. |

The platform checks every running device once a minute, so a device ends within a minute of its timer. `GET /v1/mobile_devices/{id}` also **reconciles**: it asks the provider and rewrites the stored status when they disagree, filling `terminated_at` and `termination_reason` (`requested`, `idle_timeout`, `max_duration`, or `unknown` when the provider ended it). A fifth reason, `unfunded`, is the platform stopping a device whose organization can no longer pay for it; see [Limits and billing](#limits-and-billing). The list reads stored rows and can lag until a device is opened.

## Drive it

<CodeGroup>
  ```bash CLI theme={"system"}
  vetta mobile create --name pixel --os-version 15
  vetta mobile screenshot mob_… --out shot.jpg
  vetta mobile act mob_… --type tap --text "Sign in"
  vetta mobile act mob_… --type type --text "hello"
  vetta mobile delete mob_…
  ```

  ```typescript TypeScript theme={"system"}
  const device = await vetta.mobileDevices.create({ name: "pixel", os_version: "15" });
  const look = await vetta.mobileDevices.act(device.id, { type: "screenshot" });
  await vetta.mobileDevices.act(device.id, { type: "tap", x: 162, y: 1087 });
  await vetta.mobileDevices.delete(device.id);
  ```

  ```bash cURL theme={"system"}
  curl https://api.vetta.sh/v1/mobile_devices \
    -H "Authorization: Bearer $VETTA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "name": "pixel", "os_version": "15" }'
  ```
</CodeGroup>

A screenshot is a JPEG at half the phone's resolution (540 × 1200 on a typical phone), and its pixels map 1:1 to `tap` coordinates, which is what the dashboard's click-to-tap uses. `element_tree` lists the named elements on the screen with their bounds in the same pixels, so a tap can name an element instead of a point. An action answers with words; take a screenshot to see its result.

## Agents

An agent uses a phone through the built-in [`mobile` tool](/docs/capabilities/tools#the-mobile-tool), on the `pi` harness only; the other [harnesses](/docs/concepts/harness-capabilities) have no mobile tool. The first call opens a phone for the session, the model sees each screenshot, and the phone shows up in the chat's **Computer** panel and on the Mobile page (Computers → Mobile) while the agent works, so you can watch it live. The tool asks for approval by default; approve it for the session once and the agent carries on.

* An agent's phone takes the tool's `config`: the same timers, but `max_duration_minutes` defaults to **60**, not 120.
* `open_url` is **not** bound by the browser's `allowed_domains`: a phone opens any URL or deep link. For an agent whose web reach you narrowed, keep the tool on `ask` or set it to `deny`.

## Live view

The device page's screen panel has two modes. **Screenshot** is a picture you click to tap. **Live** swaps the picture for a realtime stream of the screen, in the same place and at the same size, so the controls beside it stay where they are; **Screenshot** switches back and drops the stream. The credential behind the stream is a **bearer credential** — anyone holding it sees and drives the device — so it is held on that screen only, never stored, never logged, never returned inside another object, and withheld from the agent-facing tool catalogue. Each mint is written to the [audit log](/docs/api/audit-logs) as `mobile_device.live_view_opened`, without the credential.

In **Screenshot** mode the page takes a new screenshot after each action, and again when you switch back from **Live** (the stream can drive the phone too). Taps in **Live** go straight to the phone, so while it plays the page also takes a screenshot every 30 seconds: that keeps the idle timer from ending a phone you are using. Live is offered once the device is `ready`; asked for while it is still starting, it answers `409 computer_unavailable`.

## Limits and billing

* One person or script should drive a device at a time; actions on one device run one after another.
* Apps: up to 10 package names at create, from the platform's curated app catalogue (there is no upload route); no install on a running device.
* Capacity: no per-organization limit on live devices. A create is refused with `429 rate_limited` only when every phone slot on the platform is in use; try again shortly.
* Cost: **`$0.039` per device-minute** (`$2.34` per hour), from create to end, rounded up to whole minutes with a one-minute minimum. It is one `mobile` line on the [ledger](/docs/platform/billing), booked once when the device ends. Actions are free beyond the minutes they run in, and a device that fails to provision bills nothing; one that ran and then hit an error is ended and billed for the minutes it ran. The device page shows the rate and the cost so far. See [Pricing](/docs/platform/pricing#priced-tools).
* Money: a create is admitted when the balance covers **10 minutes (`$0.39`) for every live device and the new one** (an agent's phone included), plus what the live ones have run so far; otherwise it is `402 insufficient_credits`, naming the amount needed. Once a minute the platform checks every running device. If the organization's plan has lapsed, or its balance no longer covers what its running devices have accrued, it ends them with `termination_reason: "unfunded"` and bills the minutes they ran. A plan that is `past_due` keeps its devices through the payment grace period.
* Phone minutes bill the organization's balance directly, including a phone an agent opens. They are not held against a session's or an agent's budget cap; the timers and the funded-balance check above are what bound them.

## Reference

| Surface | Where |
| - | - |
| API | [Mobile devices](/docs/api/mobile-devices) |
| SDK | [`client.mobileDevices`](/docs/sdk/mobile-devices) |
| CLI | [`vetta mobile`](/docs/cli/mobile) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.