Maestro is a mobile UI testing framework built by mobile.dev that simplifies end-to-end testing. But its documentation is spread across multiple pages. Commands aren’t fully documented. Flags are mentioned in examples but never explained.
This is the complete reference. Every command, every flag, every config option.
Installation
macOS / Linux
curl -Ls "https://get.maestro.mobile.dev" | bash
Add to your PATH:
export PATH="$PATH":"$HOME/.maestro/bin"
Windows (WSL Required)
Maestro doesn’t run natively on Windows. You need Windows Subsystem for Linux:
- Install WSL2:
wsl --install
- Open Ubuntu terminal and install Maestro:
curl -Ls "https://get.maestro.mobile.dev" | bash
- Connect ADB to Windows:
export ADB_SERVER_SOCKET=tcp:host.docker.internal:5037
Verify Installation
maestro --version
Core Commands
maestro test
Run one or more flows.
# Run a single flow
maestro test flow.yaml
# Run all flows in a directory
maestro test flows/
# Run specific flows
maestro test flow1.yaml flow2.yaml flow3.yaml
Essential Flags
| Flag | Description | Example |
|---|---|---|
--app-path |
Path to app binary | --app-path ./app.apk |
--format |
Output format (junit) | --format junit |
--output |
Report output directory | --output ./reports |
--env |
Set environment variable | --env USERNAME=test |
--device |
Target specific device | --device emulator-5554 |
--debug-output |
Save debug artifacts | --debug-output ./debug |
--continuous |
Watch mode, re-run on changes | --continuous |
--include-tags |
Run flows with specific tags | --include-tags smoke |
--exclude-tags |
Skip flows with specific tags | --exclude-tags slow |
App Path Flag
The --app-path flag tells Maestro where to find your app binary:
# Android APK
maestro test --app-path ./app/build/outputs/apk/debug/app-debug.apk flow.yaml
# iOS Simulator App
maestro test --app-path ./build/MyApp.app flow.yaml
# iOS IPA (for real devices - limited support)
maestro test --app-path ./build/MyApp.ipa flow.yaml
If --app-path is not specified, Maestro assumes the app is already installed on the device.
Report Generation
Generate JUnit-compatible reports for CI integration:
maestro test --format junit --output ./test-results flows/
This creates report.xml in JUnit format, compatible with:
- GitHub Actions
- Jenkins
- GitLab CI
- CircleCI
- Azure DevOps
For detailed report options, see Maestro Test Reports: JUnit, HTML, Allure.
Environment Variables
Pass variables to your flows:
maestro test --env USERNAME=testuser --env PASSWORD=secret flow.yaml
Access in your flow:
- inputText: ${USERNAME}
- inputText: ${PASSWORD}
Continuous Mode
Watch for file changes and re-run tests:
maestro test --continuous flow.yaml
Useful during flow development. Press Ctrl+C to stop.
maestro studio
Launch the visual element inspector.
maestro studio
Opens in your browser at http://localhost:9999. Features:
- Live device screen view
- Element hierarchy inspector
- Accessibility ID viewer
- Click-to-generate commands
- Real-time flow execution
Studio Flags
| Flag | Description | Example |
|---|---|---|
--device |
Target specific device | --device emulator-5554 |
--port |
Custom port | --port 8080 |
maestro cloud
Run tests on Maestro Cloud infrastructure.
maestro cloud --app-file ./app.apk flows/
Cloud Flags
| Flag | Description | Example |
|---|---|---|
--app-file |
App binary to upload | --app-file ./app.apk |
--app-binary-id |
Use previously uploaded app | --app-binary-id abc123 |
--android-api-level |
Android API version | --android-api-level 33 |
--ios-version |
iOS version | --ios-version 17 |
--device-locale |
Device locale | --device-locale ja_JP |
--include-tags |
Run specific tags | --include-tags regression |
--name |
Upload name | --name "Nightly Run" |
--async |
Don’t wait for results | --async |
Cloud Pricing
Maestro Cloud costs $250/device/month for unlimited test runs. The 3-minute execution limit on free tier makes it unsuitable for comprehensive test suites.
maestro record
Record interactions and generate flow YAML.
maestro record output.yaml
Captures:
- Taps
- Swipes
- Text input
- Back button presses
Limitation: Recording doesn’t capture assertions. You’ll need to add assertVisible commands manually.
maestro download-samples
Download example flows:
maestro download-samples
Creates a samples/ directory with flows for:
- Android Contacts app
- iOS Contacts app
- Wikipedia Android app
Useful for learning Maestro syntax.
maestro hierarchy
Print the current view hierarchy:
maestro hierarchy
Outputs the element tree in text format. Useful for debugging when Studio isn’t available.
maestro start-device
Launch an emulator/simulator:
# Android
maestro start-device --platform android --api-level 33
# iOS
maestro start-device --platform ios --ios-version 17
maestro login
Authenticate with Maestro Cloud:
maestro login
Opens browser for authentication. Credentials saved to ~/.maestro/.
Required before using --analyze or cloud features.
AI Analysis (Beta)
Maestro’s AI analysis feature reviews your test results and provides insights.
maestro test --analyze flows/
Generates an HTML report with:
- Spelling and grammar issues in your app
- Internationalization problems
- UI consistency issues
- Potential bugs detected from screenshots
Requirements:
- Must be logged in (
maestro login) - Beta feature — results should be validated
Disable Analysis Notification
export MAESTRO_CLI_ANALYSIS_NOTIFICATION_DISABLED=true
maestro test flows/
Configuration File: config.yaml
Create config.yaml in your workspace root to configure test execution.
Basic Structure
# config.yaml
flows:
- "*" # Include all flows in root
- "smoke/*" # Include smoke directory
- "!regression/*" # Exclude regression directory
executionOrder:
continueOnFailure: true # Continue if a flow fails (default: true)
flowsOrder:
- login
- dashboard
- checkout
- logout
Flow Inclusion Patterns
flows:
- "*" # All flows in root directory
- "subFolder/*" # All flows in subFolder
- "**/*" # All flows recursively
- "!slow/*" # Exclude slow directory
- "smoke/login.yaml" # Specific flow
Execution Order
By default, Maestro runs flows in arbitrary order. To specify order:
executionOrder:
continueOnFailure: false # Stop on first failure
flowsOrder:
- setup # Runs first
- test_feature_a
- test_feature_b
- teardown # Runs last
Flow names can be:
- Filename without extension:
login(forlogin.yaml) - Flow name from YAML:
name: Login Flow
Environment Variables
env:
BASE_URL: https://staging.example.com
API_KEY: ${API_KEY} # Read from system environment
Tags
Define tags in your flows:
# login.yaml
tags:
- smoke
- auth
appId: com.example.app
---
- launchApp
- tapOn: "Login"
Run specific tags:
maestro test --include-tags smoke flows/
maestro test --exclude-tags slow flows/
Flow YAML Reference
Minimal Flow
appId: com.example.app
---
- launchApp
- tapOn: "Get Started"
- assertVisible: "Welcome"
Flow with Metadata
appId: com.example.app
name: Login Flow
tags:
- smoke
- critical
env:
TIMEOUT: 5000
---
- launchApp
- tapOn: "Login"
Common Commands
| Command | Description | Example |
|---|---|---|
launchApp |
Start the app | - launchApp |
tapOn |
Tap element | - tapOn: "Button" |
inputText |
Type text | - inputText: "hello" |
assertVisible |
Check element visible | - assertVisible: "Welcome" |
assertNotVisible |
Check element hidden | - assertNotVisible: "Error" |
swipe |
Swipe gesture | - swipe: { direction: "up" } |
scroll |
Scroll to element | - scroll |
back |
Press back button | - back |
hideKeyboard |
Dismiss keyboard | - hideKeyboard |
waitForAnimationToEnd |
Wait for animations | - waitForAnimationToEnd |
takeScreenshot |
Capture screenshot | - takeScreenshot: "checkout" |
runFlow |
Run another flow | - runFlow: login.yaml |
Selectors
# By text (default)
- tapOn: "Submit"
# By ID
- tapOn:
id: "submit_button"
# By accessibility ID
- tapOn:
accessibilityId: "Submit Button"
# By index (multiple matches)
- tapOn:
text: "Item"
index: 0
# With timeout
- tapOn:
text: "Loading Complete"
timeout: 10000 # 10 seconds
Conditional Logic
- runFlow:
when:
visible: "Skip Tutorial"
file: skip_tutorial.yaml
JavaScript Injection
- evalScript: |
const timestamp = Date.now();
output.timestamp = timestamp;
- inputText: ${output.timestamp}
Common Errors and Fixes
“No devices found”
Error: No devices found
Fix: Start an emulator/simulator or connect a device:
# Android
emulator -avd Pixel_6_API_33
# iOS
open -a Simulator
Verify connection:
adb devices # Android
xcrun simctl list # iOS
“App not installed”
Error: App com.example.app is not installed
Fix: Either install the app first or use --app-path:
# Install manually
adb install app.apk
# Or use --app-path
maestro test --app-path ./app.apk flow.yaml
“Element not found”
Error: Unable to find element with text "Button"
Fixes:
- Use
maestro studioto verify the element text/ID - Add timeout:
- tapOn: { text: "Button", timeout: 10000 } - Wait for animations:
- waitForAnimationToEnd - Check if element is in a scrollable container
For more on flaky tests, see Maestro Flakiness: A Code Deep-Dive.
“Flow timeout”
Error: Flow execution timed out
Fix: Increase the flow timeout in config or environment:
export MAESTRO_FLOW_TIMEOUT=600000 # 10 minutes
“Could not launch app”
Error: Could not launch app com.example.app
Fixes:
- Verify
appIdmatches your app’s package name - Check app is installed:
adb shell pm list packages | grep example - Clear app data:
adb shell pm clear com.example.app
CI/CD Integration
GitHub Actions
name: Maestro Tests
on: [push, pull_request]
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install Maestro
run: curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Start Simulator
run: |
xcrun simctl boot "iPhone 15"
- name: Run Tests
run: |
export PATH="$PATH":"$HOME/.maestro/bin"
maestro test --format junit --output ./results flows/
- name: Upload Results
uses: actions/upload-artifact@v4
with:
name: test-results
path: ./results/
For full CI/CD setup, see Maestro CI/CD: GitHub Actions & Jenkins.
Jenkins
pipeline {
agent any
stages {
stage('Install Maestro') {
steps {
sh 'curl -Ls "https://get.maestro.mobile.dev" | bash'
}
}
stage('Run Tests') {
steps {
sh '$HOME/.maestro/bin/maestro test --format junit flows/'
}
}
}
post {
always {
junit 'report.xml'
}
}
}
Running Maestro on Your Own Devices
Maestro Cloud costs $250/device/month. For a 10-device setup, that’s $30,000/year.
Alternative: Run Maestro on devices you own.
Direct Device Connection
Maestro works with any connected device:
# List connected devices
adb devices
# Run on specific device
maestro test --device emulator-5554 flow.yaml
Parallel Execution
Run on multiple devices simultaneously:
# Terminal 1
maestro test --device emulator-5554 flows/
# Terminal 2
maestro test --device emulator-5556 flows/
Scaling Beyond Local
For distributed device labs without cloud costs, tools like DeviceLab connect your own devices into a managed grid. Run Maestro flows across your entire device fleet at $99/device/month — or free if you’re running everything locally.
For real iOS testing setup, see Maestro on Real iOS Devices: The Complete Guide.
Quick Reference Card
# Run tests
maestro test flow.yaml
maestro test --app-path ./app.apk flows/
maestro test --format junit --output ./results flows/
maestro test --include-tags smoke flows/
maestro test --continuous flow.yaml
# Development
maestro studio
maestro record output.yaml
maestro hierarchy
# Cloud
maestro login
maestro cloud --app-file ./app.apk flows/
maestro test --analyze flows/
# Device management
maestro start-device --platform android --api-level 33
Missing a command or flag? Check out the Maestro vs Appium comparison if you’re evaluating options.