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

# Mobile

> Provision, control, and display cloud mobile emulators/devices via Mobilerun — run natural-language agent tasks, stream the live screen, and call any Mobilerun API — without ever holding a Mobilerun key.

The **Mobile** primitive runs cloud mobile emulators/devices on [Mobilerun Cloud](https://docs.mobilerun.ai). You provision hosted Android/iOS devices, run natural-language agent tasks on them ("Open Settings and enable dark mode"), display the live screen, manage an app (APK) library, and reach the **entire** Mobilerun API through a wildcard wrapper. Naïve owns the Mobilerun credentials and scopes every device to your tenant — your agents never hold a Mobilerun key (the same operator-key model as [Compute](/getting-started/compute) with AWS).

<Info>
  Phones are **billed per minute from your credits**: `provision` creates the device immediately and the meter runs until you `terminate` it — **there is no upstream auto-stop**, so always terminate phones you're done with (running out of credits auto-terminates the phone, as does the max-runtime failsafe). Provisioning, device lifecycle (`reboot`/`reset`/`terminate`), proxy changes, running/stopping tasks, uploading apps, and mutating wildcard `call`s are **sensitive** — depending on the user's Account Kit they may require human approval (`status: "pending_approval"`).
</Info>

## Create a phone & display it

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Create a phone — provisions immediately, billed per minute from your credits.
// Defaults to dedicated_premium_device (the minute-billed cloud phone).
const { phone, credits_per_minute } = await naive.mobile.provision({ country: "US" });

// Operate by the Mobilerun device id:
await naive.mobile.waitReady(phone.device_id);
const { stream_url, stream_token, console_url } = await naive.mobile.stream(phone.device_id);

// Done? Terminate — this is what stops the per-minute meter.
await naive.mobile.terminate(phone.device_id);
```

Scope follows the client you hold: `naive.mobile.*` (your default user) vs `naive.forUser(id).mobile.*` (an end-user). Each tenant only ever sees the phones it created through Naïve, and each tenant's credits fund only its own phones.

## Run an agent task

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const task = await naive.mobile.run({
  task: "Open the Settings app and tell me the Android version",
  deviceId: phone.device_id, // required — run on one of your active phones
  vision: true,
  reasoning: true,
});

await naive.mobile.task(task.id);          // status + result
await naive.mobile.screenshots(task.id);   // captured screenshots
await naive.mobile.trajectory(task.id);    // step-by-step actions
await naive.mobile.stop(task.id);          // cancel a running task
```

## Device lifecycle

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await naive.mobile.reboot(phone.device_id);
await naive.mobile.reset(phone.device_id);       // wipe to a fresh state
await naive.mobile.terminate(phone.device_id);   // release the phone (STOPS the per-minute meter)
```

## Proxy (optional residential IP)

Devices come online on a **datacenter IP** by default. Attach a SOCKS5 proxy for a residential / country-specific IP:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await naive.mobile.setProxy(phone.device_id, { host: "…", port: 1080, user: "…", password: "…" });
await naive.mobile.proxy(phone.device_id);        // → { connected: true, ... }
await naive.mobile.removeProxy(phone.device_id);  // back to the datacenter IP
```

## Apps

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
await naive.mobile.apps();                                   // app library
await naive.mobile.uploadApp({ name: "MyApp", fileName: "app.apk" }); // signed upload URL
```

## Wildcard: search & call any Mobilerun API

Mobilerun Cloud is large (devices, tasks, apps, proxies, eSIM, device tools like tap/swipe/screenshot, flows, triggers, …). The `mobile` primitive ships a generated catalog of every operation, so any endpoint is reachable without a dedicated method:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Discover operations
const { methods } = await naive.mobile.search("screenshot");
// → [{ operationId: "take-screenshot", method: "GET", path: "/devices/{deviceId}/screenshot", ... }]

// Call any operation by operationId; path params are substituted
await naive.mobile.call("take-screenshot", { path: { deviceId: phone.device_id } });
await naive.mobile.call("list-proxies");
```

Device-scoped operations are restricted to your own devices, and mutating calls go through the same approval gate as the curated methods.

## CLI

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
naive mobile provision --country US        # provisions immediately, billed per minute from credits
naive mobile phones                        # list your phones + status + metered spend
naive mobile stream <device-id>
naive mobile run "Open Settings and enable dark mode" --device <device-id> --vision
naive mobile call take-screenshot --path deviceId=<device-id>
naive mobile terminate <device-id>         # STOPS the per-minute meter
```

## Configuration

Set the operator's Mobilerun Cloud API key (`dr_sk_…`) in the API environment as `MOBILERUN_API_KEY` (override the base URL with `MOBILERUN_API_BASE`). Billing is metered by the API: `NAIVE_MOBILE_CREDITS_PER_MINUTE` (default 4) is charged per device-minute, and devices auto-terminate on credit exhaustion or after `NAIVE_MOBILE_MAX_RUNTIME_MINUTES` (default 1440). `naive mobile status` reports configuration, reachability, your phone counts, and the operator-wide upstream device total (the "confirm nothing is billing" check).
