Overview
The APM integration with Real User Monitoring allows you to link requests from your web and mobile applications to their corresponding backend traces. This combination enables you to see your full frontend and backend data through one lens.
Use frontend data from RUM, as well as backend, infrastructure, and log information from trace ID injection to pinpoint issues anywhere in your stack and understand what your users are experiencing.
To start sending just your iOS application’s traces to Datadog, see iOS Trace Collection.
Usage
Prerequisites
- You have set up APM tracing on the services targeted by your RUM applications.
- Your services use an HTTP server.
- Your HTTP servers are using a library that supports distributed tracing.
- You have the following set up based on your SDK:- With the Browser SDK, you have added the XMLHttpRequest (XHR) or Fetch resources on the RUM Explorer to your allowedTracingUrls.
- With the Mobile SDK, you have added the Native or XMLHttpRequest (XHR) to your firstPartyHosts.
 
- You have a corresponding trace for requests to allowedTracingUrlsorfirstPartyHosts.
Setup RUM
Note: Configuring RUM and Traces makes use of APM paid data in RUM, which may impact your APM billing.
- Set up RUM Browser Monitoring. 
- Initialize the RUM SDK. Configure the - allowedTracingUrlsinitialization parameter with the list of internal, first-party origins called by your browser application.
 - For npm install: - import { datadogRum } from '@datadog/browser-rum'
datadogRum.init({
  clientToken: '<CLIENT_TOKEN>',
  applicationId: '<APPLICATION_ID>',
  site: 'datadoghq.com',
  //  service: 'my-web-application',
  //  env: 'production',
  //  version: '1.0.0',
  allowedTracingUrls: [
    "https://api.example.com",
    // Matches any subdomain of my-api-domain.com, such as https://foo.my-api-domain.com
    /^https:\/\/[^\/]+\.my-api-domain\.com/,
    // You can also use a function for advanced matching:
    (url) => url.startsWith("https://api.example.com")
  ],
  sessionSampleRate: 100,
  sessionReplaySampleRate: 100, // if not specified, defaults to 100
  trackResources: true,
  trackLongTasks: true,
  trackUserInteractions: true,
})
 
- For CDN install: - window.DD_RUM.init({
   clientToken: '<CLIENT_TOKEN>',
   applicationId: '<APPLICATION_ID>',
   site: 'datadoghq.com',
   //  service: 'my-web-application',
   //  env: 'production',
   //  version: '1.0.0',
   allowedTracingUrls: [
     "https://api.example.com",
     // Matches any subdomain of my-api-domain.com, such as https://foo.my-api-domain.com
     /^https:\/\/[^\/]+\.my-api-domain\.com/,
     // You can also use a function for advanced matching:
     (url) => url.startsWith("https://api.example.com")
   ],
   sessionSampleRate: 100,
   sessionReplaySampleRate: 100, // if not included, the default is 100
   trackResources: true,
   trackLongTasks: true,
   trackUserInteractions: true,
 })
 
- To connect RUM to Traces, you need to specify your browser application in the - servicefield.
 - allowedTracingUrlsmatches the full URL (- <scheme>://<host>[:<port>]/<path>[?<query>][#<fragment>]). It accepts the following types:
 - string: matches any URL that starts with the value, so- https://api.example.commatches- https://api.example.com/v1/resource.
- RegExp: matches if any substring of the URL matches the provided RegExp. For example,- /^https:\/\/[^\/]+\.my-api-domain\.com/matches URLs like- https://foo.my-api-domain.com/path, but not- https://notintended.com/?from=guess.my-api-domain.com. Note: The RegExp is not anchored to the start of the URL unless you use- ^. Be careful, as overly broad patterns can unintentionally match unwanted URLs and cause CORS errors.
- function: evaluates with the URL as parameter. Returning a- booleanset to- trueindicates a match.
 
When using RegExp, the pattern is tested against the entire URL as a substring, not just the prefix. To avoid unintended matches, anchor your RegExp with `^` and be as specific as possible.
- (Optional) Configure the - traceSampleRateinitialization parameter to keep a defined percentage of the backend traces. If not set, 100% of the traces coming from browser requests are sent to Datadog. To keep 20% of backend traces, for example:
 - import { datadogRum } from '@datadog/browser-rum'
datadogRum.init({
    ...otherConfig,
    traceSampleRate: 20
})
 
Note: traceSampleRate does not impact RUM sessions sampling. Only backend traces are sampled out.
- (Optional) If you set a - traceSampleRate, to ensure backend services’ sampling decisions are still applied, configure the- traceContextInjectioninitialization parameter to- sampled(set to- sampledby default).
 - For example, if you set the - traceSampleRateto 20% in the Browser SDK:
 - When traceContextInjectionis set toall, 20% of backend traces are kept and 80% of backend traces are dropped.
 - When - traceContextInjectionis set to- sampled, 20% of backend traces are kept. For the remaining 80%, the browser SDK does not inject a sampling decision. The decision is made on the server side and is based on the tracing library head-based sampling configuration. In the example below, the backend sample rate is set to 40%, and therefore 32% of the remaining backend traces are kept.
 
 
End-to-end tracing is available for requests fired after the Browser SDK is initialized. End-to-end tracing of the initial HTML document and early browser requests is not supported.
- Set up RUM Android Monitoring. 
- Set up Android Trace Collection. 
- Add the Gradle dependency to the - dd-sdk-android-okhttplibrary in the module-level- build.gradlefile:
 - dependencies {
    implementation "com.datadoghq:dd-sdk-android-okhttp:x.x.x"
}
 
- Configure the - OkHttpClientinterceptor with the list of internal, first-party origins called by your Android application.
 - val tracedHosts = listOf("example.com", "example.eu")
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(DatadogInterceptor.Builder(tracedHosts).build())
    .addNetworkInterceptor(TracingInterceptor.Builder(tracedHosts).build())
    .eventListenerFactory(DatadogEventListener.Factory())
    .build()
 
- By default, all subdomains of listed hosts are traced. For instance, if you add - example.com, you also enable the tracing for- api.example.comand- foo.example.com.
 
- (Optional) Configure the - traceSamplerparameter to keep a defined percentage of the backend traces. If not set, 20% of the traces coming from application requests are sent to Datadog. To keep 100% of backend traces:
 -     val tracedHosts = listOf("example.com")
    val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(
        DatadogInterceptor.Builder(tracedHosts)
            .setTraceSampler(RateBasedSampler(100f))
            .build()
    )
    .build()
 
Note:
- traceSamplerdoes not impact RUM sessions sampling. Only backend traces are sampled out.
- If you define custom tracing header types in the Datadog configuration and are using a tracer registered with GlobalTracer, make sure the same tracing header types are set for the tracer in use.
- Set up RUM iOS Monitoring. 
- Enable - RUMwith the- urlSessionTrackingoption and- firstPartyHostsTracingparameter:
 - RUM.enable(
    with: RUM.Configuration(
        applicationID: "<rum application id>",
        urlSessionTracking: .init(
            firstPartyHostsTracing: .trace(
                hosts: [
                    "example.com",
                    "api.yourdomain.com"
                ]
            )
        )
    )
)
 
- Enable URLSession instrumentation for your - SessionDelegatetype, which conforms to- URLSessionDataDelegateprotocol:
 - URLSessionInstrumentation.enable(
    with: .init(
        delegateClass: <YourSessionDelegate>.self
    )
)
 
- Initialize URLSession as stated in Setup: - let session =  URLSession(
    configuration: ...,
    delegate: <YourSessionDelegate>(),
    delegateQueue: ...
)
 
- By default, all subdomains of listed hosts are traced. For instance, if you add - example.com, you also enable tracing for- api.example.comand- foo.example.com.
 - Trace ID injection works when you are providing a - URLRequestto the- URLSession. Distributed tracing does not work when you are using a- URLobject.
 
- (Optional) Set the - sampleRateparameter to keep a defined percentage of the backend traces. If not set, 20% of the traces coming from application requests are sent to Datadog.
 - To keep 100% of backend traces: - RUM.enable(
    with: RUM.Configuration(
        applicationID: "<rum application id>",
        urlSessionTracking: .init(
            firstPartyHostsTracing: .trace(
                hosts: [
                    "example.com",
                    "api.yourdomain.com"
                ],
                sampleRate: 100
            )
        )
    )
)
 
Note: sampleRate does not impact RUM sessions sampling. Only backend traces are sampled out.
- Set up RUM React Native Monitoring. 
- Set the - firstPartyHostsinitialization parameter to define the list of internal, first-party origins called by your React Native application:
 - const config = new DatadogProviderConfiguration(
    // ...
);
config.firstPartyHosts = ["example.com", "api.yourdomain.com"];
 
- By default, all subdomains of listed hosts are traced. For instance, if you add - example.com, you also enable tracing for- api.example.comand- foo.example.com.
 
- (Optional) Set the - resourceTracingSamplingRateinitialization parameter to keep a defined percentage of the backend traces. If not set, 20% of the traces coming from application requests are sent to Datadog.
 - To keep 100% of backend traces: - const config = new DatadogProviderConfiguration(
    // ...
);
config.resourceTracingSamplingRate = 100;
 
- Note: - resourceTracingSamplingRatedoes not impact RUM sessions sampling. Only backend traces are sampled out.
 
- Set up RUM Flutter Monitoring. 
- Follow the instructions under Automatically track resources to include the Datadog Tracking HTTP Client package and enable HTTP tracking. This includes the following changes to your initialization to add a list of internal, first-party origins called by your Flutter application: - final configuration = DatadogConfiguration(
  // ...
  // added configuration
  firstPartyHosts: ['example.com', 'api.yourdomain.com'],
)..enableHttpTracking()
 
RUM for Roku is not available on the US1-FED Datadog site.
- Set up RUM Roku Monitoring. 
- Use the - datadogroku_DdUrlTransfercomponent to perform your network requests.
 -     ddUrlTransfer = datadogroku_DdUrlTransfer(m.global.datadogRumAgent)
    ddUrlTransfer.SetUrl(url)
    ddUrlTransfer.EnablePeerVerification(false)
    ddUrlTransfer.EnableHostVerification(false)
    result = ddUrlTransfer.GetToString()
 
- Set up RUM Kotlin Multiplatform Monitoring. 
- Set up Ktor instrumentation. 
- Set the - tracedHostsinitialization parameter in the Datadog Ktor Plugin configuration to define the list of internal, first-party origins called by your Kotlin Multiplatform application:
 - val ktorClient = HttpClient {
    install(
        datadogKtorPlugin(
            tracedHosts = mapOf(
                "example.com" to setOf(TracingHeaderType.DATADOG),
                "example.eu" to setOf(TracingHeaderType.DATADOG)
            ),
            traceSampleRate = 100f
        )
    )
}
 
- By default, all subdomains of listed hosts are traced. For instance, if you add - example.com, you also enable tracing for- api.example.comand- foo.example.com.
 
- (Optional) Set the - traceSampleRateinitialization parameter to keep a defined percentage of the backend traces. If not set, 20% of the traces coming from application requests are sent to Datadog.
 - To keep 100% of backend traces: - val ktorClient = HttpClient {
    install(
        datadogKtorPlugin(
            tracedHosts = mapOf(
                "example.com" to setOf(TracingHeaderType.DATADOG),
                "example.eu" to setOf(TracingHeaderType.DATADOG)
            ),
            traceSampleRate = 100f
        )
    )
}
 
- Note: - traceSampleRatedoes not impact RUM sessions sampling. Only backend traces are sampled out.
 
Verifying setup
To verify you’ve configured the APM integration with RUM, follow the steps below based on the SDK you installed RUM with.
- Visit a page in your application.
- In your browser’s developer tools, go to the Network tab.
- Check the request headers for a resource request that you expect to be correlated contains the correlation headers from Datadog.
RUM Explorer to Traces
To view traces from the RUM Explorer:
- Navigate to your list of sessions and click on a session that has traces available. You can also query for sessions with traces by using@_dd.trace_id:*.
When you select a session, the session panel appears with a request duration breakdown, a flame graph for each span, and a View Trace in APM link.
Traces to RUM Explorer
To view the RUM event from Traces:
- Within a trace view, click VIEW to see all traces created during the view’s lifespan, or RESOURCE to see traces associated with the specific resource from the Overview tab.
- Click See View in RUM or See Resource in RUM to open the corresponding event in the RUM Explorer.
Supported libraries
Below is a list of the supported backend libraries that need to be on the services receiving the network requests.
OpenTelemetry support
RUM supports several propagator types to connect resources with backends that are instrumented with OpenTelemetry libraries.
The default injection style is tracecontext, Datadog.
Note: If you are using a backend framework such as Next.js/Vercel that uses OpenTelemetry, follow these steps.
- Set up RUM to connect with APM as described above. 
- Modify - allowedTracingUrlsas follows:
 - import { datadogRum } from '@datadog/browser-rum'
datadogRum.init({
    ...otherConfig,
    allowedTracingUrls: [
      { match: "https://api.example.com", propagatorTypes: ["tracecontext"]}
    ]
})
 
- matchaccepts the same parameter types (- string,- RegExpor- function) as when used in its simple form, described above.
 - propagatorTypesaccepts a list of strings for desired propagators:
 
- Set up RUM to connect with APM as described above. 
- Use - .traceWithHeaders(hostsWithHeaders:sampleRate:)instead of- .trace(hosts:sampleRate:)as follows:
 -   RUM.enable(
      with: RUM.Configuration(
          applicationID: "<rum application id>",
          urlSessionTracking: .init(
              firstPartyHostsTracing: .traceWithHeaders(
                  hostsWithHeaders: [
                      "api.example.com": [.tracecontext]
                  ],
                  sampleRate: 100
              )
          )
      )
  )
 
- .traceWithHeaders(hostsWithHeaders:sampleRate:)takes- Dictionary<String, Set<TracingHeaderType>>as a parameter, where the key is a host and the value is a list of supported tracing header types.
 - TracingHeaderTypein an enum representing the following tracing header types:
 
- Set up RUM to connect with APM as described above. 
- Configure the - OkHttpClientinterceptor with the list of internal, first-party origins and the tracing header type to use as follows:
 - val tracedHosts = mapOf("example.com" to setOf(TracingHeaderType.TRACECONTEXT),
                      "example.eu" to setOf(TracingHeaderType.DATADOG))
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(DatadogInterceptor.Builder(tracedHosts).build())
    .addNetworkInterceptor(TracingInterceptor.Builder(tracedHosts).build())
    .eventListenerFactory(DatadogEventListener.Factory())
    .build()
 
- TracingHeaderTypeis an enum representing the following tracing header types:
 
- Set up RUM to connect with APM. 
- Configure the RUM SDK with the list of internal, first-party origins and the tracing header type to use as follows: - const config = new DatadogProviderConfiguration(
    // ...
);
config.firstPartyHosts = [{
    match: "example.com",
    propagatorTypes: [
        PropagatorType.TRACECONTEXT,
        PropagatorType.DATADOG
    ]
}];
 
- PropagatorTypeis an enum representing the following tracing header types:
 
- Set up RUM to connect with APM as described above. 
- Use - firstPartyHostsWithTracingHeadersinstead of- firstPartyHostsas follows:
 - final configuration = DatadogConfiguration(
  // ...
  // added configuration
  firstPartyHostsWithTracingHeaders: {
    'example.com': { TracingHeaderType.tracecontext },
  },
)..enableHttpTracking()
 
- firstPartyHostsWithTracingHeaderstakes- Map<String, Set<TracingHeaderType>>as a parameter, where the key is a host and the value is a list of supported tracing header types.
 - TracingHeaderTypein an enum representing the following tracing header types:
 
- Set up RUM to connect with APM. 
- Configure the RUM SDK with the list of internal, first-party origins and the tracing header type to use as follows: - val ktorClient = HttpClient {
    install(
        datadogKtorPlugin(
            tracedHosts = mapOf(
                "example.com" to setOf(TracingHeaderType.DATADOG),
                "example.eu" to setOf(TracingHeaderType.DATADOG)
            ),
            traceSampleRate = 100f
        )
    )
}
 
- TracingHeaderTypeis an enum representing the following tracing header types:
 
How RUM resources are linked to traces
Datadog uses the distributed tracing protocol and sets up the HTTP headers below. By default, both trace context and Datadog-specific headers are used.
- x-datadog-trace-id
- Generated from the Real User Monitoring SDK. Allows Datadog to link the trace with the RUM resource.
- x-datadog-parent-id
- Generated from the Real User Monitoring SDK. Allows Datadog to generate the first span from the trace.
- x-datadog-origin: rum
- To make sure the generated traces from Real User Monitoring don’t affect your APM Index Spans counts.
- x-datadog-sampling-priority
- Set to 1by the Real User Monitoring SDK if the trace was sampled, or0if it was not.
- traceparent: [version]-[trace id]-[parent id]-[trace flags]
- version: The current specification assumes version is set to- 00.
- trace id: 128 bits trace ID, hexadecimal on 32 characters. The source trace ID is 64 bits to keep compatibility with APM.
- parent id: 64 bits span ID, hexadecimal on 16 characters.
- trace flags: Sampled (- 01) or not sampled (- 00)
Trace ID Conversion: The 128-bit W3C trace ID is created by padding the original 64-bit source trace ID with leading zeros. This ensures compatibility with APM while conforming to the W3C Trace Context specification. The original 64-bit trace ID becomes the lower 64 bits of the 128-bit W3C trace ID.
- tracestate: dd=s:[sampling priority];o:[origin]
- dd: Datadog’s vendor prefix.
- sampling priority: Set to- 1if the trace was sampled, or- 0if it was not.
- origin: Always set to- rumto make sure the generated traces from Real User Monitoring don’t affect your APM Index Spans counts.
Examples:
Source trace ID (64-bit): 8448eb211c80319c
W3C Trace Context (128-bit): 00000000000000008448eb211c80319c
The relationship shows that the original 64-bit trace ID 8448eb211c80319c is padded with 16 leading zeros (0000000000000000) to create the 128-bit W3C trace ID.
- Complete traceparent example:
- traceparent: 00-00000000000000008448eb211c80319c-b7ad6b7169203331-01
- tracestate: dd=s:1;o:rum
- b3: [trace id]-[span id]-[sampled]
- trace id: 64 bits trace ID, hexadecimal on 16 characters.
- span id: 64 bits span ID, hexadecimal on 16 characters.
- sampled: True (- 1) or False (- 0)
- Example for b3 single header:
- b3: 8448eb211c80319c-b7ad6b7169203331-1
- Example for b3 multiple headers:
- X-B3-TraceId: 8448eb211c80319c
- X-B3-SpanId: b7ad6b7169203331
- X-B3-Sampled: 1
These HTTP headers are not CORS-safelisted, so you need to configure Access-Control-Allow-Headers on your server handling requests that the SDK is set up to monitor. The server must also accept preflight requests (OPTIONS requests), which are made by the browser prior to every request when tracing is allowed on cross-site URLs.
Effect on APM quotas
Connecting RUM and traces may significantly increase the APM-ingested volumes. Use the initialization parameter traceSampleRate to keep a share of the backend traces starting from browser and mobile requests.
Trace retention
These traces are available for 15 minutes in the Live Search explorer. To retain the traces for a longer period of time, create retention filters. Scope these retention filters on any span tag to retain traces for critical pages and user actions.
Further Reading
Additional helpful documentation, links, and articles: