Skip to content

Published · Updated

Cloud phones from CI ​

Run your Android tests on a fresh cloud phone from GitHub Actions, GitLab, Jenkins or any script: start a phone, install your APK, run a test, fetch the reports and stop the phone. You pay £0.02 a minute from your prepaid minutes, as in the browser, and a phone that started is charged at least 10 minutes.

1. Make an API token ​

Your account → API tokens → Make token. Give it a name, an expiry (7, 30 or 90 days, or a year) and, if you like, its own monthly spending cap and the most phones it may run at once. Your account's spending limit always applies too.

The token is shown once: put it in your CI's secrets straight away (on GitHub: Settings → Secrets and variables → Actions → New repository secret, named BENCHFLEET_TOKEN). We keep only a fingerprint of it.

A token can only start, use and stop its own cloud phones. It cannot buy minutes, change your account or spending limit, or reach phones you started in the browser or the app. Revoke it on the same page and it stops working at once; the page also lists what each token did in the last 90 days, including what was refused.

2. The HTTP API ​

Everything goes to https://benchfleet.com/api/cloud/v1 with the header Authorization: Bearer <token>:

RequestWhat it does
GET /offersAndroid versions, screen sizes, prices
GET /balanceyour minutes, spending limit, and this token's spending this month
POST /rentals {"offer_id": "bf-android-17", "max_minutes": 30, "screen": "phone", "root": false}starts a phone (201, its rental)
GET /rentals, GET /rentals/IDthis token's phones and their state: requested, starting, ready, then released or failed
POST /rentals/ID/extend {"minutes": 15}more time
POST /rentals/ID/releasestops the phone
POST /rentals/ID/connectonce ready: the phone's address and a one-use pass for 60 seconds
bash
curl -s -X POST https://benchfleet.com/api/cloud/v1/rentals \
  -H "Authorization: Bearer $BENCHFLEET_TOKEN" -H "Content-Type: application/json" \
  -d '{"offer_id": "bf-android-17", "max_minutes": 30}'

Refusals carry a code: insufficient_balance (buy minutes), spending_limit (your account's limit), token_spending_limit and token_phone_limit (the token's caps), at_capacity (every phone is busy: try again in a few minutes; nothing was charged), rate_limited (with Retry-After).

connect opens the phone itself: a WebSocket to the phone's server with the same commands the browser uses (install, files, shell, log).

Coming soon: a GitHub Action and a command-line tool ​

They are not available yet; this page will say how to install them once they are. Both will do the whole job in one step: start a phone, install your APKs, run your test command (such as am instrument) in the phone's shell, fetch report files and the phone's log, and always stop the phone, passed or failed. The step or command will fail when your test fails, so your CI shows it like any other test.

Until then, the HTTP API above starts and stops phones from any CI.

What goes where ​

Your APKs, commands, test output and logs go from your CI straight to the server your phone runs on, and are deleted with the phone. Our account service sees only that a phone was started, for how long, and that a connection was made; never what you install or run. The phone keeps an audit of what was done on it under your account while it runs, deleted with the phone.

When the app is the better choice ​

The app runs workflows and AI agents on cloud phones as on your own phones (Workflows). Your Maestro, Espresso and Appium tests run in the app as test suites, with controlhub-ci for CI, on the phones attached to your computer; cloud phones are not supported there yet. Without the app, a cloud phone takes shell commands such as am instrument.