# dcd cloud

Upload an app binary and run Maestro flows on DeviceCloud. This is the primary command and a drop-in replacement for `maestro cloud`.

```bash
dcd cloud <app-file> <flows-dir> [flags]
```

The command blocks until all tests have completed, then exits with an appropriate [exit code](https://docs.devicecloud.dev/advanced/exit-codes.md).

## Arguments

| Argument | Description |
|----------|-------------|
| `<app-file>` | Path to your app binary: `.apk` for Android, `.app` or `.zip` for iOS, or an Expo iOS build archive (`.tar.gz`), which is extracted automatically |
| `<flows-dir>` | Path to the flow file or directory of flows to run |

## Flags

### Authentication

| Flag | Description |
|------|-------------|
| `--api-key <key>`, `--apiKey` | Your DeviceCloud API key. Defaults to the `DEVICE_CLOUD_API_KEY` env var. Optional if you've run [`dcd login`](https://docs.devicecloud.dev/cli-reference/login-and-accounts.md) |
| `--api-url <url>` | API base URL. Defaults to the environment you logged in to with `dcd login`, otherwise `https://api.devicecloud.dev` |

See [Authentication](https://docs.devicecloud.dev/getting-started/authentication.md) for the full picture.

### App

| Flag | Description |
|------|-------------|
| `--app-binary-id <id>` | Reuse a previously uploaded binary instead of uploading again |
| `--app-url <url>` | Signed URL to an Expo iOS build (`.tar.gz`). The archive is downloaded and extracted automatically. Expo signed URLs expire after ~1 hour. Mutually exclusive with `--app-file` |
| `--app-file <path>` | Path to the app binary (alternative to the positional `<app-file>` argument) |
| `--ignore-sha-check` | Force re-upload even if a binary with the same SHA already exists |
| `--encrypt` / `--no-encrypt` | Encryption is on by default (CLI 5.7.0 and later): the app binary, flow files and `--env` values are encrypted on your machine before upload, each with its own key. Pass `--no-encrypt` (or set `DCD_ENCRYPT=0`) to upload them unencrypted. An unchanged binary is still deduplicated, so it isn't uploaded again. See [Data Encryption](https://docs.devicecloud.dev/security-and-compliance/security-overview.md#data-encryption) |

### Device

| Flag | Description |
|------|-------------|
| `--android-device <device>` | Android device model to run on (see [Devices](https://docs.devicecloud.dev/getting-started/devices-and-os-versions.md)) |
| `--android-api-level <level>` | Android API level |
| `--ios-device <device>` | iOS device model to run on (see [Devices](https://docs.devicecloud.dev/getting-started/devices-and-os-versions.md)) |
| `--ios-version <version>` | iOS version |
| `--device-locale <locale>` | Device locale (see [Device Locale](https://docs.devicecloud.dev/configuration/device-locale.md)) |
| `--orientation <orientation>` | Device orientation, `0` (portrait) or `90` (landscape). Android only (see [Orientation](https://docs.devicecloud.dev/configuration/device-orientation.md)) |
| `--google-play` | Use a Google Play-enabled device. Android only (see [Google Play APIs](https://docs.devicecloud.dev/configuration/google-play-apis.md)) |
| `--runner-type <type>` | Runner type to use (see [Runner Types](https://docs.devicecloud.dev/configuration/runner-types.md)) |
| `--render-engine <engine>` | Android only. Software renderer the emulator boots with: `lavapipe` (default) or `swiftshader`. Try `swiftshader` if your app fails to render or the device drops out mid-run. Apps built with Flutter are detected and switched automatically |
| `--ios-device-matrix <device>:<version>` | Run every flow once on each listed iOS device, e.g. `iphone-16:18`. Repeat the flag for each device (see [Device Matrix](https://docs.devicecloud.dev/configuration/device-matrix.md)) |
| `--android-device-matrix <device>:<apiLevel>` | Run every flow once on each listed Android device, e.g. `pixel-8:34`. Append `:play` for Google Play. Repeat the flag for each device (see [Device Matrix](https://docs.devicecloud.dev/configuration/device-matrix.md)) |

### Flows

| Flag | Description |
|------|-------------|
| `--flows <path>` | Path to a flow file or a directory of flows (alternative to the positional `<flows-dir>` argument) |
| `--config <path>` | Path to a `config.yaml` workspace config file (see [Workspace Configuration](https://docs.devicecloud.dev/configuration/workspace-configuration.md)) |
| `--exclude-flows <paths>` | Comma-separated list of flow files or sub-directories to exclude |
| `--include-tags <tags>` | Only run flows with these tags (comma-separated) |
| `--exclude-tags <tags>` | Skip flows with these tags (comma-separated) |

### Test Configuration

| Flag | Description |
|------|-------------|
| `--maestro-version <version>`, `--maestroVersion` | Maestro version to use, or `latest` (see [Maestro Versions](https://docs.devicecloud.dev/configuration/maestro-versions.md)) |
| `--env <KEY=VALUE>`, `-e` | Environment variables to pass to the test. Repeat for multiple values (see [Environment Variables](https://docs.devicecloud.dev/configuration/environment-variables.md)) |
| `--metadata <key=value>`, `-m` | Arbitrary metadata to attach to the run (shown in the console). Repeat for multiple values |
| `--name <name>` | Name for this upload (shown in the console) |
| `--retry <n>` | Retry failed tests up to `n` times (free of charge). Max `2` (see [Retry Strategies](https://docs.devicecloud.dev/advanced/retry-strategies.md)) |

### GitHub / PR Context

Attach Git and pull request metadata to a run. These values are displayed in the DeviceCloud console alongside the test results, making it easy to trace a run back to the exact commit or PR that triggered it.

| Flag | Description |
|------|-------------|
| `--branch <name>` | Git branch name for this run |
| `--commit-sha <sha>` | Git commit SHA for this run |
| `--repo-name <owner/repo>` | Repository in `owner/repo` format (e.g. `acme/my-app`) |
| `--pr-number <number>` | Pull request number |
| `--pr-url <url>` | Pull request URL |

### Android-Specific

| Flag | Description |
|------|-------------|
| `--maestro-chrome-onboarding` | Force Maestro-based Chrome onboarding. Slows tests but can fix browser-related crashes (see [Chrome Onboarding](https://docs.devicecloud.dev/advanced/chrome-onboarding.md)) |
| `--android-no-snapshot` | Force a cold boot instead of a snapshot boot on the standard Android runner. Automatically enabled for API 34+ |
| `--show-crosshairs` | Display crosshairs for screen interactions during test execution |

### Performance

| Flag | Description |
|------|-------------|
| `--disable-animations` | Disable device animations during test execution. On Android, disables system animation scales. On iOS, enables Reduce Motion |

### Output & Execution

| Flag | Description |
|------|-------------|
| `--async` | Submit tests and return immediately (exit `0`) without waiting for results (see [Async Execution](https://docs.devicecloud.dev/advanced/async-execution.md)) |
| `--cancel-previous` | Cancel the still-queued tests of the previous run from the same CI context. Needs `--repo-name` plus `--branch` or `--pr-number` (see [Cancelling superseded runs](https://docs.devicecloud.dev/advanced/cancelling-superseded-runs.md)) |
| `--priority <level>` | `low`, `normal` (default) or `high`. Reorders only your organisation's own queued runs (see [Run Priority](https://docs.devicecloud.dev/configuration/run-priority.md)) |
| `--quiet`, `-q` | Suppress per-test progress; print only the final summary |
| `--json` | Output results as JSON. Exits `0` on success, `2` on test failure, `1` on CLI/infrastructure errors. The output includes a `notices` array with any deprecation or other notices for the run. A run superseded through `--cancel-previous` has `status` `SUPERSEDED` and exits `0` |
| `--json-file` | Write JSON results to a file (`<upload_id>_dcd.json` by default). Exits `0` even if the test run fails; infrastructure errors still exit `1` |
| `--json-file-name <name>` | Custom name (or relative path) for the JSON file. Requires `--json-file` |
| `--dry-run` | Simulate the run without uploading or triggering a test — useful for debugging workflow issues |
| `--report <format>`, `--format` | Generate and download a report. Options: `junit`, `html`, `html-detailed`, `allure` (see [Report Formats](https://docs.devicecloud.dev/test-artifacts-and-reports/report-formats.md)) |
| `--junit-path <path>` | Output path for the JUnit report (requires `--report junit`) |
| `--html-path <path>` | Output path for the HTML report (requires `--report html` or `html-detailed`). The HTML report downloads as a ZIP, so use a `.zip` path such as `./report.zip` |
| `--allure-path <path>` | Output path for the Allure report (requires `--report allure`) |
| `--download-artifacts <ALL\|FAILED>` | Download test artifacts after completion (see [Artifacts](https://docs.devicecloud.dev/test-artifacts-and-reports/artifacts-and-downloads.md)) |
| `--artifacts-path <path>` | Output path for the artifacts zip (default `./artifacts.zip`). Requires `--download-artifacts` |
| `--debug` | Enable verbose debug logging |

## Examples

**Android:**
```bash
dcd cloud app.apk flows/ --android-device pixel-8 --android-api-level 34
```

**iOS:**
```bash
dcd cloud app.zip flows/ --ios-device iphone-16 --ios-version 18
```

**Filter by tag:**
```bash
dcd cloud app.apk flows/ --include-tags smoke
```

**Reuse a previously uploaded binary:**
```bash
dcd cloud flows/ --app-binary-id 67894274-b789-4c1e-80d4-da8998998999
```

**Save results to JSON:**
```bash
dcd cloud app.apk flows/ --json-file --json-file-name results.json
```
