iOS RUM Collection
Incident Management is now generally available! Incident Management is now generally available!

iOS RUM Collection

The iOS RUM collection is in beta. If you have any questions, contact the support team.

Send Real User Monitoring data to Datadog from your iOS applications with Datadog’s dd-sdk-ios client-side RUM SDK and leverage the following features:

  • Get a holistic view of your app’s performance and demographics.
  • Understand which resources are the slowest.
  • Analyze errors by OS and device type.

Setup

  1. Declare the library as a dependency, depending on your package manager. See Datadog’s Releases page for the latest beta version.

    You can use CocoaPods to install dd-sdk-ios:

    pod 'DatadogSDK', :git => 'https://github.com/DataDog/dd-sdk-ios.git', :tag => '1.4.0-beta1'
    

    To integrate the SDK using Apple’s Swift Package Manager, add the following as a dependency to your Package.swift:

    .package(url: "https://github.com/DataDog/dd-sdk-ios.git", .exact("1.4.0-beta1"))
    

    You can use Carthage to install dd-sdk-ios:

    github "DataDog/dd-sdk-ios" "1.4.0-beta1"
    
  2. Initialize the library with your application context and your Datadog client token. For security reasons, you must use a client token: you cannot use Datadog API keys to configure the dd-sdk-ios library as they would be exposed client-side in the iOS application IPA byte code. For more information about setting up a client token, see the client token documentation. You also need to provide an Application ID (create a Javascript RUM application as explained in the RUM Getting Started page).

    Datadog.initialize(
        appContext: .init(),
        configuration: Datadog.Configuration
            .builderUsing(
                rumApplicationID: "<rum_application-id>",
                clientToken: "<client_token>",
                environment: "<environment_name>"
            )
            .set(serviceName: "app-name")
            .build()
    )
    
    Datadog.initialize(
        appContext: .init(),
        configuration: Datadog.Configuration
            .builderUsing(
                rumApplicationID: "<rum_application-id>",
                clientToken: "<client_token>",
                environment: "<environment_name>"
            )
            .set(serviceName: "app-name")
            .set(endpoint: .eu)
            .build()
    )
    
  3. Configure and register the RUM Monitor. You only need to do it once, usually in your AppDelegate code:

    import Datadog
    
    Global.rum = RUMMonitor.initialize()
    

The RUM SDK offers two instrumentation methods:

  • Auto-instrumentation (recommended) - the SDK tracks views, resources, actions, and errors automatically.
  • Manual instrumentation - you instrument your code to send RUM events.

Note: It is possible to mix both methods.

Auto-instrumentation

RUM Views

To enable RUM views tracking, use the .trackUIKitRUMViews(using:) option when configuring the SDK:

Datadog.Configuration
   .builderUsing(...)
   .trackUIKitRUMViews(using: predicate)
   .build()

Global.rum = RUMMonitor.initialize()

predicate must be a type that conforms to UIKitRUMViewsPredicate protocol:

public protocol UIKitRUMViewsPredicate {
    func rumView(for viewController: UIViewController) -> RUMView?
}

Inside the rumView(for:) implementation, your app should decide if a given UIViewController instance should start the RUM view or not (and return nil in this case). The returned value of RUMView should specify at least the path for created the RUM view. Refer to code documentation comments for more details.

Note: The SDK calls rumView(for:) many times while your app is running. Your implementation of the predicate should not depend on the order of SDK calls.

RUM Resources

To enable RUM resources tracking, use the .track(firstPartyHosts:) option when configuring the SDK:

Datadog.Configuration
   .builderUsing(...)
   .track(firstPartyHosts: ["your.domain.com"])
   .build()

Global.rum = RUMMonitor.initialize()

Also, assign DDURLSessionDelegate() as a delegate of the URLSession you want to monitor, for example:

let session = URLSession(
    configuration: .default,
    delegate: DDURLSessionDelegate(),
    delegateQueue: nil
)

This will make the SDK track requests sent from this instance of the URLSession. Requests whose URLs match the firstPartyHosts will be additionally marked as “first party” in the RUM Explorer.

RUM Actions

To enable RUM actions tracking, use the .trackUIKitActions(_:) option when configuring the SDK:

Datadog.Configuration
   .builderUsing(...)
   .trackUIKitActions(true)
   .build()

Global.rum = RUMMonitor.initialize()

This makes the SDK track all significant taps occurring in the app. For privacy reasons, all interactions with the on-screen keyboard are ignored.

RUM Errors

All “error” and “critical” logs are be reported as RUM errors and linked to the current RUM view:

logger.error("message")
logger.critical("message")

Similarly, all ended APM spans marked as error are be reported as RUM errors:

span.setTag(key: OTTags.error, value: true)

Manual Instrumentation

RUM Views

Use the following methods on Global.rum to manually collect RUM resources:

  • .startView(viewController:)
  • .stopView(viewController:)

Example:

// in your `UIViewController`:

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  Global.rum.startView(viewController: self)
}

override func viewDidDisappear(_ animated: Bool) {
  super.viewDidDisappear(animated)
  Global.rum.stopView(viewController: self)
}

For more details and available options, refer to the code documentation comments in DDRUMMonitor class.

RUM Resources

Use the following methods on Global.rum to manually collect RUM resources:

  • .startResourceLoading(resourceKey:request:)
  • .stopResourceLoading(resourceKey:response:)
  • .stopResourceLoadingWithError(resourceKey:error:)
  • .stopResourceLoadingWithError(resourceKey:errorMessage:)

Example:

// in your network client:

Global.rum.startResourceLoading(
    resourceKey: "resource-key", 
    request: request
)

Global.rum.stopResourceLoading(
    resourceKey: "resource-key",
    response: response
)

Note: The String used for resourceKey in both calls must be unique for the resource you are calling. This is necessary for the SDK to match a resource’s start with its completion.

For more details and available options, refer to the code documentation comments in DDRUMMonitor class.

RUM Actions

To manually register instantaneous RUM actions (e.g: .tap), use:

  • .addUserAction(type:name:)

or for continuous RUM actions (e.g: .scroll), use:

  • .startUserAction(type:name:)
  • and .stopUserAction(type:)

on Global.rum.

Example:

// in your `UIViewController`:

@IBAction func didTapDownloadResourceButton(_ sender: Any) {
    Global.rum.addUserAction(
        type: .tap,
        name: (sender as? UIButton).currentTitle ?? "",
    )
}

Note: when using .startUserAction(type:name:) and .stopUserAction(type:). This is necessary for the SDK to match a resource’s start with its completion.

For more details and available options, refer to the code documentation comments in DDRUMMonitor class.

RUM Errors

Use the following methods on Global.rum to manually collect RUM errors:

  • .addError(message:)
  • .addError(error:)

Example:

// anywhere in your code:

Global.rum.addError(message: "error message.")

For more details and available options, refer to the code documentation comments in DDRUMMonitor class.