Quick answer
A Bitrise workflow can start an Expo Simulators session, install your iOS Simulator build, drive the app with agent-device, and save screenshots and recordings as build artifacts. Store an Expo robot user's access token as a Bitrise Secret named EXPO_TOKEN. Run the eas simulator commands in Script steps on a Linux stack, and stop the session in a step that always runs.
With Expo Simulators, the iOS Simulator runs on EAS. The Bitrise machine does not need macOS or a local simulator, so this workflow runs on a Linux stack.
Set up the Expo token
- On expo.dev, create a robot user on the account that owns the project, with the Developer role or higher. Developer is the lowest role that can start and stop sessions.
- Copy its access token. Robot users cannot sign in and work only with a token.
- In Bitrise, open Workflows, select Secrets, and add a project level Secret with the key
EXPO_TOKEN.
EAS CLI reads EXPO_TOKEN from the environment, so the job never runs eas login. Bitrise shows [REDACTED] in the build log in place of the value.
Get a build
Create the build before the session starts. Add a profile that targets the iOS Simulator to eas.json:
Run eas build --platform ios --profile remote-device --non-interactive, and put the build ID in EAS_BUILD_ID. To install the newest finished build for your native code, use --build-fingerprint with the hash that eas fingerprint:generate --platform ios --build-profile remote-device --non-interactive prints. For a build made elsewhere, such as on Bitrise, pass a URL to a .tar.gz of the .app with --application-archive-url.
Add the workflow to bitrise.yml
Replace <build-id> with your build ID, and com.example.app with the ios.bundleIdentifier that npx expo config --json prints.
What does each step do?
- Git Clone checks out the repository, because the start command needs the app config with the EAS project ID.
- The start step checks access first.
simulator:availabilityexits with code 0 even without access, sojq -efails the step whenavailableisfalse. - The drive step runs agent-device through
simulator:exec, which loads the connection details of the session. agent-device downloads screenshots and recordings to the path you pass. - The stop step and Deploy to Bitrise.io run even after a failed step. A build that ends does not stop the session, so the stop step needs
is_always_run: true. Stopping a stopped session succeeds. Deploy uploads the files in$BITRISE_DEPLOY_DIRto the Artifacts tab of the build.
Each Script step runs in $BITRISE_SOURCE_DIR, so the later steps find the .env.eas-simulator file. The Ubuntu stack includes jq and Node.js 22, and agent-device needs Node.js 22.12 or later.
For Android, build an APK and use --platform android. Android support is still in development, so some features that work on iOS may not work on Android yet.
Keep tokens out of the build log
The start command writes controller tokens to .env.eas-simulator. These tokens are not Bitrise Secrets, so Bitrise does not redact them.
- Do not print the file or the
--jsonoutput of the start command. Both contain connection details. - Do not copy the file to
$BITRISE_DEPLOY_DIR. Deploy to Bitrise.io uploads every file in that directory. - Leave
set -xout of your scripts. The default Script content turns it on, and the Bitrise Secrets guide says to remove it. - Add .env.eas-simulator to .gitignore.
Let an agent set it up
If an agent writes the workflow or runs the session for you, have it load these Expo Skills first:
expo-overview: the entry point that routes the agent to the right Expo skill.eas-simulator: the currenteas simulatorcommands, session types, and cleanup steps.
Install them:
- Claude Code:
claude plugin install expo@claude-plugins-official - Codex:
codex plugin add expo@openai-curated - Cursor and other agents:
npx skills add expo/skills
The full list is at docs.expo.dev/skills.
Try it
Expo Simulators is in a limited beta release. The docs on running sessions in CI also cover the REST API and parallel sessions.
Verified on 20 October 2026.