Skip to content
Everframe Docs
Documentation

Try on device

Open the reported build on a live device, right next to the steps that broke it.

Updated

Try on device runs your app on a live device inside the dashboard: an iOS or tvOS simulator, an Android or Android TV emulator, or a Roku. Open a report or a crash, choose Try on device, and Everframe installs the build that best matches the report, streams the device to your browser, and shows the reproduction steps beside it. You drive the device with your mouse and keyboard. Nothing installs on your machine.

It needs one thing from you: a runnable build uploaded from CI. Source maps and native symbols map crash frames, but they cannot launch an app, so Try on device uses a separate upload with the same credentials.

Supported targets

SDKRunnable targets
iOSiOS, tvOS
AndroidAndroid phone and tablet, Android TV
React Native (incl. Expo)iOS, tvOS, Android, Android TV
Flutter, KMPiOS, Android
RokuRoku
React, Web, Vega OSNot supported; there is no device app.

Each target takes one package type:

--platformPackage
android, android-tvAPK
ios, tvosSimulator .app, ZIPped with the bundle at its root
rokuRoku sideload ZIP

IPA and AAB store packages are refused. An App Store or TestFlight archive is built for physical devices and does not contain a simulator app; build an APK for Android, and a separate simulator build for iOS and tvOS.

Upload a runnable build

The upload is a CI step with the Everframe CLI. It uses the same masked EVERFRAME_API_TOKEN as your symbol uploads: an API token with artifacts:write, shown as Upload source maps in Settings → API tokens. See Use the right credentials. Never ship this token in an app.

npm install --global @everframe/cli
export EVERFRAME_API_TOKEN='<masked artifacts:write token>'   # CI secret
export EVERFRAME_APP_ID='<app UUID>'   # the App ID on the app's Setup tab

The fastest start is the app’s Setup tab in the dashboard. Under Enable Try on device (optional), pick the target and enter your package path and the names of your CI version variables. It generates the exact upload and status commands for your project, ready to paste into CI.

Pass the same version and build number your SDK reports, as strings, so 0042 stays 0042. They are how Everframe finds the right build for a report. --commit <full-sha> is optional: without it, the CLI reads the commit from Git or your CI environment, and uploads without one when neither is available.

Run your APK-producing Gradle task, then upload its output. Use --platform android-tv for an Android TV APK.

./gradlew <APK-assemble-task>
everframe device-builds upload --platform android \
  --file "<path/to/app.apk>" \
  --version "$APP_VERSION" --build-number "$APP_BUILD_NUMBER" \
  --wait --json

Everframe checks the package contents after upload, not just the filename, then prepares the build. Files may be up to 500 MiB. Your local file is left in place.

Wait for ready, or check later

An accepted upload is not yet a ready build. Without --wait, the command returns as soon as the upload is accepted and prints its upload ID and state, such as queued. With --wait, it returns when the build is ready, failed or expired. --timeout <seconds> caps the whole command, upload and retries included; the default is 600.

A timeout after acceptance does not mean the build failed. The CLI prints the upload ID and a status command. Check that before uploading again:

everframe device-builds status --app-id "$EVERFRAME_APP_ID" \
  --upload-id "<upload-uuid>" --json
ResultExit code
Upload accepted (no --wait), or build ready (with --wait)0
Upload rejected, or build failed / expired1
--wait deadline reached after the upload was accepted2
status: receiving, queued, uploading, retrying or ready0
status: request error, or build failed / expired1

--json prints one JSON object on stdout with uploadId, state and, once ready, buildId. Errors add error.code and error.message, and the upload ID, last known state and status command when known. Human-readable diagnostics go to stderr.

Keep it separate from symbol uploads

A runnable build and your symbols are independent. A failed or slow device upload does not undo symbols that already uploaded, and should not fail the release by accident. Run it as its own step, and gate on its exit code only if your release requires a ready build:

symbols_exit=0
everframe dsym upload-build --archive "$XCODE_ARCHIVE_PATH" --strict || symbols_exit=$?

device_exit=0
everframe device-builds upload --platform ios \
  --file "$IOS_SIMULATOR_ZIP" \
  --version "$APP_VERSION" --build-number "$APP_BUILD_NUMBER" \
  --wait --timeout 600 || device_exit=$?
if [ "$device_exit" -ne 0 ]; then
  printf 'Device upload exited %s; check its status with the upload ID above.\n' "$device_exit" >&2
fi

exit "$symbols_exit"

How Everframe picks the build

When you open a report, Everframe looks at the ready builds for the same app and target, and picks one in this order:

  1. Matching commit: the build uploaded from the commit the report came from.
  2. Matching version and build: the same version and build number the report carries.
  3. Latest ready build: when nothing matches, the newest one.

Before you start, the panel says which rule matched, for example Report is from 2.4.0 (0042); running 2.4.0 (0042). Matching version and build · 1 candidate. It flags a Build differs mismatch, and a device model or OS version that differs from the reporter’s. A different build may not reproduce the bug, so upload a build for every release you want to investigate.

Everframe keeps the five most recent ready builds per app and target. Older ones are removed automatically, except while a session is using them.

Start a session

  1. Open a report or a crash in the dashboard. The Try on device tab appears next to the screenshots and replay when the app has a ready build for that report’s target.
  2. Choose Try on device. Everframe prepares the session and shows the build, the device, and the reproduction steps. Nothing has started yet.
  3. Click Start. If every device is busy, the session waits in a queue; Cancel queued session gives up the place.
  4. Use the device directly. The controls beside it take a Screenshot, press Back (Android, Android TV and Roku), and Rotate phones and tablets. Drag the edge of the device view to resize it.
  5. Click End session when you are done. Switching back to the replay or a screenshot ends it too, and closing the browser tab ends it shortly after, so a forgotten session does not keep using time.

The header shows the session’s time remaining. A session ends on its own after 10 minutes; start another to keep going. If the reviewed build or device changes before you click Start, Everframe shows the new details and asks you to click Start again, so you never get a different device than the one you reviewed.

Device time

Device time is a monthly allowance per organization, set by your plan and shared by everyone in it. It resets at the start of each calendar month (UTC).

  • Only time the app is actually running counts, rounded to the second.
  • Waiting in the queue, starting up and failed starts are free.
  • An organization runs one session at a time.
  • When the allowance is used up, the panel says so until next month.

Privacy and isolation

Runnable builds are private to your organization. Each app and target keeps its own build storage on the device service, and a session installs exactly the build you reviewed. Every dashboard request checks your current project access, so removing someone from a project also stops them starting sessions on it.

When the tab is missing or Start is unavailable

Message or symptomWhat to do
No Try on device tabUpload a runnable build for the report’s app and target, and wait until status says ready. Web reports never show the tab.
No ready runnable build is available for this report.Same as above. A build that is queued or failed cannot run.
This report does not have a supported device platform.The report came from a platform without a runnable target, such as the web.
No compatible simulator or emulator is available.No device can run this target right now. Try again later.
All available device sessions are in use. Try again later.Every device is busy. Wait and try again.
No device time remains in the current allowance.Your organization used this month’s device time. It resets on the 1st (UTC).
The device selection changed. Review the details and click Start again.A newer build or a different device was chosen since you opened the panel. Check the details and start again.
The device session has reached its time limit.The 10-minute session ended. Close the panel and start a new session.

Upload errors

The CLI exits 1 and prints error.code. A server refusal arrives as request_failed with its HTTP status; the CLI retries 429 and 5xx responses on its own, within --timeout.

error.codeWhat to do
missing_api_tokenSet EVERFRAME_API_TOKEN in the CI step.
invalid_input / invalid_commitCheck --app-id is the app UUID, --timeout is a positive number, and --commit is a full 40- or 64-character SHA.
invalid_formatAndroid and Android TV take an .apk; iOS and tvOS a ZIPped simulator .app; Roku a sideload .zip. IPA and AAB are refused.
upload_too_largeThe package is over 500 MiB.
source_file_unavailable / source_file_changedThe file is missing, or changed while uploading. Run the upload after the build step has finished writing it.
request_failed: HTTP 401Use a non-revoked API token. The public SDK ingest key is not accepted.
request_failed: HTTP 403Give the token artifacts:write (Upload source maps); existing tokens do not gain it automatically.
request_failed: HTTP 404Check the app UUID, the token’s project access, and the upload ID.
request_timeout / upload_timeoutThe network or --timeout ran out. If an upload ID was printed, check status before uploading again.
wait_timeout (exit 2)The upload was accepted and is still processing. Check status with the printed upload ID.

A build that reaches failed reports why:

error.codeWhat to do
invalid_format / invalid_contentThe package did not pass inspection: for example a ZIP with no .app at its root, or a device-only binary.
upload_too_largeThe package is over the size limit.
upload_expiredThe upload was not completed in time. Start a new upload.
provider_unavailable / retry_exhaustedThe device service could not take the build. Upload again later.

See Errors & limits for every limit in one place.