Skip to the content

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.apk

Commands

trailcam run --project <id> --build <path or ID> [--build …] [options]
trailcam upload <path> --project <id>
trailcam devices

run 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

OptionWhat 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-waitStart 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, --titleWhere 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-tablet

Every 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 .app folder (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

CodeMeaning
0Every run passed (or, with --no-wait, the runs started).
1A flow failed, or has errors and didn't run.
2Trailcam couldn't finish: a run couldn't run, was stopped, or results didn't come in time.
64Something 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.