Maestro Cloud charges $250/device/month. BrowserStack’s App Automate starts at $199/month. Here’s how to run Maestro tests in CI without paying either.


Maestro is open-source. The CLI is free. The test framework is free. The only thing that costs money is where you run your tests.

Whether you’re migrating from BrowserStack’s Maestro integration, evaluating Maestro Cloud pricing, or setting up mobile E2E testing from scratch, this guide covers every option.

This guide covers three approaches:

  1. GitHub Actions with Maestro Cloud — The official path (costs money)
  2. GitHub Actions self-hosted — Your own runners (free, but you manage infra)
  3. Jenkins with local devices — Full control (free, most setup)

And at the end: a fourth option that gives you the simplicity of cloud with the economics of self-hosted.


The Cloud Options: What They Cost

Before we get into the DIY setups, here’s what you’d pay for managed solutions:

Service Android iOS Notes
Maestro Cloud $250/device/month $250/device/month Per concurrent execution
BrowserStack App Automate $199-249/month $199-249/month 1 parallel included, runs Maestro 1.39
DeviceCloud (Moropo) ~50% of Maestro Cloud Same Uses open-source Maestro API

If you need 3 parallel iOS devices and 3 Android devices, Maestro Cloud costs $1,500/month.

That’s the motivation for self-hosting.


Option 1: GitHub Actions + Maestro Cloud

This is the path of least resistance. You pay for simplicity.

Setup

  1. Get your API key from console.maestro.dev
  2. Add it as a GitHub secret: MAESTRO_CLOUD_API_KEY
  3. Add the action to your workflow:
yaml
# .github/workflows/maestro.yaml
name: Maestro Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'
      
      - run: ./gradlew assembleDebug
      
      - uses: mobile-dev-inc/action-maestro-cloud@v1.9.8
        with:
          api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
          project-id: 'proj_01example'
          app-file: app/build/outputs/apk/debug/app-debug.apk

That’s it. Your app and flows upload to Maestro Cloud, tests run on their infrastructure, and results appear in your PR.

What You Get

  • No emulator/simulator management
  • Parallel execution included
  • Video recordings, logs, screenshots
  • SOC 2 compliance (if that matters to you)

What You Pay

$250/device/month. Three parallels = $750/month = $9,000/year.


Option 2: GitHub Actions Self-Hosted Runners

Run Maestro on your own hardware. Zero cloud costs, but you manage the infrastructure.

The Challenge

GitHub’s hosted runners have limitations:

  • Linux runners can run Android emulators, but without hardware acceleration (slow)
  • macOS runners work for iOS simulators, but cost 10x the Linux rate
  • Neither has physical devices

The solution: self-hosted runners on machines you control.

Android on Linux (with KVM)

For Android, you need a Linux machine with KVM virtualization enabled. This rules out most cloud VMs, but works on bare metal or dedicated hosts.

yaml
# .github/workflows/maestro-android.yaml
name: Maestro Android (Self-Hosted)

on: [push, pull_request]

jobs:
  test:
    runs-on: self-hosted  # Your own machine with KVM
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'
      
      - name: Install Maestro
        run: |
          curl -Ls "https://get.maestro.mobile.dev" | bash
          echo "$HOME/.maestro/bin" >> $GITHUB_PATH
      
      - name: Start Android Emulator
        run: |
          # Assumes Android SDK and AVD are pre-configured
          $ANDROID_HOME/emulator/emulator -avd test_avd -no-window -gpu swiftshader_indirect &
          adb wait-for-device
          adb shell input keyevent 82  # Unlock screen
      
      - name: Build APK
        run: ./gradlew assembleDebug
      
      - name: Run Maestro Tests
        run: maestro test .maestro/

iOS on macOS

For iOS simulator testing, you need a macOS machine.

yaml
# .github/workflows/maestro-ios.yaml
name: Maestro iOS (Self-Hosted)

on: [push, pull_request]

jobs:
  test:
    runs-on: self-hosted  # macOS with Xcode installed
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Maestro
        run: |
          curl -Ls "https://get.maestro.mobile.dev" | bash
          echo "$HOME/.maestro/bin" >> $GITHUB_PATH
      
      - name: Install idb-companion
        run: |
          brew tap facebook/fb
          brew install facebook/fb/idb-companion
      
      - name: Start iOS Simulator
        run: |
          DEVICE_ID=$(xcrun simctl list devices available --json | \
            jq -r '.devices[] | .[] | select(.name == "iPhone 15") | .udid' | head -n 1)
          xcrun simctl boot "$DEVICE_ID"
          sleep 30  # Wait for simulator to boot
      
      - name: Build App
        run: |
          xcodebuild -project MyApp.xcodeproj \
            -scheme MyApp \
            -destination 'platform=iOS Simulator,name=iPhone 15' \
            -derivedDataPath build
      
      - name: Run Maestro Tests
        run: maestro test .maestro/

Third-Party Runners

Don’t want to manage your own hardware? Services like BuildJet offer Linux runners with KVM at lower cost than GitHub’s macOS runners.

yaml
jobs:
  test:
    runs-on: buildjet-2vcpu-ubuntu-2204  # KVM-enabled runner

Option 3: Jenkins with Local Devices

Jenkins gives you the most control. You manage everything: the server, the agents, the devices.

Basic Jenkinsfile

groovy
pipeline {
    agent {
        label 'android'  // Agent with Android SDK and connected device
    }
    
    stages {
        stage('Checkout') {
            steps {
                git 'https://github.com/your/repo.git'
            }
        }
        
        stage('Install Maestro') {
            steps {
                sh '''
                    curl -Ls "https://get.maestro.mobile.dev" | bash
                    export PATH="$HOME/.maestro/bin:$PATH"
                    maestro --version
                '''
            }
        }
        
        stage('Build') {
            steps {
                sh './gradlew assembleDebug'
            }
        }
        
        stage('Start Emulator') {
            steps {
                sh '''
                    $ANDROID_HOME/emulator/emulator -avd test_avd -no-window &
                    adb wait-for-device
                    adb shell input keyevent 82
                '''
            }
        }
        
        stage('Run Maestro Tests') {
            steps {
                sh '''
                    export PATH="$HOME/.maestro/bin:$PATH"
                    maestro test .maestro/ --format junit --output test-results.xml
                '''
            }
        }
    }
    
    post {
        always {
            junit 'test-results.xml'
            sh 'adb emu kill || true'
        }
    }
}

Physical Devices with Jenkins

For physical devices, connect them to your Jenkins agent via USB:

groovy
stage('Run on Physical Device') {
    steps {
        sh '''
            # List connected devices
            adb devices
            
            # Install app
            adb install -r app/build/outputs/apk/debug/app-debug.apk
            
            # Run Maestro
            maestro test .maestro/
        '''
    }
}

Parallel Execution with Sharding

Maestro 2.0 introduced sharding for parallel test execution:

groovy
stage('Run Parallel Tests') {
    steps {
        sh '''
            # With 3 connected devices, split tests across all of them
            maestro test .maestro/ --shard-split 3
        '''
    }
}

The --shard-split flag distributes your test flows across N devices. Each device runs a subset of the tests.


The Problem with Self-Hosting

All three DIY options share the same fundamental issue: you manage the infrastructure.

That means:

  • Keeping emulators/simulators updated
  • Managing device connections (USB hubs, network ADB)
  • Handling device failures and reboots
  • Maintaining Maestro CLI versions
  • Dealing with flaky emulators in CI

For Android, emulators in CI are notoriously unreliable. Google’s own guidance recommends using real devices for stable E2E tests.

For iOS, you can’t run Maestro on physical devices at all—not with the open-source version. Maestro only supports iOS simulators. If you need real iPhone testing, you’re back to paying BrowserStack (who runs an outdated fork) or Maestro Cloud. For reporting, see Maestro Test Reports: JUnit, HTML, Allure.


Option 4: Your Own Devices, Managed Infrastructure

What if you could get cloud-like simplicity with self-hosted economics?

That’s what we built DeviceLab to solve.

How It Works

  1. Connect your own physical devices (Android + iOS)
  2. DeviceLab runs Maestro tests on them via peer-to-peer WebRTC
  3. Your app binary and test data never leave your network
yaml
# .github/workflows/devicelab-maestro.yaml
name: Maestro on DeviceLab

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build APK
        run: ./gradlew assembleDebug
      
      - name: Run on DeviceLab
        run: |
          curl -fsSL https://app.devicelab.dev/test-node/${{ secrets.DEVICELAB_KEY }} | sh -s -- \
            --framework maestro \
            --platform android \
            --app ./app/build/outputs/apk/debug/app-debug.apk \
            --tests ./.maestro/

What’s Different

Maestro Cloud Self-Hosted DeviceLab
Infrastructure Theirs Yours (all of it) Yours (devices only)
Devices Theirs Yours Yours
Maestro version Latest You manage Latest
iOS physical devices No No Yes
Setup time Minutes Hours/days Minutes
Monthly cost $250/device $0 + your time $99/device (1st free)

The key difference: DeviceLab runs the latest open-source Maestro on your devices. No outdated forks. No version lag.

And unlike any cloud solution: Maestro works on real iOS physical devices, not just simulators.


Choosing Your Path

Use Maestro Cloud if:

  • Budget isn’t a constraint
  • You don’t own devices
  • You want zero infrastructure management
  • SOC 2 compliance is required

Use self-hosted runners if:

  • You have DevOps capacity to maintain infrastructure
  • You only need Android (emulators are easier than iOS)
  • Budget is tight and time is available

Use Jenkins with devices if:

  • You already have Jenkins infrastructure
  • You have physical devices available
  • You want complete control over the environment

Use DeviceLab if:

  • You own or can buy the devices
  • You need iOS physical device testing (not simulators)
  • You want the latest Maestro without managing infrastructure
  • You want predictable costs without per-minute billing

For a full framework comparison, see Maestro vs Appium 2025.


Sample Flows for Any CI

Whichever CI you choose, your Maestro flows stay the same:

yaml
# .maestro/login.yaml
appId: com.example.app
---
- launchApp
- tapOn: "Sign In"
- tapOn: "Email"
- inputText: "[email protected]"
- tapOn: "Password"
- inputText: "password123"
- tapOn: "Submit"
- assertVisible: "Welcome"
yaml
# .maestro/checkout.yaml
appId: com.example.app
---
- launchApp
- tapOn: "Products"
- tapOn: "Add to Cart"
- tapOn: "Cart"
- tapOn: "Checkout"
- assertVisible: "Order Confirmed"

The flows are portable. The execution environment is what changes.


The Bottom Line

Maestro is free. Running Maestro at scale is where costs appear.

You have options:

  • Pay Maestro Cloud for managed simplicity ($250/device/month)
  • Self-host everything for free (but spend engineering time)
  • Use your devices with DeviceLab for a middle path ($99/device/month, 1st free)

The right choice depends on your budget, your team’s DevOps capacity, and whether you need real iOS devices.


Need Maestro CI/CD on your own devices? DeviceLab runs the latest Maestro on your physical iOS and Android devices—no uploads, no third-party data access. Start free.