-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Best practices for native iOS Android tracing #30238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
rtrieu
merged 20 commits into
master
from
rtrieu/docs-9023-native-ios-android-tracing-use-cases
Jul 24, 2025
Merged
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
7bbe8ba
[DOCS-9023] Best practices for tracing native iOS Android apps
rtrieu 0126cfb
separate example
rtrieu bbcc684
remove duplicate info
rtrieu 430dbef
space
rtrieu a3fe966
small edit
rtrieu 82860d7
Merge branch 'master' into rtrieu/docs-9023-native-ios-android-tracin…
rtrieu f81d130
more cohesive
rtrieu d0d7e77
Merge branch 'master' into rtrieu/docs-9023-native-ios-android-tracin…
rtrieu 1908b94
Apply suggestions from code review
rtrieu 7fcba31
Merge branch 'master' into rtrieu/docs-9023-native-ios-android-tracin…
rtrieu 67fd9b2
Merge branch 'rtrieu/docs-9023-native-ios-android-tracing-use-cases' …
rtrieu 8661b72
move other platforms
rtrieu 9922020
Apply suggestions from code review
rtrieu ba03b92
remove business spans section
rtrieu 5387f08
small errors
rtrieu c031046
Update content/en/real_user_monitoring/guide/best-practices-tracing-n…
rtrieu d3a17f7
address janine feedback
rtrieu 55e6477
Merge branch 'master' into rtrieu/docs-9023-native-ios-android-tracin…
rtrieu 78a5b4b
Update content/en/real_user_monitoring/guide/best-practices-tracing-n…
rtrieu aaeb559
Apply suggestions from code review
rtrieu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
...en/real_user_monitoring/guide/best-practices-tracing-native-ios-android-apps.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| --- | ||
| title: Best Practices for Tracing Native iOS and Android Apps | ||
| description: Learn how to instrument, use, and optimize Datadog's Trace SDK for native iOS and Android apps. | ||
| further_reading: | ||
| - link: '/real_user_monitoring/connect_rum_and_traces' | ||
| tag: 'Documentation' | ||
| text: 'Connect RUM and Traces' | ||
| - link: '/tracing/trace_collection/automatic_instrumentation/dd_libraries/ios' | ||
| tag: 'Documentation' | ||
| text: 'iOS Trace SDK' | ||
| - link: '/tracing/trace_collection/automatic_instrumentation/dd_libraries/android/' | ||
| tag: 'Documentation' | ||
| text: 'Android Trace SDK' | ||
| - link: '/tracing/trace_collection/custom_instrumentation/ios/otel/' | ||
| tag: 'Documentation' | ||
| text: 'OpenTelemetry for iOS' | ||
| - link: '/tracing/trace_collection/custom_instrumentation/android/otel/' | ||
| tag: 'Documentation' | ||
| text: 'OpenTelemetry for Android' | ||
| --- | ||
|
|
||
| # Overview | ||
|
|
||
| Datadog's Trace SDK for [iOS][1] and [Android][2] lets you add APM spans to your mobile apps. This guide covers usage, key use cases, and sampling rates, with or without using the Datadog RUM SDK. | ||
|
|
||
| Native mobile tracing gives you precise control over what operations are measured by manually instrumenting spans in your iOS or Android app code. This approach works independently of Datadog RUM, but can also be used alongside it for deeper visibility into user experiences and backend interactions. You can also use [OpenTelemetry for iOS][3] or [OpenTelemetry for Android][4] for custom instrumentation. | ||
|
|
||
| **Note**: When using the Trace SDK independently (without the RUM SDK), backend APM traces do not automatically collect spans, so you need to manually start and stop spans. | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Use cases | ||
|
|
||
| ### Wrap a frontend-to-backend distributed trace under a native span | ||
|
|
||
| You can create distributed traces that span from your mobile frontend to your backend services. This is possible with or without RUM. For example, you can wrap one or more frontend-to-backend traces under a manually created span using the Trace SDK. | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| {{< tabs >}} | ||
| {{% tab "iOS" %}} | ||
| Use the [manual context propagation][1] to inject trace headers into network requests. Use `setActive()` to link child spans to a parent span ([API reference][2]). | ||
|
|
||
| [1]: /tracing/trace_collection/automatic_instrumentation/dd_libraries/ios?tab=swiftpackagemanagerspm#:~:text=(Optional)%20To%20distribute%20traces%20between%20your%20environments%2C%20for%20example%20frontend%20%2D%20backend%2C%20you%20can%20either%20do%20it%20manually%20or%20leverage%20our%20auto%20instrumentation.%20In%20both%20cases%2C%20network%20traces%20are%20sampled%20with%20an%20adjustable%20sampling%20rate.%20A%20sampling%20of%2020%25%20is%20applied%20by%20default | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| [2]: https://swiftpackageindex.com/datadog/dd-sdk-ios/develop/documentation/datadogtrace/otspan/setactive/ | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| {{% /tab %}} | ||
| {{% tab "Android" %}} | ||
|
|
||
| Use [OkHttp parent span helpers][1] or [OpenTelemetry addParentSpan][2] to link spans across threads. | ||
|
|
||
| [1]: /tracing/trace_collection/automatic_instrumentation/dd_libraries/android/?tab=kotlin#okhttp | ||
| [2]: /tracing/trace_collection/custom_instrumentation/android/otel/?tab=kotlin#:~:text=(Optional)%20Add%20local%20parent%20span%20to%20the%20span%20generated%20around%20the%20OkHttp%20request%20in%20RUM%3A | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| {{% /tab %}} | ||
| {{< /tabs >}} | ||
|
|
||
| **Note**: Wrapping RUM resource spans under a native span works automatically if the parent span is on the same thread as the network call. Otherwise, use the provided helpers to set the parent span manually. | ||
|
|
||
| ### Profiling native application performance | ||
|
|
||
| Instrumenting multiple native spans and linking them (using `setActive` on iOS or `addParentSpan` on Android) allows you to profile key parts of your app. This helps you: | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - Understand how different methods and components interact | ||
| - Break down performance bottlenecks | ||
| - Gain actionable insights into app behavior | ||
|
|
||
| Here's how to manually instrument a span in your mobile app using the Trace SDK: | ||
|
|
||
| {{< tabs >}} | ||
| {{% tab "iOS" %}} | ||
| ```swift | ||
| let span = tracer.startSpan(operationName: "<span_name>") | ||
| // ... code to measure ... | ||
| span.finish() | ||
| ``` | ||
| See [more iOS examples][1]. | ||
|
|
||
| [1]: /tracing/trace_collection/automatic_instrumentation/dd_libraries/ios?tab=swiftpackagemanagerspm | ||
|
|
||
| {{% /tab %}} | ||
| {{% tab "Android" %}} | ||
|
|
||
| ```kotlin | ||
| val span = tracer.buildSpan("<span_name>").start() | ||
| // ... code to measure ... | ||
| span.finish() | ||
| ``` | ||
| See [more Android examples][1]. | ||
|
|
||
| [1]: /tracing/trace_collection/automatic_instrumentation/dd_libraries/android/?tab=kotlin | ||
|
|
||
| {{% /tab %}} | ||
| {{< /tabs >}} | ||
|
|
||
| ### Creating business spans | ||
|
|
||
| The Trace SDK is independent from RUM, so you can track business processes or flows that span multiple screens or views. For example, you can measure how long it takes users to complete a checkout flow, or how long a background sync takes, regardless of RUM session sampling. These business spans appear in the APM UI and can be used for custom metrics and dashboards. | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Sampling | ||
|
|
||
| Sampling in native mobile tracing controls which spans and traces appear in the Datadog UI, helping you balance visibility with data volume. When you manually instrument spans in your app, sampling determines which ones are displayed for analysis in the Datadog interface. | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Sampling parameters | ||
|
|
||
| The following sampling rate parameters control different aspects of data collection: | ||
rtrieu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| {{< tabs >}} | ||
| {{% tab "iOS" %}} | ||
|
|
||
| | Parameter | Description | | ||
| |---------------------------------------------|------------------------------------------------------------------| | ||
| | `Trace.sampleRate` | Controls the percentage of manually instrumented spans collected by the tracer.| | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| | `urlSessionTracking.firstPartyHostsTracing.sampleRate` | Controls the percentage of network requests traced for first-party hosts. | | ||
| | `RUM.sessionSampleRate` | Controls the percentage of user sessions that are recorded for RUM.| | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| | `WebViewTracking.logsSampleRate` | Controls the percentage of logs collected from WebViews. | | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| {{% /tab %}} | ||
| {{% tab "Android" %}} | ||
|
|
||
| | Parameter | Description | | ||
| |---------------------------------------------|------------------------------------------------------------------| | ||
| | `Trace.sampleRate` | Controls the percentage of manually instrumented spans collected by the tracer.| | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| | `urlSessionTracking.firstPartyHostsTracing.sampleRate` | Controls the percentage of network requests traced for first-party hosts. | | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| | `RUM.sessionSampleRate` | Controls the percentage of user sessions that are recorded for RUM.| | ||
| | `WebViewTracking.logsSampleRate` | Controls the percentage of logs collected from WebViews. | | ||
|
|
||
| {{% /tab %}} | ||
| {{< /tabs >}} | ||
|
|
||
| ### How sampling works | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Sampling affects different types of spans you create in your mobile app: | ||
|
|
||
| - **Local span sampling** applies to manually instrumented spans (like business spans or performance profiling spans). It's controlled by the `Trace.sampleRate` parameter. For example, if you set this rate to 50, all manually created spans are sent to Datadog, but only 50% are visible in the UI. Each span event includes the `_dd.agent_psr` field (the sampling rate) and `metrics._sampling_priority_v1` (1 for sampled, 0 for not sampled). | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - **Distributed trace sampling** applies to traces that cross service boundaries, such as network requests to your backend (relevant for the "Wrap a frontend-to-backend distributed trace" use case). This is controlled by the `urlSessionTracking.firstPartyHostsTracing.sampleRate` parameter. If set to 50, only half of backend requests have the sampled flag set to true, as indicated by the [W3C trace context][7]. All Datadog agents honor this decision, so you see 50% of distributed traces in the UI. | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Sampling rates are applied independently. The most restrictive rate determines what data is visible in the UI for a given session or trace. For example: | ||
| - If you set a low RUM session sample rate (for example, 1%), only 1% of user sessions are recorded for RUM, but you can still trace all network requests within those sessions by setting the network tracing sample rate to 100%. | ||
| - If you set a high trace sample rate but a low RUM sample rate, you may see traces without corresponding RUM data. | ||
|
|
||
| **Example scenario:** | ||
| To sample 1% of all app sessions and trace all API networks within those sessions: | ||
| - Set `RUM.sessionSampleRate = 1` | ||
| - Set `urlSessionTracking.firstPartyHostsTracing.sampleRate = 100` | ||
|
|
||
| Sampling decisions are communicated through trace headers, ensuring all services in a distributed trace use the same sampling choice. | ||
|
|
||
| **Note**: The sampling behavior described above applies to iOS SDK `v2.9.0+` and Android SDK `v1.18.0+`. For earlier versions, see the respective SDK documentation for platform-specific sampling behavior. | ||
rtrieu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Further reading | ||
|
|
||
| {{< partial name="whats-next/whats-next.html" >}} | ||
|
|
||
| [1]: /tracing/trace_collection/automatic_instrumentation/dd_libraries/ios | ||
| [2]: /tracing/trace_collection/automatic_instrumentation/dd_libraries/android | ||
| [3]: /tracing/trace_collection/custom_instrumentation/ios/otel | ||
| [4]: /tracing/trace_collection/custom_instrumentation/android/otel | ||
| [5]: https://github.com/DataDog/dd-sdk-ios/blob/develop/DatadogTrace/Sources/TraceConfiguration.swift#L32 | ||
| [6]: https://github.com/DataDog/dd-sdk-ios/blob/develop/DatadogTrace/Sources/TraceConfiguration.swift#L106 | ||
| [7]: https://www.w3.org/TR/trace-context/#sampled-flag | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.