Your test matrix, without a device lab.
Run your app on the phones your users actually own: 150+ models from 11 brands, Android 10 to 17. Reset to a clean snapshot before every run, clone for parallel runs, and reach each phone through ADB and the API.
The phones your users own.
Budget Galaxy A-series to this year’s Pixels, each model built from a snapshot of the real device and measured against it before anyone can launch it.
Layouts on real screens
Resolution, density and display features of the real panel, so layouts, screenshots and visual checks match the device.
Graphics as shipped
GPU vendor and renderer strings, OpenGL and Vulkan versions of the real chipset, so your app sees the hardware it expects.
Google Play inside
Google Play services and Play Store installed as on a phone, for apps that need them to sign in, pay or update.
A clean phone for every run.
Get a phone to the state your tests expect, snapshot it, and put it back there before every run. When one phone is not enough, clone more from the same snapshot.
- Restore before every runOne call rolls the phone back to the clean snapshot, so every run starts from the same state.
- Clone for parallel runsNew phones from the same snapshot, each with its own identity, to split a suite across devices.
- Nightly backupsSnapshot phones every night on a schedule; stopped phones cost nothing while they wait.
ADB, when you need to go lower.
Every phone has its own ADB relay. It stays off until you open it for your IPs and for a set time, and it refuses what could damage the device.
- Off until you turn it onEnable it per phone with an allow-list of up to 20 IPs or CIDRs.
- Expires by itself24 hours by default, up to 7 days; idle sessions close after 30 minutes.
- A one-time login codeShown once; wrong codes lock the relay. Up to 3 sessions per phone, push and pull up to 2 GiB per session.
- Dangerous services refusedroot, remount, disable-verity, reverse, reboot, tcpip, usb, jdwp, sideload and restore are always refused. Every session is logged.
# 1. open ADB on qa01 for your IP, 24 hours (dashboard or API) curl -X POST https://api.clousd.com/v1/devices/qa01/adb \ -H "Authorization: Bearer $CLOUSD_KEY" \ -H "Content-Type: application/json" \ -d '{"allow_ips":["203.0.113.7"],"ttl_hours":24}' # → connect command and a one-time code, shown once # 2. connect and sign in with the code adb connect $HOST:$PORT adb -s $HOST:$PORT shell clousd-login $CODE # 3. work as usual adb -s $HOST:$PORT install app-debug.apk adb -s $HOST:$PORT shell pm list packages | grep example adb -s $HOST:$PORT logcat -d | tail -n 50
Plug it into CI.
Everything a test run needs is a REST call on https://api.clousd.com/v1. Long operations answer 202 with a job to poll, and a key can be limited to the test phones and to read or control.
API=https://api.clousd.com/v1 AUTH="Authorization: Bearer $CLOUSD_KEY" # reset qa01 to its clean snapshot and wait for the job JOB=$(curl -s -X POST -H "$AUTH" \ $API/devices/qa01/snapshots/v20/restore | jq -r .job.id) until [ "$(curl -s -H "$AUTH" $API/jobs/$JOB | jq -r .job.state)" \ != running ]; do sleep 3; done # install this build and open it curl -s -H "$AUTH" -F apk=@app-release.apk $API/devices/qa01/apk curl -s -H "$AUTH" -H "Content-Type: application/json" \ -d '{"op":"open_app","package":"com.example.app"}' \ $API/devices/qa01/action # keep the evidence curl -s -H "$AUTH" $API/devices/qa01/screenshot -o after.png curl -s -H "$AUTH" $API/devices/qa01/logs > logcat.txt
# the same steps on four phones at once, 0–5 s apart curl -X POST https://api.clousd.com/v1/groups -H "$AUTH" \ -H "Content-Type: application/json" -d '{ "phones": ["qa01", "qa02", "qa03", "qa04"], "steps": [ {"op": "open_app", "package": "com.example.app"}, {"op": "wait", "seconds": 3}, {"op": "if_text", "text": "Sign in", "skip": 1}, {"op": "screenshot"} ], "stagger": [0, 5] }' # 202 → progress per phone in job.output
# a key created with a webhook URL receives signed events POST https://ci.example.com/clousd X-Clousd-Signature: 9f2c…e41a {"event": "job.finished", "ts": …, "phone": "qa01", "job": {…}} # events: job.finished · health.problem · health.resolved # signature: HMAC-SHA256 of the body · 3 delivery attempts
Watch it. Test it anywhere.
See the run as it happens, and move a phone to another country without leaving your desk.
The stream steps down the quality ladder when your connection does, and back up when it recovers. Multi-view shows many screens at once, and Sync mirrors your input to the phones you select.
Questions, answered.
Something else? Write to support and a person answers, usually within a working day.
Can I choose the exact Android version?
Yes, per phone. Each model in the catalog lists the versions you can launch today, Android 10 to 17 across the catalog. Android 12–14 are the base price; Android 15 costs 10% more, Android 16 and 17 cost 25% more.
How do I reset a phone between test runs?
Snapshot it once in a clean state, then restore that snapshot before each run. It is one API call that answers 202 with a job to poll at /v1/jobs/{id}.
Can I run a suite in parallel?
Yes. Clone new phones from the clean snapshot, each with its own identity, and split the suite across them, or run the same steps on a whole group with a random stagger.
Is ADB open to the internet?
No. ADB is off by default. You open it per phone for an allow-list of up to 20 IPs or CIDRs and for a set time (24 hours by default, up to 7 days), sign in with a one-time code, and every session is logged.
Can I install my own APK?
Yes: upload it in the dashboard, send it to POST /v1/devices/{id}/apk, or adb install it through the relay.
Can I test how my app behaves in another country?
Yes. Give the phone an exit in that country and its time zone, language, keyboard, store and SIM country follow. Pick the region closest to your team so the screen and ADB stay quick.
Put your app on a real model in a minute.
- The first 30 minutes are free, no card.
- Pick a model and an Android version.
- Install your build and start testing.