# How to Integrate Maestro with CI/CD Pipelines: Complete Technical Guide

> Learn how to integrate Maestro with CI/CD pipelines for seamless automated testing. This guide covers headless execution and artifact collection for your mobile app.

- Repository: [Maestro/Maestro](https://github.com/mobile-dev-inc/Maestro)
- Tags: how-to-guide
- Published: 2026-03-20

---

**Maestro automatically detects CI environments via environment variables and disables interactive prompts, enabling headless test execution with the `MAESTRO_CLI_NO_ANALYTICS=true` setting and `--flatten-debug-output` flag for deterministic artifact collection.**

Maestro is a command-line UI testing framework for mobile applications designed to run seamlessly in automated build pipelines. According to the mobile-dev-inc/Maestro source code, the CLI includes built-in CI detection logic that suppresses UI-only features and adapts output for machine consumption, making it straightforward to integrate Maestro with CI/CD pipelines across GitHub Actions, CircleCI, GitLab CI, Jenkins, and custom runners.

## CI Environment Detection in Maestro

Maestro identifies CI environments automatically through the `CiUtils` class located in [`maestro-cli/src/main/java/maestro/cli/util/CiUtils.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/util/CiUtils.kt). The `CiUtils.getCiProvider()` function (lines 5-19) scans for known CI provider environment variables:

- `GITHUB_ACTIONS`
- `CIRCLECI`
- `TEAMCITY_VERSION`
- `GITLAB_CI`
- `JENKINS_HOME`

When detected, Maestro disables progress bars, suppresses interactive prompts, and routes output appropriately for headless execution.

### Overriding CI Detection for Custom Runners

If your CI provider is not in the built-in list, force detection by setting the `MDEV_CI` environment variable:

```bash
export MDEV_CI=your-ci-name

```

As implemented in [`CiUtils.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/CiUtils.kt), this override returns your custom identifier as the provider name, ensuring consistent behavior across proprietary or self-hosted CI systems.

## Essential Environment Variables

Two key environment variables control CI-specific behavior:

**`MAESTRO_CLI_NO_ANALYTICS`** – Set this to `true` to disable the analytics consent dialog. According to the source in [`maestro-cli/src/main/java/maestro/cli/analytics/Analytics.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/analytics/Analytics.kt), this prevents the interactive prompt that would otherwise halt execution in non-interactive shells.

**`MDEV_CI`** – Forces CI mode detection when running on custom infrastructure or unsupported CI platforms.

## CLI Flags for CI-Friendly Output

The `TestCommand` class in [`maestro-cli/src/main/java/maestro/cli/command/TestCommand.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/command/TestCommand.kt) exposes flags that streamline artifact collection:

**`--flatten-debug-output`** (lines 158-161) – Writes all test artifacts directly into a single folder without timestamps or subdirectories, simplifying artifact upload configurations in CI systems.

**`--format junit`** – Produces JUnit XML reports that most CI platforms can parse for test result visualization.

**`--debug-output <path>`** – Specifies a deterministic location for screenshots, logs, and other debug artifacts.

## Step-by-Step Integration

Follow this pattern to add Maestro to any CI pipeline:

1. **Install the Maestro CLI** using the official installer or by extracting the pre-built distribution:

```bash
curl -fsSL "https://get.maestro.mobile.dev" | bash

```

2. **Configure environment variables** to suppress interactive elements:

```bash
export MAESTRO_CLI_NO_ANALYTICS=true

```

3. **Execute tests** with CI-optimized flags:

```bash
maestro test path/to/flow.yaml \
  --flatten-debug-output \
  --output ./maestro-output \
  --format junit

```

4. **Upload artifacts** to your CI platform's storage for failure analysis.

## CI/CD Platform Configuration Examples

### GitHub Actions

The mobile-dev-inc/Maestro repository uses this pattern in [`.github/workflows/test-e2e.yaml`](https://github.com/mobile-dev-inc/Maestro/blob/main/.github/workflows/test-e2e.yaml):

```yaml
name: Maestro CI Demo

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 17
      
      - name: Install Maestro
        run: |
          curl -fsSL "https://get.maestro.mobile.dev" | bash
          echo "$HOME/.maestro/bin" >> $GITHUB_PATH
      
      - name: Run Maestro tests
        env:
          MAESTRO_CLI_NO_ANALYTICS: true
        run: |
          maestro test ./e2e/workspaces/demo_app \
            --flatten-debug-output \
            --output ./maestro-output \
            --format junit
      
      - name: Upload test results
        uses: actions/upload-artifact@v4
        with:
          name: maestro-test-results
          path: ./maestro-output

```

### CircleCI

For CircleCI, use the `store_artifacts` step after running Maestro:

```yaml
version: 2.1

jobs:
  maestro-test:
    docker:
      - image: cimg/android:2024.01
    steps:
      - checkout
      - run:
          name: Install Maestro
          command: |
            curl -fsSL "https://get.maestro.mobile.dev" | bash
            echo 'export PATH="$HOME/.maestro/bin:$PATH"' >> $BASH_ENV
      - run:
          name: Run tests
          command: |
            export MAESTRO_CLI_NO_ANALYTICS=true
            maestro test ./flows --flatten-debug-output --output ./results
      - store_artifacts:
          path: ./results
          destination: maestro-output

```

### GitLab CI

GitLab CI requires explicit artifact path definitions:

```yaml
maestro-tests:
  image: ubuntu:latest
  before_script:
    - apt-get update && apt-get install -y curl unzip openjdk-17-jdk
    - curl -fsSL "https://get.maestro.mobile.dev" | bash
    - export PATH="$HOME/.maestro/bin:$PATH"
  script:
    - export MAESTRO_CLI_NO_ANALYTICS=true
    - maestro test ./app/flows --flatten-debug-output --output ./maestro-output --format junit
  artifacts:
    when: always
    paths:
      - ./maestro-output
    reports:
      junit: ./maestro-output/report.xml

```

## Summary

- **Automatic Detection**: Maestro identifies CI environments via `CiUtils.getCiProvider()` in [`maestro-cli/src/main/java/maestro/cli/util/CiUtils.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/util/CiUtils.kt), checking for variables like `GITHUB_ACTIONS` and `CIRCLECI`.

- **Non-Interactive Mode**: Set `MAESTRO_CLI_NO_ANALYTICS=true` to disable analytics prompts and ensure headless execution.

- **Deterministic Output**: Use `--flatten-debug-output` from [`TestCommand.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/TestCommand.kt) to write artifacts to a single directory without timestamps, simplifying CI artifact collection.

- **Custom CI Support**: Export `MDEV_CI=your-ci-name` to force CI detection on unsupported or self-hosted platforms.

- **JUnit Integration**: Add `--format junit` to generate XML reports compatible with GitHub Actions, GitLab CI, Jenkins, and other platforms.

## Frequently Asked Questions

### How does Maestro know it is running in a CI environment?

Maestro checks for standard CI provider environment variables in the `CiUtils.getCiProvider()` function. Located in [`maestro-cli/src/main/java/maestro/cli/util/CiUtils.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/util/CiUtils.kt) (lines 5-19), this function maps variables like `GITHUB_ACTIONS`, `CIRCLECI`, and `GITLAB_CI` to normalized provider names. When any are detected, the CLI automatically disables progress bars and interactive prompts.

### What happens if my CI provider is not supported?

Set the `MDEV_CI` environment variable to any non-empty value. As implemented in [`CiUtils.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/CiUtils.kt), this forces the CLI into CI mode regardless of the underlying platform. This ensures that UI-only features remain disabled and output remains machine-readable on custom runners or proprietary CI systems.

### Why is my CI pipeline hanging at the analytics prompt?

Without the `MAESTRO_CLI_NO_ANALYTICS=true` environment variable, Maestro attempts to prompt for analytics consent via stdin. In non-interactive CI shells, this blocks indefinitely. The [`Analytics.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/Analytics.kt) file checks this variable to skip the prompt, allowing execution to proceed immediately.

### How do I collect test artifacts consistently across CI runs?

Use the `--flatten-debug-output` flag available in [`TestCommand.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/TestCommand.kt) (lines 158-161). This writes screenshots, logs, and other debug files directly into your specified output directory without timestamped subfolders. Combined with `--output ./maestro-output`, this creates a stable path for CI artifact uploaders to collect results after every test run.