Record iOS sessions

Use the sessionReplay module in iOS applications.

Prerequisites

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 languagesSwift, Objective-C (ObjC)
compileVersion34
minVersion21
targetVersion31
Java version1.8
Kotlin version1.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.

Swift
let sessionReplay = SplunkRum.shared.sessionReplay
ObjC
SessionReplayModule *sessionReplay = [[SplunkRum shared] sessionReplay];

Start recording

Swift
SplunkRum.shared.sessionReplay.start()
ObjC
[[[SplunkRum shared] sessionReplay] 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.

Swift
SplunkRum.shared.sessionReplay.stop()
ObjC
[[[SplunkRum shared] sessionReplay] stop];

Get preferences

Swift
SplunkRum.shared.sessionReplay.preferences
ObjC
[[[SplunkRum shared] sessionReplay] preferences];

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 the sessionReplay 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: If RenderingMode is native, both the video and wireframe recordings operate simultaneously due to the nature of the implementation. Consequently, both modes are accessible to the player.
  • wireframeOnly: 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.
Swift
enum class RenderingMode {
    native,
    wireframeOnly
}
SplunkRum.shared.sessionReplay.preferences.renderingMode = .native
ObjC
public enum RenderingMode {
    native,
    wireframeOnly
}
[SplunkRum.shared.sessionReplay.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 UIView, you can use the RecordingMask object:

Swift
var maskElements = [MaskElement]()

maskElements.append(MaskElement(rect: CGRect(x: 0, y: 0, width: 100, height: 100), type: .covering))
maskElements.append(MaskElement(rect: CGRect(x: 50, y:120, width: 100, height: 100), type: .erasing))

let recordingMask = RecordingMask(elements: maskElements)

SplunkRum.shared.sessionReplay.recordingMask = recordingMask
ObjC
CGRect coveringRect = CGRectMake(0, 0, 100, 100);
CGRect erasingRect = CGRectMake(50, 120, 100, 100);

MaskElement *coveringElement = [[MaskElement alloc] initWithRect:coveringRect maskType:MaskTypeCovering];
MaskElement *erasingElement = [[MaskElement alloc] initWithRect:erasingRect maskType:MaskTypeErasing];

RecordingMask *recordingMask = [[RecordingMask alloc] initWithElements:@[coveringElement, erasingElement]];

You can only have one RecordingMask set at a time, but it can contain a list of MaskElement objects to cover multiple areas at once.

The MaskElement can be one of two types:

  • MaskElement.MaskType.covering: The area defined by the element Rect is not recorded.

  • MaskElement.MaskType.erasing : The area defined by the element Rect is recorded even if a previous RecordingMask.Element inside a list was covering 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:

  • You can set the sensitivity on any UIView instance:

    Swift
    SplunkRum.shared.sessionReplay.sensitivity.set(someView, true|false|nil)
    
    SplunkRum.shared.sessionReplay.sensitivity[someView] = true|false|nil
    ObjC
    [SplunkRum.shared.sessionReplay setViewInstanceSensitivityWithView:self.someView isSensitive:@YES|@NO|nil];
  • You can also set the sensitivity on all instances of a Class that extends a UIView rather than setting the sensitivity on a specific UIView:
    Swift
    SplunkRum.shared.sessionReplay.sensitivity[SomeViewSubclass.self] = true|false|nil
    ObjC
    [SplunkRum.shared.sessionReplay setViewClassSensitivityWithViewClass:[SomeViewSubclass class] isSensitive:@YES|@NO|nil];
  • Default sensitive classes

    By default, the UITextView, UITextField and WKWebView classes are set as sensitive. To override the sensitivity on the class or instance level, set the class or instance sensitivity to false or nil.

  • Sensitivity prioritization

    When determining if the UIView instance is sensitive, the resolution process checks the sensitivity in a strict order.

    UIView instances are not recorded if:

    • The sensitivity is set to true.

    • The Class sensitivity is set to true.

  • Class hierarchy and sensitivity

    The sensitivity set on descendants has a higher priority than the sensitivity set on the ancestors. For example, if we have a custom UITextView class descendant (class MyCustomTextView: UITextView) and mark it as non-sensitive, then MyCustomTextView and all its descendants will not be sensitive, no matter what sensitivity we set for UITextView.

    Similarly, if we set the sensitivity on an ancestor class, all its descendants take over that sensitivity.

  • WebView sensitivity

    If an app uses WKWebView and you want record them, you need to enable WKWebView recording. You can enable WKWebView recording by removing the sensitivity:

    Swift
    SplunkRum.shared.sessionReplay.sensitivity[WKWebView.self] = false
    ObjC
    [SplunkRum.shared.sessionReplay setViewClassSensitivityWithViewClass:[WKWebView class] isSensitive:@NO];

    If WKWebView is being recorded, all sensitive elements on the displayed website should be marked as sensitive so that they are hidden. You can mark sensitive elements as sensitive using HTML elements with the CSS .session-replay-hide class:

    <div class='session-replay-hide'>
       This will be hidden.
    </div>

    All inputs are hidden by default except button and submit. If some hidden inputs should be recorded, make them part of the CSS .session-replay-show class:

    <input type="text" class='session-replay-show'>
  • SwiftUI sensitivity

    Note:

    Sensitivity support:

    Support for sensitivity in SwiftUI is available from version 2.1 and is a standard part of the session replay module.

    When using the native rendering mode, the sessionReplay module can record sensitive data in your application. In order to protect user privacy, you can configure the module to not record sensitive data.

    The module attempts to hide selected sensitive UI elements automatically. You can also configure it to hide or show particular UI components. Alternatively, you can use one of the wireframe rendering modes to record the screen in a schematic way, showing no user data. The last possibility is to stop screen capturing altogether by using no rendering mode.

    Note:

    Locally hidden elements:

    Sensitive elements are hidden locally on the device. No sensitive data is transferred to or stored in the dashboard.

  • View sensitivity

    You can set the sensitivity of any View with the corresponding ViewModifier:

    Text("Example")
        .sessionReplaySensitive()

    If you need to control the sensitivity of View dynamically, you can set this with an optional parameter:

    Text("Example")
        .sessionReplaySensitive(true|false)
  • Advanced sensitivity control

    Because SwiftUI does not use class hierarchy like UIKit, but dynamically generates content, the use of inheritance is irrelevant. The corresponding functions for setting sensitivity based on a class, instance, or using a protocol are unavailable for View.

    However, this is not a limitation because there are other, more appropriate ways to handle similar needs in SwiftUI.

    For example, suppose you have an element aggregating multiple elements and want to set all contained elements as sensitive. You can use the .sessionReplaySensitive() modifier directly on the aggregating element. Sensitivity set in this way will be propagated to all contained elements.

    Group {
        Text("First text")
        Text("Second text")
    }
    .sessionReplaySensitive()

    Similarly, if an element needs to be completely hidden (for example, List), then we can set the appropriate sensitivity:

    struct NamesListView: View {
        let names = ["John", "Alena", "Kabir"]
        
        var body: some View {
            List(names, id: \.self) { name in
                Text("\(name)")
                    .padding()
            }
            .sessionReplaySensitive()
        }
    }
  • Default sensitivity

    Some UI elements in UIKit are default sensitive. This setting causes potentially sensitive areas to be hidden and not visible even in SwiftUI.

    If a UIView descendant is used directly or indirectly in SwiftUI, its sensitivity will be propagated to the corresponding View.

    Note: Some SwiftUI elements, such as TextField, perform this encapsulation in the background.
  • Interference with UIKit

    Disabling sensitivity on a View that encapsulates a descendant of UIView with defined sensitivity does not carry over to the encapsulated UIView. To fully control the sensitivity on such a View, you must disable sensitivity on the encapsulated UIView using the UIKit API and then set the sensitivity on the View.

    Enabling sensitivity on the View item that encapsulates the UIView descendant can be done at any time and always takes precedence over the settings for the encapsulated UIView.

    Note: Disabling the default sensitivity: For UITextEdit, etc. must be done outside the View, ideally in the main application's controller or another suitable place. It is strongly discouraged to do this directly inView.

    For applications combining SwiftUI and large parts in UIKit, remember that disabling default sensitivity is for the entire application. This will also affect parts in UIKit.

Get the state

Swift
SplunkRum.shared.sessionReplay.state
ObjC
[[[SplunkRum shared] sessionReplay] state];

Get the rendering mode

Swift
val state = SplunkRum.instance.sessionReplay.state
val renderingMode: RenderingMode = state.renderingMode
ObjC
State state = SessionReplay.getInstance().getState();
RenderingMode renderingMode = state.getRenderingMode();

Get the recording status

Swift
let recordingStatus = SplunkRum.shared.sessionReplay.state.status
ObjC
NSNumber *recordingStatus = SplunkRum.shared.sessionReplay.state.status;

Procedure

  1. Get and instance of the sessionReplay module.

  2. Set the module's rendering mode, recording mask, and sensitivity.

  3. Start recording.

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.