Skip to content

Mobile UI testing platform for Android and iOS

Mobile app testing and UI test automation for Android and iOS: run Espresso, XCUITest and Maestro suites on virtual devices provisioned for every run, with the pool sized from your suite's history to target 15 minutes.

What mobile UI testing is

Mobile UI testing drives the app through its user interface, the way a user would: tap, type, scroll and check what is on screen. Espresso, XCUITest and Maestro script those interactions on an Android emulator, an iOS simulator or a device.

Its job is quality assurance at the level users care about: after every change, the product still works end to end. Unit tests prove that functions behave; UI tests prove that sign-in, checkout and every other critical flow still work in the build you are about to ship.

That guarantee is what lets a team change code quickly without trading away quality. When the full suite runs on every pull request, a regression is caught before merge, in the change that caused it, instead of in a nightly run or a user report. UI tests are slower and more sensitive to timing than unit tests, which is why running them on every pull request takes parallel devices and per-test retries.

AI mobile testing: a hermetic check for agent-written changes

Coding agents such as Claude Code, Cursor, Codex and Copilot now produce changes faster than anyone can click through them, and they often touch more than was asked. Many of them can drive a device to check their own work, through MCP servers such as Emu and others.

That check is useful in the inner loop, but it is not new: it is a test on a local, non-hermetic device, with whatever app data, emulator state and backend it happened to have. What worked for decades before LLMs still works after them: a hermetic CI check that runs the full suite on fresh devices for every pull request, no matter who or what wrote the change.

Keep your Espresso, XCUITest or Maestro suite as that check, written against the behaviour you expect rather than generated from the same prompt as the code. Marathon Cloud runs it the same way for a person or an agent: one CLI command that exits with 1 when any test fails and 0 when all pass.

When a test fails, the agent gets something it can act on: --result-file writes a machine-readable summary, --output downloads JUnit XML and videos, and every test has its own device logs. The documentation is published for LLMs at docs.marathonlabs.io/llms.txt, so an agent can look up flags instead of guessing them.

How it works

How a run works on Marathon Cloud

01

Your engineers add one line to the build

The build pipeline hands us the app and its tests, the same files it already produces. Nothing to install, no devices to configure.

build 4m 10s
unit tests 2m 05s
ui tests · marathon cloud 11m 42s
See the command
marathon-cloud run android \
  --application app.apk \
  --test-application appTest.apk
02

We supply and scale the devices

From your test history we work out how many devices it takes to target 15 minutes, spin them up, and tear them down when the run ends. You never buy or maintain one.

2 → 12 devices · finishes in 11m 42s
03

Every change gets a verdict with evidence

Pass or fail, back in the pull request before anyone merges. Failures come with video, logs and screenshots so they are fixed in minutes, not argued about.

LoginTest.signIn 1.2s
CartTest.addItem 0.9s
CheckoutTest.pay 2.1s
CheckoutTest.applyCoupon 3.4s
videologsscreenshot

Frameworks

Marathon Cloud supports native instrumentation testing through Espresso on Android and XCUITest on iOS, as well as cross-platform flows using Maestro. Jetpack Compose UI tests are instrumentation tests and run unchanged on Marathon Cloud (Compose testing docs).

You upload the same app and test binaries your build already produces, with no proprietary SDKs to integrate.

Virtual devices, not a device farm

Every run gets Android emulators and iOS simulators provisioned for that run and destroyed when it ends. Marathon Cloud is not a physical device farm.

These are the same kind of devices your engineers already run UI tests on locally, so with matching OS versions and configuration a failure in CI can be reproduced on a laptop. Tests that depend on real hardware, such as the camera, biometrics or NFC, still belong on a physical device; the questions below list what stays there.

Retries and flaky tests

A failed test is rescheduled on a different device. Tests that pass on a subsequent attempt are reported as flaky, while those that fail every attempt are marked as failed.

Marathon Cloud keeps per-test outcome history and uses it to run preventive retries of recently unstable tests.

CI integration

Marathon Cloud ships an official GitHub Action, a Bitrise step, and a Docker image. It runs from any CI or a developer laptop.

Integrate it into your pipeline to block merges on test failures. You can find complete job examples for GitHub Actions and other platforms in the documentation.

Reproducible by construction

Every run starts from a clean state: we provision a fresh emulator or simulator for the run and destroy it when the run ends. That makes the environment hermetic per run, with no device lab to maintain.

Tests execute in batches, and tests in the same batch share the app process in sequence, as they do locally. If a test leaks state, the batching docs describe the isolated option: "--isolated sets the batch size to one, so no test shares a batch with another."

Because environments are ephemeral, you can shard the full suite across many devices on every pull request, ending the reliance on nightly regression runs.

Reports

Every run produces an Allure report, JUnit XML, and a Marathon HTML timeline.

Each test also gets its own screen recording and device logs, which you can fetch with marathon-cloud download --glob.

Pricing

Pricing is $2.00 per hour for Android virtual devices and $3.00 per hour for iOS virtual devices, billed per second and invoiced monthly.

For example, a suite with 120 minutes of total test time runs on 8 devices for about 15 minutes: 2 device-hours, costing $4.00 on Android or $6.00 on iOS.

Start today, size nothing upfront

Getting started is self-serve: sign up, create an API key in the console, and run one CLI command. Your Starter tier includes 50 free device hours with no credit card required.

Because the device pool is sized per run, there is no concurrency to forecast. You do not need to buy parallel slots upfront.

For procurement-driven teams, Enterprise plans offer volume pricing, annual terms, SAML SSO, and IP allowlisting.

Frequently asked

Which frameworks are supported?

Espresso/instrumentation on Android, XCUITest on iOS, and Maestro on both platforms.

Are these real devices?

No. Marathon Cloud runs Android emulators and iOS simulators, provisioned fresh for every run and destroyed when it ends. That is what makes a 15-minute target for any suite size and pay-per-second pricing possible, and it is the same environment your engineers already use to run UI tests locally. Physical hardware still matters for what cannot be emulated yet: a real camera, fingerprint and face sensors, NFC and Bluetooth radios, manufacturer skins, and real-hardware performance numbers. Most teams keep a small physical lab for those and move the rest to Marathon Cloud.

How long does a run take?

The scheduler sizes the device pool from the suite's historical duration, targeting 15 minutes. This is a target, not a hard limit.

How much does it cost?

Pricing is $2.00 per hour for Android and $3.00 per hour for iOS, billed per second based on virtual device time used.

Which CI systems work?

There is an official GitHub Action, a Bitrise step, and a Docker image. CircleCI is documented, and the CLI runs from any CI or a laptop.

Start with 50 free
device hours

Run your real suite today. No credit card, no sales call required.