Getting Started

Run on Android

Connect a device via USB or start an emulator, then run your flows:

maestro-runner flows/

Platform and device are auto-detected. No configuration needed for a single connected Android device.

Tip: For faster Android execution, use the DeviceLab driver: maestro-runner --driver devicelab flows/ (~2x faster than the default UIAutomator2 driver, ~7.2x faster than Maestro CLI).

Explicit device selection

maestro-runner --platform android --device emulator-5554 flows/

Auto-start an emulator

If no device is connected, maestro-runner can start one for you:

maestro-runner --auto-start-emulator flows/

Or start a specific AVD by name:

maestro-runner --start-emulator Pixel_7_API_33 flows/

The emulator shuts down automatically after tests. Use --shutdown-after=false to keep it running.

Run on iOS Simulator

maestro-runner --platform ios flows/

Start a simulator by name if none is booted:

maestro-runner --platform ios --start-simulator "iPhone 15 Pro" flows/

Or let maestro-runner pick one automatically:

maestro-runner --platform ios --auto-start-emulator flows/

Note: When a booted simulator is auto-detected, --team-id is not required.

Run on iOS Real Device

Connect your iPhone or iPad via USB. Real devices require an Apple Development Team ID for WDA code signing:

maestro-runner --platform ios --team-id ABCDE12345 flows/

Find your Team ID in Xcode under Signing & Capabilities, or:

security find-identity -v -p codesigning | head -5

Target a specific device by UDID:

maestro-runner --platform ios --team-id ABCDE12345 \
  --device 00001234-ABCDEF012345 flows/

Install an App Before Testing

The --app-file flag installs a fresh build before running tests, so you always test the right version:

Platform Command
Android maestro-runner --app-file app.apk flows/
iOS Simulator maestro-runner --platform ios --app-file MyApp.app flows/
iOS Device maestro-runner --platform ios --team-id ABCDE12345 --app-file MyApp.ipa flows/

Without --app-file, tests run against whatever is already installed on the device.

Run on Cloud (Appium)

Connect to BrowserStack, SauceLabs, LambdaTest, or any Appium-compatible cloud:

maestro-runner --driver appium \
  --appium-url "https://your-cloud-provider/wd/hub" \
  --caps caps.json \
  flows/

The caps.json file uses standard Appium capabilities. CLI flags like --platform, --device, and --app-file override values in the caps file.

For a local Appium server, just switch the driver:

maestro-runner --driver appium flows/

Parallel Execution

Run tests across multiple devices at the same time:

maestro-runner --parallel 3 flows/

Combine with auto-start to spin up emulators automatically:

maestro-runner --parallel 3 --auto-start-emulator flows/

Or specify exact devices:

maestro-runner --device emulator-5554,emulator-5556 flows/

Each parallel Android emulator needs a unique AVD name. For iOS, if not enough shutdown simulators exist, maestro-runner automatically creates them (and deletes them on shutdown). Use --platform ios --parallel 2 --auto-start-emulator.

Troubleshooting

Stale socket after crash

If maestro-runner was killed unexpectedly (kill -9, system crash), the next run automatically detects and cleans up stale socket files. No manual intervention needed.

If you see "device already in use" but no other instance is running, remove the files:

rm /tmp/uia2-<serial>.sock /tmp/uia2-<serial>.pid

Replace <serial> with your device serial (find it with adb devices).

Keyboard covering target element

If taps fail after inputText or inputRandom with an error like "keyboard covering element", add - hideKeyboard after the input step:

- inputText: "[email protected]"
- hideKeyboard
- tapOn: "Submit"

maestro-runner automatically detects when the soft keyboard covers a target element and suggests this fix in the error message.

clearState fails on iOS real device (Appium)

If clearState fails with mobile: clearApp unsupported, use newSession: true on launchApp instead:

- launchApp:
    appId: com.example.app
    newSession: true

This creates a fresh Appium session, providing clean state without relying on mobile: clearApp.