Blue Triangle Help Center
Auto Light Dark
Auto Light Dark

Blue Triangle SDK for Android Installation Guide

Introduction

The Blue Triangle SDK for Android enables application owners to track their users’ experience so they can focus on user experience issues that impact their business outcomes.

PLEASE read through the mandatory instrumentation instructions to ensure that 

  • Mobile native views are reported for views and performance

  • User sessions are properly stitched between mobile native views and webviews

  • Network details are reported (detailed backend interaction, errors etc.)

  • Checkout events are reported

Instrumenting Your App with the Blue Triangle SDK

Android SDK Default Values

Feature

Required (For installation), 
Recommended, 
Optional

Configuration property name

Default Value

Notes

Site ID

Required (Set parameter)

siteID

 

This will ensure data from the SDK is sent to the correct account in Blue Triangle

Native View Tracking

Required (Add Code)

enableScreenTracking

TRUE

This will enable automatic mobile view tracking. 

Webview Capture

Required (Add Code)

BTTWebViewTracker.onLoadResource(view, url)

TRUE

This will enable session stitching

Network Capture

Required (Add Code, change setting for debugging)

networkSampleRate

0.05 (5%) 
Min = 0.0 (Disabled) 
Max = 1.0 (100%)

This sample rate defines the percentage of user sessions for which network calls will be captured. A value of 0.05 = 5%, 0.0 = no tracking, and 1.0 means that all  network requests will be captured for any user sessions. It is recommended to set to 1.0 (100%) when installing or debugging the SDK.

Campaign Configuration Parameters

Recommended

abTestID

 

These fields can be used to identify and segment users for optimized analytics contextualization. They can be set in advance and changed in real time.

campaignMedium

campaignName

campaignSource

dataCenter

trafficSegmentName

Offline Caching

Optional, changes to default values are not recommended

cacheMemoryLimit

30 Mb 
Min = 0Mb 
Max = 100MB

The amount of memory the cache uses (in bytes) to store Blue Triangle data when the device is offline

cacheExpiryDuration

48 Hours 
Min = 0 Hours 
Max = 120 Hours

The amount of time (in milliseconds) the data is kept in the cache before it expires

Memory Warning

Optional, changes to default values are not recommended

enableMemoryWarning

TRUE

This will enable memory warnings

Performance Monitoring CPU and Memory

Optional, changes to default values are not recommended

isPerformanceMonitorEnabled

TRUE

This will enable or disable CPU and Memory performance metrics

performanceMonitorSampleRate

1000ms

Set the sampling interval for performance monitoring in milliseconds

ANR Detection

Optional, changes to default values are not recommended

ANRMonitoring

TRUE

This will enable ANR tracking

ANRWarningTimeInterval

5 seconds 
Min = 3s 
Max = 10s

Use this configuration property to configure the interval duration that qualifies as an ANR state 

Track Crashes

Optional, changes to default values are not recommended

enableTrackingNetworkState

TRUE

Set this property to TRUE to enable crash tracking

Network State Capture

Optional, changes to default values are not recommended

enableTrackingNetworkState

TRUE

Network interfaces include wifi, ethernet, cellulat, etc. This enables the network state, (associated with all Timers, Errors and Network Requests captured by the SDK)

Application Hot/Cold Launch Time

Optional, changes to default values are not recommended

enableLaunchTime

TRUE

Report on the application hot/cold launch time

Mandatory Installation Steps

SDK Installation

To download the latest Android SDK, please visit https://github.com/blue-triangle-tech/btt-android-sdk.

To integrate Blue Triangle into your Android project, follow these steps:

  • Add the Maven repository to the project's build.gradle file:

allprojects {
  repositories {
  //...
  maven { url 'https://jitpack.io' }
  }
}

Or

             settings.gradle file:

dependencyResolutionManagement {
    //...
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}
  • Add the package dependency to your application's build.gradle file:

dependencies {
    //...
    implementation 'com.github.blue-triangle-tech:btt-android-sdk:2.16.1'
}

Note: For Gradle Plugin Version 8.2.0+

If your project uses Gradle plugin version 8.2.0 and above, use an exclude with a dependency:

implementation("com.github.blue-triangle-tech:btt-android-sdk:2.16.1") {
    exclude("com.squareup.okhttp3", "okhttp-bom")
}

Site ID Configuration

In order to use Blue Triangle, the Site ID needs to be configured in the SDK. 

Find your site ID by:

  • Login to https://portal.bluetriangletech.com 

  • Click on "Settings" icon

  • Open the Sites page under the Settings Modal. (Logged in user needs to have access to Sites page)

  • Get the value for Site ID from the "Tag Prefix" column for the desired "Site Name"

  • Add the Blue Triangle site ID metadata in the manifest as follows:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <meta-data android:name="com.blue-triangle.site-id" android:value="<BTT_SITE_ID>"/>
        <!-- Your other manifest stuff goes here -->
    </application>
</manifest>
  • Initialize the Tracker in your Application class's onCreate as follows:

import android.app.Application
import com.bluetriangle.analytics.Tracker // Import BlueTriangle Tracker

//...
class YourApplication:Application() {
    override fun onCreate() {
        super.onCreate()
        Tracker.init(this) // Initialize the BlueTriangle Tracker
        //...
    }
}
  • Alternatively, if you don't want to add meta-data in your Manifest file, you can provide the site ID programmatically as follows:

import android.app.Application
import com.bluetriangle.analytics.Tracker // Import BlueTriangle Tracker

//...
class YourApplication:Application() {
    override fun onCreate() {
        super.onCreate()
        Tracker.init(this, "<BTT_SITE_ID>") // Initialize the BTT SDK with the given site ID
        //...
    }
}

Native View Performance Tracking

Native view tracking automatically captures all activities and fragments in your app. You will see fragment and activity class names on our dashboard with the view count.

Tracking Composables (If using composables, these steps are mandatory) 
Unlike Activities and Fragments, Composable screens are not automatically tracked. You need to call BttTimerEffect side-effect for each class you want to track. If your app uses Jetpack Compose UI, use our side-effect BttTimerEffect(<screen name>) shown below. The only parameter to this side-effect is view name:

@Composable
fun UserProfileScreen() {
    BttTimerEffect("User Profile")
    // ...
}

If your app is using both Composables and Fragments, then for those composables which are added to a fragment it is not necessary to call BttTimerEffect, because the fragment is automatically tracked.

 
You can disable native view tracking by adding the following meta-data:

<meta-data android:name="com.blue-triangle.screen-tracking.enable" android:
value="false"/>

Note: 
Native view tracking also allows correlating errors and network requests. The crash or network request associates the view name on which this crash or network request occurred. Thus, if view tracking is disabled, the page name of most recently started manual Timer's page name will be sent along with the crash or network request.

Native View/Webview Tracking/Session Stitching

Native Webviews that are integrated into your native application can be tracked in the same session as the native app. To achieve this, follow the steps below to configure the webview:

  • Implement a WebViewClient as shown below:

import android.webkit.WebView
import android.webkit.WebViewClient
import com.bluetriangle.analytics.BTTWebViewTracker

//...
class BTTWebViewClient : WebViewClient() {
    override fun onLoadResource(view: WebView?, url: String?) {
        super.onLoadResource(view, url)
        BTTWebViewTracker.onLoadResource(view, url)
        //...
    }
}

or if you already have a WebViewClient, call the following in its onLoadResource method:

BTTWebViewTracker.onLoadResource(view, url) 

  • Enable JavaScript and Dom Storage and set the WebViewClient

//...
val webView = getWebViewInstance()
webView.settings.javascriptEnabled = true
webView.settings.domStorageEnabled = true
webView.webViewClient = BTTWebViewClient()
//...

WebView tracking full example with Layout:

import android.os.Bundle
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
import com.bluetriangle.bluetriangledemo.utils.BTTWebViewClient
import com.bluetriangle.bluetriangledemo.R

class WebViewActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_web_view)

        val webView = findViewById<WebView>(R.id.webView)
        webView.webViewClient = BTTWebViewClient() // Set BTTWebViewClient declared above
        // Enable Javascript and DOM Storage
        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true

        binding?.webView?.loadUrl("https://www.bluetriangle.com/")
    }
}

WebView tracking full example with Compose:

import androidx.compose.runtime.Composable
import android.webkit.WebView
import androidx.compose.ui.viewinterop.AndroidView
import com.bluetriangle.bluetriangledemo.utils.BTTWebViewClient

@Composable

fun WebViewScreen() {
    AndroidView(factory = { context ->
        WebView(context).apply {
            webViewClient = BTTWebViewClient() // Set BTTWebViewClient declared above
            // Enable Javascript and DOM Storage
            settings.javaScriptEnabled = true
            settings.domStorageEnabled = true
        }
    }, update = {
        it.loadUrl("https://www.bluetriangle.com/")
    })
}

Network Capture  

To capture network details, you need to add one of these code snippets.

OkHttp Support

The SDK provides plug and play support for OkHttp which allows you to easily track all your network requests going through an OkHttpClient. Add the BlueTriangleOkHttpInterceptor & BlueTriangleOkHttpEventListener 

to your OkHttpClient as follows:

import com.bluetriangle.analytics.okhttp.BlueTriangleOkHttpInterceptor
import com.bluetriangle.analytics.okhttp.BlueTriangleOkHttpEventListener
//...
val okHttpClient = OkHttpClient.Builder()
    //...
    // Add BlueTriangleOkHttpInterceptor
    .addInterceptor(BlueTriangleOkHttpInterceptor(Tracker.instance!!.configuration))
    // Add BlueTriangleOkHttpEventListener
    .eventListener(BlueTriangleOkHttpEventListener(Tracker.instance!!.configuration))
    //...
    .build()

If your app already implements and sets an EventListener object to the OkHttpClient, the SDK provides a constructor for BlueTriangleOkHttpEventListener that takes in another EventListener object. You can use this as shown below:

val okHttpClient = OkHttpClient.Builder()
    //...
    // Add BlueTriangleOkHttpInterceptor
    .addInterceptor(BlueTriangleOkHttpInterceptor(Tracker.instance!!.configuration))
    // Add BlueTriangleOkHttpEventListener
    .eventListener(BlueTriangleOkHttpEventListener(Tracker.instance!!.configuration, `<your event listener instance>`))
    //...
    .build()
Manual Network Capture

If you are not using OkHttp or you don't want to track all requests done by OkHttp, you can manually track and submit network requests by using CapturedRequest object as shown below:

// Import CapturedRequest
import com.bluetriangle.analytics.networkcapture.CapturedRequest
//...

// create a captured request object
val capturedRequest = CapturedRequest()
// set the URL which also sets the host, domain, and file parameters that could be set otherwise
capturedRequest.url = "https://bluetriangle.com/platform/business-analytics/"
// start timing the request
capturedRequest.start()
// make the network request
// end timing the request on response/error 
capturedRequest.stop()

// (Optional) set HTTP response status code
capturedRequest.responseStatusCode = 200

// (Optional) set encoded body size based on response content length header
capturedRequest.encodedBodySize = 12341

// (Optional) set based on response content type
capturedRequest.requestType = RequestType.html

// submit the captured request to the tracker instance
Tracker.instance?.submitCapturedRequest(capturedRequest)

Network State Capture

The BlueTriangle SDK allows capturing of network state data. Network state refers to the availability of any network interfaces on the device. Network interfaces include wifi, ethernet, cellular, etc. Once Network state capturing is enabled, the Network state is associated with all Timers, Errors and Network Requests captured by the SDK.

 

This requires the android.permission.ACCESS_NETWORK_STATE permission. Include the permission into your AndroidManifest.xml file as follows:

<uses-permission android:name=
"android.permission.ACCESS_NETWORK_STATE" />

To disable Network state capture, add the following meta-data:

<meta-data android:name="com.blue-triangle.track-network-state.enable" android:
value="false"/>

Note:

  • If Network state capture is enabled and the ACCESS_NETWORK_STATE permission is not granted, then the SDK will not track network state.

  • This feature is only available on API Level 21 and above

Network Capture Sample Rate

The network sample rate will determine the percentage of session network requests that are captured. For example a value of 0.05 means that network capture will be randomly enabled for 5% of user sessions. Network sample rate value should be between 0.0 to 1.0 representing fraction value of percent 0 to 100. The default value is 0.05, i.e only 5% of sessions network request are captured.

Configure the sample rate by adding the following meta-data in your AndroidManifest.xml:

<meta-data android:name="com.blue-triangle.sample-rate.network" android:
value="0.05"/>

To disable network capture, set this value to 0.0 during configuration.

It is recommended to have 100% sample rate while developing/debugging, by setting this value to 1.0 during configuration.

Checkout Event Data

Upon a customer checkout, it is possible to configure the following data parameters for the event:

Brand Value 

val timer = Timer() timer.start() 
timer.setPageName("SignUp") 
//... 
timer.setBrandValue(99.99) 
timer.submit()

Cart Value, Order Number, Order Time, Cart Count, Checkout Count

val timer = Timer() 
timer.start() 
timer.setPageName("Confirmation") 
//... 
timer.setCartValue(99.99) 
timer.setOrderNumber("XYZ1234") 
timer.setCartCount (2)
timer.serCartCountCheckout (5)
timer.setOrderTime(System.currentTimeMillis()) // Optional
timer.submit()

Blue Triangle Campaign Configuration Fields

The following fields can be used to identify and segment users for optimized analytics contextualization. They can be configured in the SDK and modified in the app in real time, and they show in the Blue Triangle portal as parameters for reporting.

abTestID="MY_AB_TEST_ID"

Capture a variable that allows us to understand a live AB test of two variants in the app.

campaignMedium="MY_CAMPAIGN_MEDIUM"

Understand the general reason the journey started (email, paid search, organic search, etc)

campaignName="MY_CAMPAIGN_NAME"

Understand the campaign name that started the journey. 

campaignSource="MY_CAMPAIGN_SOURCE"

Understanding the type of marketing campaign. 

dataCenter="MY_DATA_CENTER"

Understand if you have multiple data centers that serve your customers you can group data by them.

trafficSegmentName="MY_SEGMENT_NAME"

This can be used to segment environment type.  For instance, we can use this to understand if you have beta vs prod but both are live versions of the app.  

Tracker.instance?.setSessionAbTestIdentifier("MY_AB_TEST_ID")
Tracker.instance?.setSessionCampaignMedium("MY_CAMPAIGN_MEDIUM")
Tracker.instance?.setSessionCampaignName("MY_CAMPAIGN_NAME")
Tracker.instance?.setSessionCampaignSource("MY_CAMPAIGN_SOURCE")
Tracker.instance?.setSessionDataCenter("MY_DATA_CENTER")
Tracker.instance?.setSessionTrafficSegmentName("MY_SEGMENT_NAME")

Custom Timers 

While mobile Views are automatically tracked upon installation, Custom Timers can also be configured if needed. 

NOTE: To enable application performance-oriented reporting, timer duration is limited to 120 seconds.

// create and start a timer
final Timer timer=new Timer("Page Name","Traffic Segment Name").start();

// do work...

// optionally, mark the timer as interactive
timer.interactive();

// maybe set a field
timer.setCartValue(99.99);

// do some more work

// end the timer and submit
timer.end().submit();

// or end the timer, set fields such as brand value, and finally submit the timer.
timer.end();
timer.setBrandValue(99.99);
timer.submit();

Timers implement a Parcelable to allow timers to be passed via Bundle such as between activities in an Intent.

// MainActivity.java
final Timer timer=new Timer("Next Page","Android Traffic").start();
final Intent intent=new Intent(this,NextActivity.class);
intent.putExtra(Timer.EXTRA_TIMER,timer);
startActivity(intent);

// NextActivity.java
final Timer timer=getIntent().getParcelableExtra(Timer.EXTRA_TIMER);
timer.end().submit();

When a timer is submitted to the tracker, the tracker sets any global fields such as site ID, session ID, and user ID. Additional global fields may be set as needed and applied to all timers. The timer's fields are then converted to JSON and sent via HTTP POST to the configured tracker URL.

Custom Variables 

In certain scenarios, a developer may need to include additional application-specific information with Timers. This can be achieved by setting custom variables within the Tracker class on Android (and the BlueTriangle class on iOS). These custom variables are global, meaning that once defined, they will automatically be included with every subsequent Timer payload.

To introduce a custom variable, the developer first needs to create it on the BlueTriangle portal. Follow the instructions provided here. Variables created in the portal have a unique variable name associated with them, e.g. CV1, CV2, etc. which are used while setting the custom variable values.

The custom variable values are sent in String format. The following overload functions are just for the convenience of the app developer. In case of boolean value, the custom variable on the portal should be of type “Text”.

Setting a Single Custom Variable

Kotlin 

Kotlin
Tracker.instance?.setCustomVariable(<VARIABLE NAME>, "Some Textual Information"") // String Overload
Tracker.instance?.setCustomVariable(<VARIABLE NAME>, true) // Boolean Overload
Tracker.instance?.setCustomVariable(<VARIABLE NAME>, 1.2349) // Numeric Overload

Java 

Java
Tracker.getInstance().setCustomVariable(<VARIABLE NAME>, "Some Textual Information"") // String Overload
Tracker.getInstance().setCustomVariable(<VARIABLE NAME>, true) // Boolean Overload
Tracker.getInstance().setCustomVariable(<VARIABLE NAME>, 1.2349) // Numeric Overload
Setting Multiple Custom Variables

These methods take a map/dictionary as input, where all the key and values are of String type. The keys correspond to the custom variable names and the values are their respective custom variable values.

Kotlin 

Kotlin
Tracker.instance?.setCustomVariables(values)

Java 

Java
Tracker.getInstance().setCustomVariables(values)
Getting a Single Custom Variable

There are no method overloads for different data types, as those values are converted to String when they are set. The app developer needs to use the correct data types are parsed after getting the value from getCustomVariable.

If there is no value stored against the provided variable name, this method will return null/nil.

Kotlin 

Kotlin
val value = Tracker.instance?.getCustomVariable(<VARIABLE NAME>)

Java 

Java
String value = Tracker.getInstance().getCustomVariable(<VARIABLE NAME>)
Getting All Custom Variables

These methods take a map/dictionary as input, where all the key and values are of String type. The keys correspond to the custom variable names and the values are their respective custom variable values.

Kotlin 

Kotlin
val variables = Tracker.instance?.getCustomVariables()

Java 

Java
Map<String, String> variables = Tracker.getInstance().getCustomVariables()
Clearing a Single Custom Variable

Kotlin 

Kotlin
Tracker.instance?.clearCustomVariable(<VARIABLE NAME>)

Java 

Java
Tracker.getInstance().clearCustomVariable(<VARIABLE NAME>)
Clearing All Custom Variables

Kotlin 

Kotlin
Tracker.instance?.clearAllCustomVariables()

Java 

Java
Tracker.getInstance().clearAllCustomVariables() 

Optional Configuration Steps

ANR Detection

The ANR Detector identifies blocks in the main thread over a specified period of time and reports them as Application Not Responding (ANR) incidents. By default, the ANR is reported if your app's main thread is blocked for 5 seconds or more. You can modify this duration (in seconds) by setting the com.blue-triangle.track-anr.interval-sec metadata as follows:

<meta-data android:name="com.blue-triangle.track-anr.interval-sec" android:
value="5"/>

You can disable ANR detection by setting the following meta-data:

<meta-data android:name="com.blue-triangle.track-anr.enable" android:
value="false"/>

Memory Warning 

When the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector, an OutOfMemoryError is thrown.

The SDK automatically tracks the memory consumption of your app and reports a Memory warning error if your code uses up more than 80% of the app's available memory (heap capacity).

To disable memory warning, add the following meta-data:

<meta-data android:name="com.blue-triangle.memory-warning.enable" android:
value="false"/>

Memory Usage

Memory usage is the amount of memory used by the code during the Timer interval. This is measured in number of bytes.

Against each timer, 3 Memory measurements are being sent, minimum, maximum and average.

The memory that an app can actually take into use is just a fraction of the whole device's memory capacity. So, the memory data that is sent along with the timer is captured based on our App-level memory usage.

To set the interval (in ms) at which the Memory usage is being captured, set the following field:

val configuration = BlueTriangleConfiguration()
configuration.performanceMonitorIntervalMs = 1000

To disable Memory usage set the following field:

val configuration = BlueTriangleConfiguration()
configuration.isPerformanceMonitorEnabled = false

CPU Usage

CPU Usage is the amount of CPU being used by the code during the Timer interval. This is measured in the form of 0-100%.

Against each timer, 3 CPU measurements are being sent: minimum, maximum and average.

To express this in a 0% to 100% format, Blue Triangle calculates the CPU usage by dividing number of CPU cores. This will give you a percentage value between 0% and 100%. 
 
0% to 100% format = Total current CPU usage on Instruments / Number of CPU cores
 
For example:, if you have 4 CPU cores and your current usage is 300%. then actual BTT CPU usage 300% / 4 = 75%. This indicates that CPU is being utilized at 75% of its total capacity.

 

To set the interval (in ms) at which the CPU usage is being captured, set the following field in BlueTriangleConfiguration:

val configuration = BlueTriangleConfiguration()
configuration.performanceMonitorIntervalMs = 1000

To disable CPU usage set the following field in BlueTriangleConfiguration:

val configuration = BlueTriangleConfiguration()
configuration.isPerformanceMonitorEnabled = false

Track Crashes 

The SDK automatically tracks and reports all crashes. To disable this feature, add the following meta-data:

<meta-data android:name="com.blue-triangle.track-crashes.enable" android:
value="false"/>

Offline Caching 

To support offline usage tracking, timer and crash reports that cannot be sent immediately will be cached in the application's cache directory and retried when a successful submission of a timer occurs.

Memory Limit

The amount of memory the cache uses (in bytes) can be configured by setting the following meta-data in the AndroidManifest.xml:

<meta-data android:name="com.blue-triangle.cache.memory-limit" value="30000000"></meta-data>

If new data is sent to the cache after the memory limit exceeds, the cache deletes the oldest data and then adds the new data. So, only the most recently captured user data is tracked by the cache. By default the memory limit is 30Mb.

Expiry Duration

The amount of time (in milliseconds) the data is kept in the cache before it expires can be configured by setting the following meta-data in the AndroidManifest.xml:

<meta-data android:name="com.blue-triangle.cache.expiry" value="86400000"></meta-data>

The data that is kept longer in cache than the expiry duration is automatically deleted. By default the expiry duration is 48 hours.

Launch Time 

Blue Triangle tracks app launch performance. Launch time refers to the duration it takes for an app to become ready for user interaction after it has been started. Blue Triangle automatically tracks both hot launch and cold launch.

Cold Launch

A cold launch occurs when the app process is not already stored in the main memory. This can happen if the System or user terminated your app's process or its first time launch after install/update/reboot.

The SDK measures the cold launch latency, which is the time between the onCreate of the BlueTriangle SDK's ContentProvider and onResume call for the first Activity.

Warm Launch

A Warm Launch occurs when the app is evicted from memory by the system. Then, when it's in the background and the user re-launches it, the OS will bring it back to foreground. This type of launch has less overhead than the cold start but since the activity needs to be recreated, it takes somewhat longer than a hot start.

The Blue Triangle SDK measures the warm launch latency, which is the time between the `onCreate` and `onResume` of the first `Activity` after the app is brought into foreground.

Hot Launch

A Hot Launch occurs when the app is already running in the background and is brought to the foreground. This type of launch is typically faster since the app's state is preserved in memory.

The BlueTriangle SDK measures the hot launch latency, which is the time between the onStart and onResume of the first Activity after the app is brought into foreground.

When the user locks the device while the app was on the screen and then unlocks it, the System calls the same lifecycle callbacks as when the user puts the app in background and brings it to foreground. Therefore, unlocking followed by locking while the app was active is tracked as a Hot Launch.

You can disable Launch Time feature by adding the following meta-data in your AndroidManifest.xml file.

<meta-data android:name="com.blue-triangle.launch-time.enable" android:value="false"/>

Note: This feature is only available on API Level 29 and above

How to Test your Android SDK

Memory Warning

You can declare and call the following function to generate a memory warning:

fun testMemoryWarning() { 
 Thread { 
 val timer = Timer("MemoryWarningTimer", "AndroidNative") 
 timer.start() 
 Thread.sleep(1000) 
 val memoryBlock = ByteArray((Runtime.getRuntime().maxMemory() * 0.85).toInt()) 
 Log.d("MemoryWarningTest", "AllocatedMemory: ${memoryBlock.size}") 
 Thread.sleep(1000) 
 timer.submit() 
 }.start() 
}

ANR Tracking

To test ANR Tracking, you can declare and call the following function on the main thread:

fun testANRTracking() {  val startTime = System.currentTimeMillis()  while(System.currentTimeMillis() - startTime <= (6000)) {
  } 
}

Crash Tracking

To test Crash Tracking, you can declare and call the following function:

fun testCrashTracking() {  throw ArithmeticException() }

Testing Warm Launch

In order to test Warm Launch, you need to enable the "Don't Keep Activities" setting. To enable the "Don't Keep Activities" option on an Android device, follow these steps:

1. Open Settings

Tap on the "Settings" icon on your device to open the Settings menu.

2. Go to Developer Options

  • If Developer Options are already enabled, you can skip to step 5.

  • If Developer Options are not enabled, follow these steps to enable it:

    1. Scroll down and tap on "About phone" (or "About device").

    2. Find "Build number" (you might need to tap on "Software information" first on some devices).

    3. Tap "Build number" multiple times (usually 7 times) until you see a message that says "You are now a developer!" or "Developer mode has been enabled".

    4. You may be prompted to enter your device's PIN or password.

3. Return to the Main Settings Menu

Once Developer Options are enabled, go back to the main Settings menu.

4. Open Developer Options

Scroll down and tap on "System" (or "System & updates" on some devices), then select "Developer options".

5. Enable Don't Keep Activities

  • Scroll down to find the "Don't keep activities" option.

  • Toggle the switch to enable it.

Important Notes

Enabling "Don't Keep Activities" forces the system to destroy every activity as soon as the user leaves it. This is useful for testing purposes to ensure that your app properly handles activity lifecycle transitions, but it might make the device behave differently than normal usage, leading to unexpected behavior in other apps.

Apps build using the React Native framework will not be able to use this method for testing warm launch. If the “Don’t keep activities” option is enabled on an app within this framework, it will cause a crash and not capture a warm launch.

Limitations/Known Issues

Crashes

The expiration timestamp is only updated when the app offscreen event is received and therefore the app offscreen events cannot be handled when a crash happens. Because of this, BTT is unable to renew the session expiration timestamp in crash scenarios. The potential impact of this scenario is that the session could expire in less than 30 minutes instead of 30 minutes. The exact duration of expiration would depend on the last time the user went offscreen since that was when the expiration timestamp was set. 

WebView Stitching

If a WebView was displaying in the app when the user went off-screen, when the user returns the session is updated. The Blue Triangle btt.js tag receives the new session id, however the btt.js tag manages its own session. Because of this, after the session is injected into the WebView, the btt.js tag itself renews its internal session, possibly resulting in the tag using a different session than the Native SDK.

General Information

Supported SDK Metrics

  • Performance & Network Timings

    • Main Timers

    • Network Timers

    • Custom Timers

  • Errors & Crashes

  • Application Not Responding (ANR)

  • HTTP Response Codes

  • App Crashes

  • Device Stats & Session Attributes

    • OS/OS Version

    • App Version

    • Device Type

    • Geographical/Country

    • CPU Usage

    • Memory Warnings

    • Memory/Out of Memory

    • Hot/Cold Launch

    • Custom variables

    • Network Type

    • Device Model

Release Notes

Version

Date

Notes

2.19.17

July 27, 2026

Combined repetitive SwiftUI view entries in breadcrumbs for cases like list and for each. Multiple view appear in a list will be shown as a single entry with a count

2.19.16

July 10, 2026

  • Automatic screen tracking for Compose using btt-gradle-plugin plugin. Added support for btt-gradle-plugin to track Compose screens automatically.

  • SDK logs are only emitted in DEBUG mode(BuildConfig.DEBUG).

2.19.5

May 26, 2026

  • Added support for app install reporting.

  • Added support for force restart error reporting.

  • Added remote configuration support to enable or disable user action tap interception.

2.19.4

Mar 23, 2026

Added breadcrumbs for ANRs, Crashes, and Memory Warnings

2.19.3 

Feb 18, 2026

  • Add support for remote configuration of the SDK to report checkout events based on screen or API calls that represent a successful checkout. This is to maintain representation of conversion events in production in case such event was not instrumented as described in the quick start guide.

  • Added support for custom categories and additional parameters abTestID, campaignMedium, campaignName, campaignSource, and dataCenter.

2.19.2

Jan 28, 2026

  • Removed redundant analytics beacons from errors/crashes in most cases

  • Network data and classes will be sent in the same sessions, following the set fidelity rate

  • Matching Page Group and Traffic Segment between error and analytics beacons

  • Improved Memory Warning message for consistency

  • Improved ANR Warning message for consistency

2.19.1

Jan 5, 2026

  • Added additional remote configuration flags to enable/disable: Grouping tap detection, Network state tracking, ANR tracking, Crash tracking, Memory warning, Launch time tracking and WebView stitching

  • Default grouped view sample rate set to 5% for automated timers

  • Fixed excessive Launch time values issue

2.19.0

Dec 17, 2025

  • Updated minimum supported Android version to API 21 (minSdkVersion = 21).

  • Optimized Performance Monitoring by moving CPU, Memory, and Main Thread usage tracking to a single global monitor instead of per-Timer.

2.18.5

Nov 28, 2025

Bug Fixes

  • Resolved rare crashes in NetworkStateMonitor occurring during ConnectivityManager.registerNetworkCallback() on Android 11 and above.

  • Fixed a low-frequency crash in Tracker.getMostRecentTimer() caused by ArrayDeque.getLastOrNull() method.

2.18.4

Nov 21, 2025

Bug Fixes and Improvements

  • Lowercased cellular network states 2g, 3g, 4g, 5g

  • Changed remote config URL to use site prefix

  • Fixed network sample rate config parsing to accept decimal values e.g. 1.5%, 2.5%, etc.

2.18.3

Nov 4, 2025

Fixed a rare crash in Screen Tracking during Activity lifecycle tracking

2.18.2

Oct 8, 2025

Fixed edge case crash related to WebView configuration updates

2.18.1

Sep 16, 2025

Report CPU, Memory for classes and fragments

2.18.0

Sep 2, 2025

  • Automated Grouping of Activity/Fragments/Composables

  • Automated group name through screen title or class name.

  • Manual API to start a new group with setNewGroup().

  • Manual API to provide group name with setGroupName() method.

  • Grouping enabled by default

  • Calculation of page time for Group by doing a sum of all Fragments/Activities/Composables with discarding overlapped timings.

See here for more details.

2.17.2

Aug 1, 2025

  • Separate App and SDK versions

  • Added the ability to enable/disable screen tracking from the portal

2.17.0

Apr 8, 2025

No-code support for integrated Clarity (session playback) experience. The SDK will automatically detect the presence of Clarity, request a playback URL, which would show in the performance details page. To read more about Blue Triangle's Clarity integration, please visit here.

2.16.2

Feb 7, 2025

Added the ability to disable or enable the SDK (in production) through remote configuration.

2.16.1

Dec 27, 2024

Added the ability to suppress reporting of native views from the SDK through a portal setting. This is beneficial to remotely control SDKs in production. At present this is an SDK capability only, customers wishing to use this feature should contact their account manager.

2.16.0

Dec 6, 2024

Remotely overwrite the Network Sample Rate from the portal

2.15.0

Oct 23, 2024

Custom Variables Support

2.14.0

Oct 8, 2024

Collection of network protocols

2.13.1

September 20, 2024

Collection of device models

2.13.0

September 4, 2024

Feature Improvements

  • Added session expiry after 30 minutes of inactivity

  • Session will now be maintained within 30 minutes duration across app background, app kills and system reboots

  • Automatically updates session in WebView on session expiry

2.12.0

June 17, 2024

New Features

  • Implemented Warm Launch

  • Added Cart Count and Cart Count Checkout Revenue fields to Timer

  • Automatically taking Order Time to be Timer's end time

2.11.0

May 21, 2024

Support for hot and cold application launch timers

2.10.0

May 2, 2024

Simplified and reduced instrumentation needs

2.9.0

March 18, 2024

New Features

  • Network State capture

  • WebView Tracking

  • Memory Warning

Feature Improvements

  • Optimized CPU and Memory Tracking

  • Improved offline caching mechanism with the including of Memory Limit and Expiration

  • Added support for capturing Network Errors

2.8.1

September 21, 2023

Application launch timer tracking