Command-line tool
trailcam uploads the builds your CI made, runs the project's flows on them, waits for the results and fails the job
if a flow fails. It needs Node 20.12 or later.
npx --yes @trailcam/cli@1 run --project <id> --build app/build/outputs/apk/debug/app-debug.apkCommands
trailcam run --project <id> --build <path or ID> [--build …] [options]
trailcam upload <path> --project <id>
trailcam devicesrun uploads each build (or uses one uploaded earlier, by its ID), runs the flows and waits. upload only uploads,
and prints the build's ID for a later run. devices lists the devices flows can run on, as --device names them;
it needs no project or key.
Options
| Option | What it does |
|---|---|
--project <id> | The project's ID, from its CI tab. Or TRAILCAM_PROJECT. |
--build <path or ID> | A build to run on. Repeat it for the other platform. |
--flow <name> | Run only this flow. Repeat it for more. Without it, every flow runs. |
--device <device> | Run on this device; repeat it for more. See Devices. |
--no-wait | Start the runs and finish, without waiting for the results. |
--timeout <minutes> | How long to wait for results (default 30). The runs carry on afterwards. |
--commit, --branch, --pull-request, --repository, --title | Where the runs come from, when your CI doesn't say. Or TRAILCAM_COMMIT and so on. |
The tool reads the commit, branch, pull request and repository from GitHub Actions, GitLab, Bitrise, CircleCI, Codemagic, Xcode Cloud and EAS Build. Outside CI, it reads your local git checkout. If CI cancels the job, the tool stops its runs before it exits.
Devices
Without --device, each build runs on its platform's default device: an iPhone 17 and a Pixel 8. To run on others,
name each one: a model from trailcam devices, and, for a system other than the model's default, its version
(model=pixel-8,os=16, or pixel-8,os=16). A version can be written as people know it (16, 26.5, or 26 for
the newest iOS 26) or as Android's API level (36, API 36, android-36). At most 10 devices a run.
npx --yes @trailcam/cli@1 run --project <id> --build app-debug.apk \
--device pixel-8 --device model=pixel-8,os=16 --device pixel-tabletEvery flow runs once on each device, and each run counts once. A build no device is named for runs on its platform's default. A device the tool doesn't know, or one for a platform there's no build for, stops it before any run starts (after uploading the builds, which the next run can use). The devices table lists them all.
Signing in
- A CI key: make one on the project's CI tab and add it to your CI's secrets as
TRAILCAM_KEY. - GitHub Actions, with no key: link the repository and give the job
id-token: write. See Running from CI.
Builds
- Android: an APK built for emulators (x86_64, or universal).
- iOS: a simulator build: the
.appfolder (the tool zips it) or a zip of it.
The tool checks each build before uploading it, with the same reader Trailcam uses, so a wrong file is explained in seconds rather than after an upload.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Every run passed (or, with --no-wait, the runs started). |
| 1 | A flow failed, or has errors and didn't run. |
| 2 | Trailcam couldn't finish: a run couldn't run, was stopped, or results didn't come in time. |
| 64 | Something to fix in how it's run: a missing key, a build it can't run, a flow it can't find. |
In GitHub Actions
Use the Trailcam action, which runs this tool. Run directly, the tool also sets the step's outputs, adds a summary to the job's page, and marks each failed flow with an annotation.
Behind a proxy
Xcode Cloud sends everything through a proxy (HTTPS_PROXY). The tool follows it on Node 22.21 or later.