Flashcat Android RUM SDK provides various advanced configuration options that allow you to modify collected data and context according to your needs, supporting the following scenarios:
When using ActivityViewTrackingStrategy or FragmentViewTrackingStrategy, the RUM SDK automatically tracks views. You can also manually send custom RUM views when a view becomes visible or interactive:
import cloud.flashcat.android.rum.GlobalRum
fun onResume() {
GlobalRum.get().startView(viewKey, viewName, attributes)
}
fun onPause() {
GlobalRum.get().stopView(viewKey, attributes)
}
import cloud.flashcat.android.rum.GlobalRum;
public void onResume() {
GlobalRum.get().startView(viewKey, viewName, attributes);
}
public void onPause() {
GlobalRum.get().stopView(viewKey, attributes);
}
Parameter descriptions:
viewKey (String): Unique identifier for the view. The same viewKey is used for both startView() and stopView() callsviewName (String): Name of the viewattributes (Map<String, Any?>): Attributes attached to the view, optionalBesides automatically tracked user interactions, you can also track specific custom user actions (such as taps, swipes, likes):
import cloud.flashcat.android.rum.GlobalRum
import cloud.flashcat.android.rum.RumActionType
fun onUserInteraction() {
GlobalRum.get().addAction(
RumActionType.TAP,
name,
attributes
)
}
import cloud.flashcat.android.rum.GlobalRum;
import cloud.flashcat.android.rum.RumActionType;
public void onUserInteraction() {
GlobalRum.get().addAction(
RumActionType.TAP,
name,
attributes
);
}
RumActionType options:
RumActionType.TAP: Tap actionRumActionType.SCROLL: Scroll actionRumActionType.SWIPE: Swipe actionRumActionType.CLICK: Click actionRumActionType.CUSTOM: Custom actionBesides automatically tracked resources, you can also manually track specific custom resources (such as network requests, third-party library loading):
import cloud.flashcat.android.rum.GlobalRum
import cloud.flashcat.android.rum.RumResourceKind
fun loadResource() {
GlobalRum.get().startResource(
resourceKey,
method,
url,
attributes
)
}
fun resourceLoadSuccess() {
GlobalRum.get().stopResource(
resourceKey,
statusCode,
size,
RumResourceKind.NATIVE,
attributes
)
}
fun resourceLoadError() {
GlobalRum.get().stopResourceWithError(
resourceKey,
statusCode,
message,
source,
throwable
)
}
import cloud.flashcat.android.rum.GlobalRum;
import cloud.flashcat.android.rum.RumResourceKind;
public void loadResource() {
GlobalRum.get().startResource(
resourceKey,
method,
url,
attributes
);
}
public void resourceLoadSuccess() {
GlobalRum.get().stopResource(
resourceKey,
statusCode,
size,
RumResourceKind.NATIVE,
attributes
);
}
public void resourceLoadError() {
GlobalRum.get().stopResourceWithError(
resourceKey,
statusCode,
message,
source,
throwable
);
}
RumResourceKind options:
RumResourceKind.BEACON: Beacon requestRumResourceKind.FETCH: Fetch requestRumResourceKind.XHR: XHR requestRumResourceKind.DOCUMENT: Document resourceRumResourceKind.IMAGE: Image resourceRumResourceKind.JS: JavaScript resourceRumResourceKind.FONT: Font resourceRumResourceKind.CSS: CSS resourceRumResourceKind.MEDIA: Media resourceRumResourceKind.OTHER: Other resourceRumResourceKind.NATIVE: Native resourceTo log specific errors, notify the RUM SDK when an exception occurs:
import cloud.flashcat.android.rum.GlobalRum
GlobalRum.get().addError(
message,
source,
throwable,
attributes
)
import cloud.flashcat.android.rum.GlobalRum;
GlobalRum.get().addError(
message,
source,
throwable,
attributes
);
RumErrorSource options:
RumErrorSource.NETWORK: Network errorRumErrorSource.SOURCE: Source code errorRumErrorSource.CONSOLE: Console errorRumErrorSource.LOGGER: Logger errorRumErrorSource.AGENT: Agent errorRumErrorSource.WEBVIEW: WebView errorRumErrorSource.CUSTOM: Custom errorBesides RUM SDK's default performance metrics, you can also use the addTiming API to measure time spent in your app. Timings are relative offsets from the current RUM view start time.
For example, you can time how long it takes to display a hero image:
import cloud.flashcat.android.rum.GlobalRum
fun onHeroImageLoaded() {
GlobalRum.get().addTiming("hero_image")
}
import cloud.flashcat.android.rum.GlobalRum;
public void onHeroImageLoaded() {
GlobalRum.get().addTiming("hero_image");
}
Once the timing is set, it can be accessed via @view.custom_timings.<timing_name>, for example @view.custom_timings.hero_image.
RUM SDK automatically tracks user attributes. You can also add additional custom user attributes, such as user plan, user group, etc:
import cloud.flashcat.android.rum.GlobalRum
GlobalRum.get().setUserInfo(
id = "1234",
name = "John Doe",
email = "john@doe.com",
extraInfo = mapOf(
"plan" to "premium",
"group" to "vip"
)
)
import cloud.flashcat.android.rum.GlobalRum;
import java.util.HashMap;
import java.util.Map;
Map<String, Object> extraInfo = new HashMap<>();
extraInfo.put("plan", "premium");
extraInfo.put("group", "vip");
GlobalRum.get().setUserInfo(
"1234",
"John Doe",
"john@doe.com",
extraInfo
);
Use clearAllData to clear all unsent data currently stored in the SDK:
import cloud.flashcat.android.Flashcat
Flashcat.clearAllData()
import cloud.flashcat.android.Flashcat;
Flashcat.clearAllData();
Use stopInstance to stop collecting data and clear all local data:
import cloud.flashcat.android.Flashcat
Flashcat.stopInstance()
import cloud.flashcat.android.Flashcat;
Flashcat.stopInstance();
RUM SDK automatically batches event uploads. You can control batch upload behavior through configuration parameters:
import cloud.flashcat.android.core.configuration.Configuration
import cloud.flashcat.android.core.configuration.UploadFrequency
val configuration = Configuration.Builder(
clientToken = clientToken,
env = environmentName,
variant = appVariantName
)
.setBatchSize(batchSize)
.setUploadFrequency(UploadFrequency.FREQUENT)
.build()
import cloud.flashcat.android.core.configuration.Configuration;
import cloud.flashcat.android.core.configuration.UploadFrequency;
Configuration configuration = new Configuration.Builder(clientToken, environmentName, appVariantName)
.setBatchSize(batchSize)
.setUploadFrequency(UploadFrequency.FREQUENT)
.build();
UploadFrequency options:
UploadFrequency.FREQUENT: Frequent uploadUploadFrequency.AVERAGE: Average upload (default)UploadFrequency.RARE: Rare uploadYou can define a minimum log level for remotely recorded messages. Logs below this level will not be sent to Flashcat:
import cloud.flashcat.android.log.Logs
import cloud.flashcat.android.log.LogsConfiguration
import android.util.Log
val logsConfig = LogsConfiguration.Builder()
.setRemoteSampleRate(100f)
.setRemoteLogThreshold(Log.WARN)
.build()
Logs.enable(logsConfig)
import cloud.flashcat.android.log.Logs;
import cloud.flashcat.android.log.LogsConfiguration;
import android.util.Log;
LogsConfiguration logsConfig = new LogsConfiguration.Builder()
.setRemoteSampleRate(100f)
.setRemoteLogThreshold(Log.WARN)
.build();
Logs.enable(logsConfig);
Besides default attributes automatically captured by the RUM SDK, you can add additional contextual information to RUM events, such as custom attributes. Custom attributes allow you to filter and group observed user behavior based on code-level information (such as shopping cart status, merchant tier, advertising campaign).
Adding user information to RUM sessions allows you to:
The following attributes are optional, but you should provide at least one:
id (String): Unique user identifiername (String): User-friendly name, displayed by default in RUM UIemail (String): User email, displayed if no name is providedTo identify user sessions, use the setUserInfo API after SDK initialization:
import cloud.flashcat.android.rum.GlobalRum
GlobalRum.get().setUserInfo(
id = "1234",
name = "John Doe",
email = "john@doe.com"
)
import cloud.flashcat.android.rum.GlobalRum;
GlobalRum.get().setUserInfo("1234", "John Doe", "john@doe.com", null);
import cloud.flashcat.android.rum.GlobalRum
GlobalRum.get().addAttribute("key", "value")
import cloud.flashcat.android.rum.GlobalRum;
GlobalRum.get().addAttribute("key", "value");
import cloud.flashcat.android.rum.GlobalRum
GlobalRum.get().removeAttribute("key")
import cloud.flashcat.android.rum.GlobalRum;
GlobalRum.get().removeAttribute("key");
Widgets are not automatically tracked. To manually send interactions from Widget UI, you can call the Flashcat API:
import cloud.flashcat.android.rum.GlobalRum
fun onWidgetClicked() {
GlobalRum.get().addAction(
RumActionType.TAP,
"widget_clicked",
mapOf("widget_name" to "HomeWidget")
)
}
import cloud.flashcat.android.rum.GlobalRum;
import java.util.HashMap;
import java.util.Map;
public void onWidgetClicked() {
Map<String, Object> attributes = new HashMap<>();
attributes.put("widget_name", "HomeWidget");
GlobalRum.get().addAction(
RumActionType.TAP,
"widget_clicked",
attributes
);
}
When initializing the Flashcat Android SDK, you can configure the SDK using the following methods in Configuration.Builder:
To automatically track views (Activities, Fragments), use useViewTrackingStrategy during initialization:
import cloud.flashcat.android.rum.RumConfiguration
import cloud.flashcat.android.rum.tracking.ActivityViewTrackingStrategy
val rumConfig = RumConfiguration.Builder(applicationId)
.useViewTrackingStrategy(ActivityViewTrackingStrategy(true))
.build()
import cloud.flashcat.android.rum.RumConfiguration;
import cloud.flashcat.android.rum.tracking.ActivityViewTrackingStrategy;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.useViewTrackingStrategy(new ActivityViewTrackingStrategy(true))
.build();
Available tracking strategies:
ActivityViewTrackingStrategy(trackExtras): Track each Activity as a separate view. The trackExtras parameter determines whether to track Activity Intent extrasFragmentViewTrackingStrategy(trackArguments): Track each Fragment as a separate view. The trackArguments parameter determines whether to track Fragment argumentsMixedViewTrackingStrategy(trackExtras, trackArguments): Track both Activities and Fragments. Track both Activity and Fragment as separate viewsNavigationViewTrackingStrategy(navigationViewId): For Android Navigation component. Track navigation destinations as viewsTo automatically track network requests, refer to the OkHttp interceptor configuration in the SDK Integration Guide.
If you're using the Apollo GraphQL client for network calls, you can enable automatic tracking by following these steps:
Step 1: Add the fc-sdk-android-apollo dependency to your app's build.gradle file:
dependencies {
implementation "cloud.flashcat:fc-sdk-android-apollo:x.x.x"
}
Step 2: Add the Flashcat interceptor to your Apollo Client configuration:
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.network.okHttpClient
import cloud.flashcat.android.apollo.FlashcatApolloInterceptor
val apolloClient = ApolloClient.Builder()
.serverUrl("GraphQL endpoint")
.addInterceptor(FlashcatApolloInterceptor())
.okHttpClient(okHttpClient)
.build()
import com.apollographql.apollo.ApolloClient;
import cloud.flashcat.android.apollo.FlashcatApolloInterceptor;
ApolloClient apolloClient = new ApolloClient.Builder()
.serverUrl("GraphQL endpoint")
.addInterceptor(new FlashcatApolloInterceptor())
.okHttpClient(okHttpClient)
.build();
This will automatically add Flashcat tracing headers to your GraphQL requests, enabling them to be tracked by Flashcat.
Note:
4query and mutation type operations are tracked, not subscription operationssendGraphQLPayloads flag in the FlashcatApolloInterceptor constructor:FlashcatApolloInterceptor(sendGraphQLPayloads = true)
new FlashcatApolloInterceptor(true)
Long-running operations on the main thread can impact your app's visual performance and responsiveness. To track these operations, define a duration threshold for when a task is considered too long:
import cloud.flashcat.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.trackLongTasks(durationThreshold)
.build()
import cloud.flashcat.android.rum.RumConfiguration;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.trackLongTasks(durationThreshold)
.build();
For example, to replace the default 100 ms duration, you can set a custom threshold in the configuration:
val rumConfig = RumConfiguration.Builder(applicationId)
.trackLongTasks(250L) // Track tasks exceeding 250ms as long tasks
.build()
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.trackLongTasks(250L) // Track tasks exceeding 250ms as long tasks
.build();
To modify certain attributes of RUM events before batch processing, or to completely drop certain events, provide an implementation of EventMapper<T> when initializing the RUM Android SDK:
import cloud.flashcat.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.setErrorEventMapper(rumErrorEventMapper)
.setActionEventMapper(rumActionEventMapper)
.setResourceEventMapper(rumResourceEventMapper)
.setViewEventMapper(rumViewEventMapper)
.setLongTaskEventMapper(rumLongTaskEventMapper)
.build()
import cloud.flashcat.android.rum.RumConfiguration;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.setErrorEventMapper(rumErrorEventMapper)
.setActionEventMapper(rumActionEventMapper)
.setResourceEventMapper(rumResourceEventMapper)
.setViewEventMapper(rumViewEventMapper)
.setLongTaskEventMapper(rumLongTaskEventMapper)
.build();
When implementing the EventMapper<T> interface, only some attributes can be modified for each event type:
| Event Type | Modifiable Attribute Keys | Description |
|---|---|---|
| ViewEvent | view.referrer | URL linking to the initial view |
view.url | URL of the view | |
view.name | Name of the view | |
| ActionEvent | action.target.name | Target name |
view.referrer | URL linking to the initial view | |
view.url | URL of the view | |
view.name | Name of the view | |
| ErrorEvent | error.message | Error message |
error.stack | Stack trace of the error | |
error.resource.url | URL of the resource | |
view.referrer | URL linking to the initial view | |
view.url | URL of the view | |
view.name | Name of the view | |
| ResourceEvent | resource.url | URL of the resource |
view.referrer | URL linking to the initial view | |
view.url | URL of the view | |
view.name | Name of the view | |
| LongTaskEvent | view.referrer | URL linking to the initial view |
view.url | URL of the view | |
view.name | Name of the view |
Note: If you return null from the EventMapper<T> implementation, the event will remain unchanged and be sent as is.
val rumConfig = RumConfiguration.Builder(applicationId)
.setErrorEventMapper { errorEvent ->
if (errorEvent.error.message?.contains("sensitive_data") == true) {
null // Drop errors containing sensitive data
} else {
errorEvent
}
}
.build()
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.setErrorEventMapper(errorEvent -> {
if (errorEvent.error.message != null &&
errorEvent.error.message.contains("sensitive_data")) {
return null; // Drop errors containing sensitive data
} else {
return errorEvent;
}
})
.build();
Retrieving the RUM Session ID is helpful for troubleshooting. For example, you can attach the Session ID to support requests, emails, or error reports so that support teams can later find user sessions in Flashcat.
You can access the RUM Session ID at runtime without waiting for the sessionStarted event:
import cloud.flashcat.android.rum.GlobalRum
GlobalRum.get().getCurrentSessionId { sessionId ->
currentSessionId = sessionId
}
import cloud.flashcat.android.rum.GlobalRum;
GlobalRum.get().getCurrentSessionId(sessionId -> {
currentSessionId = sessionId;
});
By default, Flashcat RUM collects data for all sessions. You can reduce the number of sessions collected by setting a sampling rate (percentage) using the sessionSampleRate parameter at initialization:
import cloud.flashcat.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.setSessionSampleRate(90.0f) // Collect 90% of sessions
.build()
import cloud.flashcat.android.rum.RumConfiguration;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.setSessionSampleRate(90.0f) // Collect 90% of sessions
.build();
Sampled sessions will not collect any page views and their associated telemetry data.
To comply with privacy regulations such as GDPR and CCPA, Flashcat RUM allows setting user tracking consent status at initialization. Options:
TrackingConsent.GRANTED: Start collecting data and send to FlashcatTrackingConsent.NOT_GRANTED: Do not collect any dataTrackingConsent.PENDING: Start collecting data but do not send to FlashcatIf initialized with TrackingConsent.PENDING, the SDK will start collecting data, but will not send it until the consent status changes to TrackingConsent.GRANTED.
You can change the consent status after initialization through the setTrackingConsent API:
import cloud.flashcat.android.Flashcat
import cloud.flashcat.android.privacy.TrackingConsent
Flashcat.setTrackingConsent(TrackingConsent.GRANTED)
import cloud.flashcat.android.Flashcat;
import cloud.flashcat.android.privacy.TrackingConsent;
Flashcat.setTrackingConsent(TrackingConsent.GRANTED);
startView and stopView are called in appropriate lifecycle methods to avoid duplicate view trackingstartResource has a corresponding stopResource or stopResourceWithError call