Skip to main content
qawolf runner drives a browser, an Android device, or an iOS device hosted by QA Wolf. Nothing runs on your machine. You launch a runner, run a flow on it, then act on its screen and read what it shows. Unlike qawolf flows run, this works for iOS flows.
Sign in with qawolf auth login, or set QAWOLF_API_KEY. See Authenticate. Run the commands from a directory that holds a flow file and a package.json.

Launch a runner

1
Launch a runner under an id you choose, and pick what it runs with --name: ios, android, or playwright for a browser.
The id is yours to pick. Launching an id that is already running reconnects to that runner instead of starting a second one. Launching it with a different --name still attaches to the existing runner. To change what it runs, terminate it first or use a new id. The CLI stores the runner as this directory’s default, so later commands reach it without --runner.The command prints a URL. The page shows the runner’s screen live to anyone in your workspace.
2
Run a flow on the runner:
On an Android or iOS runner, the first run starts the device session, so this step is required even if you only want to drive the device by hand. Until then, screenshot, act and inspect exit with code 2. A browser runner’s screen starts at launch. The flow’s target has to match what the runner runs. run sends the flow file, the files it imports, and your package.json. --follow waits for the run to finish and exits with code 1 if it did not pass.
3
Drive and inspect the runner with the commands in the sections below. When you’re done, terminate it:
qawolf runner list shows the runners running in your workspace. A runner that sits idle for too long times out, and commands that target it exit with code 8.

Drive a mobile device

A mobile runner has a touchscreen, so it takes its own actions through qawolf runner act:
  • tap — touches a point (--x, --y) or the element --selector names.
  • swipe — moves in a straight line from --from x,y to --to x,y. --duration-ms sets how long it takes, up to 10000. A slow swipe scrolls and a fast one flings.
  • fill — replaces the value of the field --selector names with --text. --text "" clears it.
  • type — types --text into whatever the last tap focused.
--selector takes XPath by default. Pass --strategy ios-predicate or --strategy shadow for the other selector types. Coordinates are pixels on the runner’s screenshot. Examples:
Browser actions such as click, drag, scroll, and navigate fail on a mobile runner with action-not-supported-on-mobile. Use tap and swipe instead. To send up to ten steps in one request, pass them to qawolf runner actions as a JSON array. The steps run back to back, so batch only steps whose targets are on the screen you last saw.

Inspect a mobile device

qawolf runner inspect reads one thing off the device’s Appium session and prints it to stdout:
  • session — whether the Appium session is ready, and why not if it isn’t.
  • contexts — the WebView contexts available, and which one is current.
  • page-source — the current context’s page source, as a tree. --context reads another context.
  • elements — the elements at a point (--x, --y), carrying some text (--text, with --partial for a partial match), or matching a selector (--selector, with --strategy).
Examples:
Check a selector with inspect elements --selector before you tap or fill with it. inspect element-html and inspect page-html work on a browser runner only. inspect variable --name <name> prints a top-level variable from the running flow on either kind of runner.

Take a screenshot

qawolf runner screenshot saves a JPEG of the runner’s screen:
To act and capture the result in one call, pass --screenshot to act or actions:
A runner bills while it’s up, so terminate it when you’re done. Android and iOS runners need mobile testing on your plan. Without it, launch exits with code 7.
Last modified on October 15, 2026