Record Android sessions
Use the sessionReplay module in Android applications.
Alpha features described in this document are provided by Splunk to you "as is" without any warranties, maintenance and support, or service-level commitments. Splunk makes this Alpha feature available at its sole discretion and may discontinue it at any time. These documents are not yet publicly available and we ask that you keep this information confidential. Use of Alpha features is subject to the Splunk Pre-Release Agreement for Hosted Services.
Use these links to navigate to topics within this Alpha release:
Prerequisites
You must have an enterprise subscription.
You must use Splunk RUM agent version
2.0.0
or higher.
Introduction
This page explains how to use the sessionReplay
module in Android applications. This module provides several APIs so that you can choose which ones work best for your application.
Supported languages Java, Kotlin compileVersion 34 minVersion 21 targetVersion 31 Java version 1.8 Kotlin version 1.7.20 - APIs
- Most APIs are methods within
SplunkRum.instance.sessionReplay
:In addition, there are some Kotlin-specific extensions (properties) of standard Android classes, such as:
SplunkRum.instance.sessionReplay
Get a sessionReplay
instance, which is used to configure and start the recording.
The instance doesn't automatically start recording when you create it. To start recording, call its start()
method.
- Kotlin
val sessionReplay = SplunkRum.instance.sessionReplay
- Java
SessionReplay sessionReplay = SessionReplay.getInstance();
Start recording
- Kotlin
SplunkRum.instance.sessionReplay.start()
- Java
SessionReplay.getInstance().start();
Stop recording
There is no need to manually stop the recording when the application enters the background; the recording process automatically stops, and the sessionReplay
module provides the final data chunk. When the application returns to the foreground, the sessionReplay
module resumes recording automatically, provided it was active before the application was previously suspended.
If the application is forcibly terminated (not just suspended to the background) or crashes, the behavior of the sessionReplay
module depends upon the platform:
If the system permits some time to process the incident, the last data chunk is immediately made available.
If not, the most recent replay data chunk prior to the incident is reconstructed and published when the
sessionReplay
module is re-initialized during the application's next run. This includes the corresponding metadata (the actual start and end time stamps of the reconstructed chunk).
After the incident, the sessionReplay
module doesn't resume recording automatically.
- Kotlin
SplunkRum.instance.sessionReplay.stop()
- Java
SessionReplay.getInstance().stop();
Get preferences
- Kotlin
SplunkRum.instance.sessionReplay.preferences
- Java
SessionReplay.getInstance().getPreferences();
Set the rendering mode
When your application displays sensitive or unnecessary data that you don’t want to record, you can set a rendering mode to protect or hide that information. Valid values:
NATIVE
: Regularly captures the application screen which thesessionReplay
module immediately processes to remove sensitive data. The frames are then complied to make the session recording. The representation of the recording is video.Note: IfRenderingMode
isNATIVE
, both the video and wireframe recordings operate simultaneously due to the nature of the implementation. Consequently, both modes are accessible to the player.WIREFRAME_ONLY
: Renders the application using only a wireframe representation of the screen data. No user data is recorded. The representation of the recording is in JSON format.
- Kotlin
enum class RenderingMode { NATIVE, WIREFRAME_ONLY }
val preferences = SplunkRum.instance.sessionReplay.preferences val renderingMode: RenderingMode = preferences.renderingMode preferences.renderingMode = RenderingMode.NATIVE
- Java
public enum RenderingMode { NATIVE, WIREFRAME_ONLY }
Preferences preferences = SessionReplay.getInstance().getPreferences(); RenderingMode renderingMode = preferences.getRenderingMode(); preferences.setRenderingMode(RenderingMode.NATIVE);
Set the recording mask
In cases where areas of the app shouldn't be recorded, but cannot be defined by a View
, you can use the RecordingMask
object:
- Kotlin
val recordingMask = RecordingMask( listOf( RecordingMask.Element( Rect(left, top, right, bottom), RecordingMask.Element.Type.COVERING|RecordingMask.Element.Type.ERASING ) ) ) SplunkRum.instance.sessionReplay.recordingMask = recordingMask
- Java
ArrayList<RecordingMask.Element> elements = new ArrayList<>(); elements.add( new RecordingMask.Element( new Rect(left, top, right, bottom), RecordingMask.Element.Type.COVERING|RecordingMask.Element.Type.ERASING ) ); RecordingMask recordingMask = new RecordingMask(elements); SessionReplay.getInstance().setRecordingMask(recordingMask);
You can only have one
RecordingMask
set at a time, but it can contain a list ofRecordingMask.Element
objects to cover multiple areas at once.The
RecordingMask.Element
can be one of two types:RecordingMask.Element.Type.COVERING
: The area defined by the elementRect
is not recorded.RecordingMask.Element.Type.ERASING
: The area defined by the elementRect
is recorded even if a previousRecordingMask.Element
inside a list wascovering
the area.
The following screenshots describe a
RecordingMask
in action.On the left:
The blue box represents a
video_item
element.The red box represents a
video_item_image
element.
On the right:
The
video_item
element (blue box) has a.COVERING
value. The.COVERING
value masks the element in the session recording.The
video_item_image
element (red box) has an.ERASING
value. The image is visible in the session recording because the.ERASING
value cancels the.COVERING
value.
Set the sensitivity of a UI element or view
When you mark UI elements or views as sensitive, the sessionReplay module masks them in the recording directly on the device. The way to mark elements as sensitive depends on the element type:
Jetpack Compose layout elements can be marked as sensitive using the
isSensitivite
modifier:Text( text = "I'm sensitive text", modifier = Modifier .sessionReplay( isSensitive = true ) )
XML layouts:
View
You can set the sensitivity on any
View
instance:- Kotlin
sampleView.isSensitive = true|false|null
- Java
SessionReplay.getInstance().getSensitivity().setViewInstanceSensitivity(sampleView, true|false|null);
You can also tag any
View
directly in theXML
layout file:<View> <tag android:id="@id/sr_sensitivity" android:value="true|false"/> </View>
XML layouts:
Class
You can set the sensitivity on all instances of a
Class
that extends aView
rather than setting the sensitivity on a specificView
:- Kotlin
SampleViewClass::class.isSensitive = true|false|null
- Java
SessionReplay.getInstance().getSensitivity().setViewInstanceSensitivity(view, true|false|null);
Default sensitive classes
By default, the
EditText
class is set to sensitive. To override the sensitivity at the class or instance level, instance sensitivity needs to be set tofalse
ornull
.Sensitivity prioritization
When determining if the
View
instance is sensitive, the resolution process checks the sensitivity in a strict order.View
instances are not recorded if:The XML has the
sl_sensitivity
tag set totrue
.The
sensitivity
is set totrue
.the
Class
sensitivity is set totrue
.
Class hierarchy and sensitivity
Sensitivity set to a more specific class (deeper in the inheritance tree) has higher priority. Let's demonstrate this principle in the example using the inheritance tree:
If
TextView
is set to be sensitive andRadioButton
is explicitly set to not be sensitive:- Kotlin
TextView::class.isSensitive = true RadioButton::class.isSensitive = false
- Java
SessionReplay.getInstance().getSensitivity().setViewClassSensitivity(TextView.class, true); SessionReplay.getInstance().getSensitivity().setViewClassSensitivity(RadioButton.class, false);
These statements are factual if we assume no
View
instance-specific sensitivity is set:All instances of
TextView
,Button
,CompoundButton
,RadioButton
,Switch
, andToggleButton
are sensitive.All instances of
RadioButton
are not sensitive, even thoughRadioButton
inherits from the sensitive classTextView
.
WebView layouts
WebView
isn't sensitive by default, but if you need to handle sensitivity within aWebView
class, you can mark all sensitive elements on the displayed website as sensitive so that they are hidden. Make these HTML elements part of the CSS.session-replay-hide
class:<div class='session-replay-hide'> This will be hidden. </div>
All inputs are hidden by default except
button
andsubmit
. If some hidden inputs should be recorded, make them part of the CSS.session-replay-show
class:<input type="text" class='session-replay-show'>
Get the state
- Kotlin
SplunkRum.instance.sessionReplay.state
- Java
SessionReplay.getInstance().getState();
Get the rendering mode
- Kotlin
val state = SplunkRum.instance.sessionReplay.state val renderingMode: RenderingMode = state.renderingMode
- Java
State state = SessionReplay.getInstance().getState(); RenderingMode renderingMode = state.getRenderingMode();
Get the recording status
- Kotlin
val status = SplunkRum.instance.state.status when (status) { is Status.Recording -> { println("Recording in progress...") } is Status.NotRecording.NotStarted -> { println("Recording has not started.") } is Status.NotRecording.Stopped -> { println("Recording was stopped.") } is Status.NotRecording.BelowMinSDKVersion -> { println("Cannot record: below minimum SDK version.") } is Status.NotRecording.StorageLimitReached -> { println("Cannot record: storage limit reached.") } is Status.NotRecording.InternalError -> { println("Cannot record: internal error.") } } if (status.isRecording) { println("Do something only if we are recording") }
- Java
Status status = SessionReplay.getInstance().getState().getStatus(); if (status instanceof Status.Recording) { System.out.println("Recording..."); } else if (status instanceof Status.NotRecording.NotStarted) { System.out.println("Not started."); } else if (status instanceof Status.NotRecording.Stopped) { System.out.println("Stopped."); } else if (status instanceof Status.NotRecording.BelowMinSDKVersion) { System.out.println("Below SDK."); } else if (status instanceof Status.NotRecording.StorageLimitReached) { System.out.println("Storage limit reached."); } else if (status instanceof Status.NotRecording.InternalError) { System.out.println("Internal error."); } if (status.getIsRecording()) { System.out.println("Do something because it's recording"); }
Procedure
Set the module's rendering mode, recording mask, and sensitivity.
Results
The sessionReplay
module autonomously captures session data at its own rate and periodically publishes the data, typically several times per minute, through its API. To replay a user session, use replay player in the Splunk RUM UI.