Skip to main content

Using Sauce Mobile Beta with Backtrace

Beta release

Beta release

The Sauce Mobile Beta SDK is in beta. The current release candidates are 2.2.0-rc for iOS and Android and 3.0.0-rc for React Native.

  • Final: the artifact names and the API.
  • Can still change before general availability: the version numbers, the iOS package URL, and this documentation.

Share feedback with your Sauce Labs representative.

The Sauce Mobile Beta SDK and Backtrace (Sauce Labs Error Reporting) run side by side in one app. This guide describes the contract that makes that possible: Backtrace owns crashes, Sauce Mobile Beta owns beta sessions, and both carry the same correlation attribute so a crash report and its session recording can be matched across the two consoles.

Overview​

A process can have only one owner of its signal and exception handlers. The Sauce Mobile Beta SDK never installs one, at any layer and on any platform, so Backtrace is always the sole crash owner. The two SDKs are designed to run in the same app.

ProductOwns
BacktraceNative crashes (iOS, Android JVM and NDK), JavaScript errors and unhandled promise rejections (React Native), out-of-memory detection, symbolication
Sauce Mobile Beta SDKBeta sessions and video, tester feedback and screenshots, remote logs and events, session attributes, tester workflow

Import the TestFairy module on iOS, com.testfairy.TestFairy on Android, and the TestFairy default export in React Native. On every platform, beginWithoutCrashHandler is the entry point for an app that runs Backtrace: it starts a session and never installs a crash handler.

Before You Begin​

Install both SDKs.

  1. Install Backtrace for your platform: iOS, Android (plus Native Crash Integration if you want NDK crashes), or React Native. New to Backtrace? Start with Getting Started.
    • Android: use Backtrace Android SDK 3.7.14 or later, which added BacktraceClient.addAttribute (see Configuring Backtrace for Android). On 3.7.13 or earlier, use ((BacktraceDatabase) client.database).addAttribute(key, value) instead.
  2. Install the Sauce Mobile Beta SDK: iOS, Android, or React Native.
  3. On Android, use Backtrace's minSdk (21) for the combined app. Sauce Mobile Beta alone supports minSdk 16.

Initialization Order​

Initialize in this order on every platform:

  1. Generate one lowercase UUID v4 for this launch and build the shared attribute map before either SDK starts.
  2. Initialize Backtrace with the shared attributes. Backtrace installs the crash handlers.
  3. Register a Sauce Mobile Beta session-state listener that mirrors the session URL back into Backtrace.
  4. Copy the shared attributes to Sauce Mobile Beta with setAttribute.
  5. Start Sauce Mobile Beta with beginWithoutCrashHandler.

The listener is registered before beginWithoutCrashHandler because the session URL is assigned asynchronously. Reading it immediately after begin can return null.

Pass the attribute map to the BacktraceClient constructor that also takes BacktraceDatabaseSettings. The attributes-only constructor creates a disabled database, and enableNativeIntegration() then silently does nothing. Use the /json submission URL and keep enableNativeIntegration() as the last Backtrace setup call: native annotations are snapshotted there, so values added later reach native reports only through client.addAttribute (backtrace-android 3.8 and later) or ((BacktraceDatabase) client.database).addAttribute (3.7.x).
import android.app.Application
import backtraceio.library.BacktraceClient
import backtraceio.library.BacktraceCredentials
import backtraceio.library.models.BacktraceExceptionHandler
import backtraceio.library.models.database.BacktraceDatabaseSettings
import com.testfairy.SessionStateListener
import com.testfairy.TestFairy
import java.io.File
import java.util.UUID

class MainApplication : Application() {
private lateinit var backtrace: BacktraceClient

override fun onCreate() {
super.onCreate()
// 1. One lowercase UUID v4 per launch, before either SDK starts.
val shared = mapOf(
"sauce.correlation_id" to UUID.randomUUID().toString(),
"sauce.sdk.coexistence_mode" to "backtrace_crash_owner",
"sauce.environment" to "beta",
"sauce.release" to "${BuildConfig.APPLICATION_ID}@${BuildConfig.VERSION_NAME}",
"sauce.dist" to BuildConfig.VERSION_CODE.toString(),
)

// 2. Backtrace first: sole JVM and native crash owner.
backtrace = BacktraceClient(
applicationContext,
BacktraceCredentials("https://submit.backtrace.io/<universe>/<backtrace-token>/json"),
BacktraceDatabaseSettings(File(applicationContext.filesDir, "backtrace").absolutePath),
HashMap<String, Any>(shared)
)
BacktraceExceptionHandler.enable(backtrace)
backtrace.enableNativeIntegration() // keep last

// 3. Mirror every session URL into Backtrace (overwritten on each start).
TestFairy.addSessionStateListener(object : SessionStateListener() {
override fun onSessionStarted(sessionUrl: String?) {
// backtrace-android 3.7.14+; on 3.7.13 or earlier: (backtrace.database as BacktraceDatabase).addAttribute(key, value)
backtrace.addAttribute("sauce.mobile_beta.session_started", "true")
backtrace.addAttribute("sauce.mobile_beta.session_url", sessionUrl ?: "")
}
override fun onSessionFailed() {
backtrace.addAttribute("sauce.mobile_beta.session_started", "false")
}
})

// 4. Same attributes before begin; the SDK keeps them for every session.
shared.forEach { (key, value) -> TestFairy.setAttribute(key, value) }

// 5. Start the SDK. It never installs a crash handler.
TestFairy.beginWithoutCrashHandler(applicationContext, "<sauce-mobile-beta-token>")
}
}

beginWithoutCrashHandler forces the enableCrashReporter option (TFSDKEnableCrashReporterKey on iOS) to false even if you pass true. Plain begin(...) also starts a session without a crash handler, but the explicit call documents the contract in your code and is the recommended entry point.

Shared Attributes​

Both SDKs receive the same keys and values. The values are copies, not references: nothing joins the two products server-side, so a report and a session match only when the app wrote the same value to both.

AttributeValueWhy
sauce.correlation_idLowercase UUID v4, generated once per app launchThe join key. Search it in either console to find the matching report or session.
sauce.sdk.coexistence_modebacktrace_crash_ownerDocuments which product owns crashes in this build. Use it to filter mixed fleets.
sauce.environmentbeta, production, or your own environment nameSeparates beta traffic from other environments in both consoles.
sauce.release<appId>@<version> (for example com.example.app@1.2.3)Ties reports and sessions to a release without relying on platform-specific version fields.
sauce.distBuild number (CFBundleVersion or versionCode)Distinguishes builds of the same version.
mad.distribution_idYour Mobile App Distribution build idOptional. Set it only when configured, so filters never see an empty string.

The Backtrace side additionally receives two attributes the app writes on every Sauce Mobile Beta session start: sauce.mobile_beta.session_url (the recording's address) and sauce.mobile_beta.session_started (the strings "true" or "false"). A launch can produce several sessions (after stop() and a resume), so overwrite these values in the listener every time. Never set them once.

Why one id per launch

A crash belongs to the launch it happened in. Generating sauce.correlation_id once per launch, before either SDK starts, guarantees that the report Backtrace writes at crash time and the session Sauce Mobile Beta recorded up to that moment carry the same value. For identity that spans launches, use setUserId with your real user id or a persisted identifier. Do not reuse the correlation id for that.

Limits on the Sauce Mobile Beta side: 64 attributes per session, keys up to 64 characters, values up to 1000 characters on iOS and 1024 on Android. On iOS and Android, setAttribute returns false when a value is rejected. The React Native binding returns nothing. Set every shared attribute before beginWithoutCrashHandler. The SDK keeps them and attaches them to every session it starts, including sessions started after stop().

caution

Do not use setCorrelationId or identify for the correlation id. Both are deprecated and write the user-identity field that setUserId writes (on Android only once per process), so they would collide with your real user id. Keep setUserId for the user and setAttribute for sauce.correlation_id. See Identifying Your Users and Session Attributes.

Finding a Crash's Session​

  1. Index the attributes in Backtrace. Backtrace lets you filter and group on a custom attribute only after it has been indexed once per project under Project Settings > Attributes. Index sauce.correlation_id with the UUID format, and sauce.mobile_beta.session_url as a string. See Indexing Attributes.
  2. From a crash report, copy the sauce.correlation_id value and search for it in the Sauce Labs Mobile App Distribution session list. The session recorded up to the crash carries the same value.
  3. Or follow sauce.mobile_beta.session_url from the report directly to the recording. It points at the most recent session of that launch, which is the one running when the crash happened.

In the other direction, filter Backtrace on sauce.correlation_id with the value shown on a session's attributes to see whether that launch crashed.

Crash APIs​

These methods exist in the API and do nothing: installCrashHandler, enableCrashHandler, and disableCrashHandler. didLastSessionCrash always returns false. In React Native, isCrashReportingAvailable() returns false and getIntegrationInfo().coexistenceMode is backtrace_crash_owner. Use Backtrace for crash history.

Production Builds​

Keep the Sauce Mobile Beta SDK out of store builds and ship Backtrace in every build. Backtrace is designed for production crash reporting. The Sauce Mobile Beta SDK records sessions for testers. On Android, declare the SDK with debugImplementation or in a beta flavor so release variants never package it. On iOS, gate the calls behind a build setting or a no-op wrapper. Sauce Mobile Beta SDK in Production describes the options, including the no-op wrapper pattern. The shared attributes go to Backtrace in production as well, which keeps sauce.release and sauce.dist consistent between beta and store reports.

Reference Apps​

This pattern is taken from the Sauce Labs demo apps and the React Native package's example app, all of which run the released SDKs:

To try it, run a demo app with your own Backtrace submission URL and Sauce Mobile Beta token, then trigger a crash: More > Crash the App on iOS, or Crash app (debug) in the menu on Android. The process dies as a genuine crash. The Sauce Mobile Beta SDK does not intercept it. Relaunch the app: Backtrace uploads the pending report while Sauce Mobile Beta starts a new session. Open the report, copy its sauce.correlation_id, and search for it in the session list to land on the recording of the launch that crashed.