Datadog Integration for Mobile App Monitoring (APM)
APM for mobile apps is not the same as APM on the backend. A server trace starts with an HTTP request and ends with a response. On a mobile client, the chain is more complex: cold startup → SDK initialization → navigation → network request → screen render. The Datadog Mobile SDK can link all these stages into a single distributed trace, but only with proper instrumentation.
Why Datadog Instead of Just Firebase Crashlytics
Firebase is good at catching crashes. Datadog solves a different problem — seeing live session performance: how long Time to Interactive takes on a specific screen, which HTTP requests slow down rendering, at which funnel step users wait longer than 3 seconds.
Linking DD-Trace on iOS/Android with dd-trace on the backend allows you to pass the trace-id from the mobile client into the server request — and in Datadog APM you see the full path from button tap to database response.
SDK Integration
iOS (Swift Package Manager):
// Package.swift dependency
.package(url: "https://github.com/DataDog/dd-sdk-ios", from: "2.0.0")
import DatadogCore
import DatadogRUM
import DatadogTrace
Datadog.initialize(
with: Datadog.Configuration(
clientToken: "pub-xxxxx",
env: "production",
site: .eu1
),
trackingConsent: .granted
)
RUM.enable(with: RUM.Configuration(applicationID: "your-rum-app-id"))
Trace.enable()
The trackingConsent parameter is critical for GDPR: if the user hasn't consented yet, use .pending. The SDK buffers data locally. Once you get consent, call Datadog.set(trackingConsent: .granted) and it sends everything.
Android (Kotlin):
// build.gradle.kts
implementation("com.datadoghq:dd-sdk-android-rum:2.+")
implementation("com.datadoghq:dd-sdk-android-trace:2.+")
implementation("com.datadoghq:dd-sdk-android-okhttp:2.+")
val config = Configuration.Builder(
clientToken = "pub-xxxxx",
env = "production"
).build()
Datadog.initialize(this, config, TrackingConsent.GRANTED)
val rumConfig = RumConfiguration.Builder("your-rum-app-id")
.trackUserInteractions()
.trackLongTasks(durationThreshold = 100L)
.build()
RumMonitor.enable(rumConfig)
View and Action Instrumentation
By default, Datadog automatically tracks UIViewController on iOS and Activity/Fragment on Android. But auto-tracking shows class names, not readable screen names. Add custom names:
// iOS — custom View name
RUM.monitor?.startView(viewController: self, name: "ProductDetailScreen")
// Android — manual View tracking in Fragment
GlobalRumMonitor.get().startView(
key = this,
name = "ProductDetailScreen",
attributes = mapOf("product_id" to productId)
)
For user actions: Datadog automatically tracks taps via trackUserInteractions(). Log custom business events explicitly:
GlobalRumMonitor.get().addAction(
type = RumActionType.CUSTOM,
name = "AddToCart",
attributes = mapOf("sku" to sku, "quantity" to qty)
)
Distributed Tracing Mobile → Backend
The most valuable part — linking mobile requests to server traces. Datadog SDK injects headers x-datadog-trace-id and x-datadog-parent-id into outgoing HTTP requests.
iOS with URLSession:
let session = URLSession(
configuration: .default,
delegate: DDURLSessionDelegate(),
delegateQueue: nil
)
Android with OkHttp:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(
DatadogInterceptor.Builder(listOf("api.myapp.com"))
.setTraceSampler(RateBasedSampler(20f)) // 20% of traces
.build()
)
.build()
Note the RateBasedSampler — for high-traffic apps, 100% tracing quickly exceeds quota. When debugging a new screen, use 100%; in production, 10–20% usually suffices.
On the backend (e.g., Node.js with dd-trace):
const tracer = require('dd-trace').init({ service: 'mobile-api' });
// dd-trace automatically extracts x-datadog-trace-id from headers
In Datadog APM UI, you'll see a graph from the mobile RUM View to the specific SQL query on the server.
Custom Metrics and Alerts
For business metrics, use addAttribute at the RUM View level:
RUM.monitor?.addAttribute(forKey: "checkout.step", value: "payment")
RUM.monitor?.addAttribute(forKey: "cart.value", value: cartTotal)
In Datadog Monitors, create an alert on p95(rum.view.loading_time) > 3000 for the checkout screen — this catches degradation before users complain.
What We Do
- Connect SDK for iOS and Android (or Flutter via
datadog_flutter_plugin) - Configure auto-tracking of Views, Actions, Errors, and Long Tasks
- Instrument the network layer for distributed traces
- Create dashboards: Time to Interactive, Error Rate, p95 Network Latency by screen
- Set up alerts for performance degradation
Timeline
Basic integration with RUM and APM: 2–3 days. Adding custom business attributes and dashboards — another day. Pricing is calculated individually.







