Skip to the content

Writing flows

A flow is one journey through your app, written in Maestro's YAML: what to tap, what to type, and what should be on the screen. Trailcam runs it as written on every platform your project has.

The shape of a flow

A flow has a short config section, a line with ---, then its steps:

appId: ${APP_ID}
name: Checkout
tags:
  - checkout
env:
  # A test card your payment provider accepts.
  CARD_NUMBER: "4242 4242 4242 4242"
---
- launchApp:
    clearState: true
- tapOn: "Shop"
- tapOn: "Add to basket"
- tapOn: "Checkout"
- tapOn: "Card number"
- inputText: ${CARD_NUMBER}
- tapOn: "Pay now"
- extendedWaitUntil:
    visible: "Thanks for your order"
    timeout: 15000

appId: ${APP_ID} is required. Trailcam fills ${APP_ID} with the app ID of the build each run uses, so one flow runs on your iOS and Android builds alike.

Start from a template (blank, sign up, sign in, checkout or onboarding), describe the journey and let Trailcam AI write it, or let Trailcam AI find your journeys in a new build and write the ones you choose.

Variables

Values a flow needs, like a test account's password, go in its env: section and are used as ${NAME}:

env:
  PASSWORD: Trailcam-check-2468
---
- tapOn: "Password"
- inputText: ${PASSWORD}

Variables are passed to the device privately. A run's steps show them by name, and Trailcam AI reads them only by name (what it sees). The device's own message can quote a value a step used, so use accounts made for testing, never a real customer's.

Sign-ups that email a code

Every run has an email address of its own, made for that run: ${TRAILCAM_EMAIL}. Sign up with it, and the step runScript: trailcam/email-code.js waits for the email your app sends and puts the code in it in ${output.emailCode}, for the next step to type:

- tapOn: "Email"
- inputText: ${TRAILCAM_EMAIL}
- tapOn: "Continue"
# Waits for your app's email, and reads the code in it.
- runScript: trailcam/email-code.js
- tapOn: "Code"
- inputText: ${output.emailCode}
- tapOn: "Confirm email"
  • It waits a minute, or as long as you say, up to 5 minutes. A code of a shape it doesn't find can be named with a pattern:

    - runScript:
        file: trailcam/email-code.js
        env:
          TIMEOUT: 120
          PATTERN: "[A-Z]{3}-\\d{3}"
  • It finds the code near words like "code" or "verify", or on a line of its own: 4 to 8 digits, or capitals and digits like K7Q-2M9, never a price, a date or a phone number.

  • A link too: when the email asks you to confirm or sign in by a link, it's in ${output.emailLink}.

  • The run's page shows what arrived: each email's sender, subject and words, the code found, and whether the flow typed it.

  • Each run's address is new, so a sign-up never meets the last run's account. It takes mail from the moment the run is queued until 30 minutes after it ends, at most 20 emails of up to 1 MB, and turns away anything else. Emails are kept with the run's recording and removed with it, and shared links leave them out.

  • Codes by text message can't be read yet.

Describe it and Find my journeys write sign-ups like this themselves.

Commands

Trailcam runs Maestro 2. The editor suggests every command it can run as you type:

WhatCommands
The applaunchApp, stopApp, killApp, clearState, clearKeychain
Tapping and gesturestapOn, doubleTapOn, longPressOn, swipe, scroll, scrollUntilVisible, back
TypinginputText, inputRandomEmail, inputRandomPersonName, inputRandomNumber, inputRandomText, eraseText, pressKey, pasteText, copyTextFrom, setClipboard, hideKeyboard
Checking the screenassertVisible, assertNotVisible, assertTrue, assertDarkMode, assertLightMode
Checking with AIassertWithAI, assertNoDefectsWithAI, extractTextWithAI
WaitingextendedWaitUntil, waitForAnimationToEnd
The deviceopenLink, setLocation, travel, setAirplaneMode, toggleAirplaneMode, setDarkMode, toggleDarkMode, setOrientation, setPermissions
Pictures and recordingstakeScreenshot, startRecording, stopRecording
LogicevalScript, runFlow (with its steps inline), repeat, retry, runScript: trailcam/email-code.js (above)

The AI commands are answered by Trailcam's own models, with no key of your own. Each plan includes a number of them a month; see Trailcam AI.

What flows can't do on Trailcam

A few Maestro features need files or a network that a hosted device doesn't have. The editor marks them as errors, and a flow with errors doesn't run until they're fixed:

  • addMedia and assertScreenshot, which read files from your computer, and runScript with any script but Trailcam's own (trailcam/email-code.js).
  • runFlow or retry pointing at another file: put the steps inline with commands: instead.
  • Screenshot and recording names that are paths, like ../shot.
  • Web requests from scripts (Maestro's http).
  • Links to your own computer or private network, like localhost, 10.0.2.2 or 192.168.….
  • YAML aliases (*name).

Warnings never stop a flow from running.

Devices

Each run starts on a clean device, discarded afterwards, so nothing one run does carries over to the next. Runs use each platform's default device, an iPhone 17 or a Pixel 8, unless they name others:

  • In the app, the arrow beside Run chooses the devices, and a system for each. Run remembers your choice for that flow, in this browser.
  • From CI, --device (or the Action's devices), as the command-line tool shows.
  • A production check runs on one device for each platform, chosen when you add or change it.
Device--deviceSystems
iPhone 17 (the default)iphone-17iOS 26.5
iPhone 17 Pro Maxiphone-17-pro-maxiOS 26.5
iPad (A16)ipad-a16iPadOS 26.5
iPad Pro 13-inch (M5)ipad-pro-13-inch-m5iPadOS 26.5
Pixel 8 (the default)pixel-8Android 14 (the default), Android 16 and 11
Pixel Tabletpixel-tabletAndroid 16
Pixel 9 Pro Foldpixel-9-pro-foldAndroid 16

A run counts once on any device. An iPhone app runs on an iPad as iPadOS runs it, and an app built only for iPad runs only on the iPads. A foldable runs in the position it starts in: a flow can't fold or unfold it.

Limits

  • A flow's run can take up to 15 minutes. Long runs count once for every 3 minutes of the flow; see Runs and results.
  • A flow can have up to 1,000 steps and 100,000 characters, and its name up to 80 characters.

In the editor

  • ⌘ S (or Ctrl S) saves. If a teammate saved the flow while you were editing, Trailcam asks first: load their version, or save yours over it.
  • Ctrl Space suggests commands, F8 goes to the next problem, and quick fixes correct the common ones.
  • When Trailcam AI suggests a change, Run to check runs the flow as it is in the editor, unsaved, on the build that failed. It's a draft: it never becomes the flow's latest result.