---
title: iOS and tvOS Custom Instrumentation using the OpenTelemetry API
description: >-
  Instrument your iOS and tvOS application with the OpenTelemetry API to send
  traces to Datadog.
breadcrumbs: >-
  Docs > APM > Application Instrumentation > Code-Based Custom Instrumentation >
  Client-Side Custom Instrumentation > iOS > iOS and tvOS Custom Instrumentation
  using the OpenTelemetry API
---

# iOS and tvOS Custom Instrumentation using the OpenTelemetry API

{% alert level="info" %}
Unsure when to use OpenTelemetry with Datadog? Start with [Custom Instrumentation with the OpenTelemetry API](https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/otel_instrumentation/) to learn more.
{% /alert %}

## Overview{% #overview %}

There are a few reasons to manually instrument your applications with the OpenTelemetry API:

- You are not using Datadog [supported library instrumentation](https://docs.datadoghq.com/tracing/trace_collection/compatibility/).
- You want to extend the `ddtrace` library's functionality.
- You need finer control over instrumenting your applications.

The `ddtrace` library provides several techniques to help you achieve these goals. The following sections demonstrate how to use the OpenTelemetry API for custom instrumentation to use with Datadog.

## Requirements and limitations{% #requirements-and-limitations %}

- DatadogTrace for iOS and tvOS version 2.12.0+.

## Tracing iOS applications with OpenTelemetry{% #tracing-ios-applications-with-opentelemetry %}

1. Declare the library as a dependency depending on your package manager. Swift Package Manager (SPM) is recommended.

{% tab title="Swift Package Manager (SPM)" %}
To integrate using Apple's Swift Package Manager, add the following as a dependency to your `Package.swift`:

```swift
.package(url: "https://github.com/Datadog/dd-sdk-ios.git", .upToNextMajor(from: "2.0.0"))
```

In your project, link the following libraries:

```
DatadogCore
DatadogTrace
```

{% /tab %}

{% tab title="CocoaPods" %}
You can use [CocoaPods](https://cocoapods.org/) to install `dd-sdk-ios`:

```
pod 'DatadogCore'
pod 'DatadogTrace'
```

{% /tab %}

{% tab title="Carthage" %}
You can use [Carthage](https://github.com/Carthage/Carthage) to install `dd-sdk-ios`:

```
github "DataDog/dd-sdk-ios"
```

In Xcode, link the following frameworks:

```
OpenTelemetryApi.xcframework
DatadogInternal.xcframework
DatadogCore.xcframework
DatadogTrace.xcframework
```

{% /tab %}
Initialize the library with your application context and your [Datadog client token](https://docs.datadoghq.com/account_management/api-app-keys/#client-tokens). For security reasons, you must use a client token: you cannot use [Datadog API keys](https://docs.datadoghq.com/account_management/api-app-keys/#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](https://docs.datadoghq.com/account_management/api-app-keys/#client-tokens).

{% callout %}
# Important note for users on the following Datadog sites: app.datadoghq.com



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

{% callout %}
# Important note for users on the following Datadog sites: app.datadoghq.eu



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        site: .eu1,
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

{% callout %}
# Important note for users on the following Datadog sites: us3.datadoghq.com



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        site: .us3,
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

{% callout %}
# Important note for users on the following Datadog sites: us5.datadoghq.com



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        site: .us5,
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

{% callout %}
# Important note for users on the following Datadog sites: app.ddog-gov.com



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        site: .us1_fed,
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

{% callout %}
# Important note for users on the following Datadog sites: ap1.datadoghq.com



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        site: .ap1,
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

{% callout %}
# Important note for users on the following Datadog sites: ap2.datadoghq.com



{% tab title="Swift" %}

```swift
import DatadogCore

Datadog.initialize(
    with: Datadog.Configuration(
        clientToken: "<client token>",
        env: "<environment>",
        site: .ap2,
        service: "<service name>"
    ),
    trackingConsent: trackingConsent
)
```

{% /tab %}


{% /callout %}

To be GDPR compliant, the SDK requires the `trackingConsent` value at initialization. The `trackingConsent` can be one of the following values:

- `.pending`: The SDK starts collecting and batching the data but does not send it to Datadog. The SDK waits for the new tracking consent value to decide what to do with the batched data.
- `.granted`: The SDK starts collecting the data and sends it to Datadog.
- `.notGranted`: The SDK does not collect any data: logs, traces, and RUM events are not sent to Datadog.

To change the tracking consent value after the SDK is initialized, use the `Datadog.set(trackingConsent:)` API call.

The SDK changes its behavior according to the new value. For example, if the current tracking consent is `.pending`:

- If changed to `.granted`, the SDK sends all current and future data to Datadog;
- If changed to `.notGranted`, the SDK wipes all current data and stops collecting any future data.

Before data is uploaded to Datadog, it is stored in cleartext in the cache directory (`Library/Caches`) of your [application sandbox](https://support.apple.com/en-gb/guide/security/sec15bfe098e/web). The cache directory cannot be read by any other app installed on the device.

When writing your application, enable development logs to log to console all internal messages in the SDK with a priority equal to or higher than the provided level.

{% tab title="Swift" %}

```swift
Datadog.verbosityLevel = .debug
```

{% /tab %}
Datadog tracer implements the [Open Telemetry standard](https://opentelemetry.io/docs/concepts/signals/traces/). Enable the Datadog tracer, register the tracer provider, and get the tracer instance:
{% tab title="Swift" %}

```swift
import DatadogTrace
import OpenTelemetryApi

Trace.enable(
    with: Trace.Configuration(
        networkInfoEnabled: true
    )
)

OpenTelemetry.registerTracerProvider(
    tracerProvider: OTelTracerProvider()
)

let tracer = OpenTelemetry
    .instance
    .tracerProvider
    .get(instrumentationName: "", instrumentationVersion: nil)
```

{% /tab %}
Instrument your code with the OpenTelemetry API:
{% tab title="Swift" %}

```swift
let span = tracer.spanBuilder(spanName: "<span_name>").startSpan()
// do something you want to measure ...
// ... then, when the operation is finished:
span.end()
```

{% /tab %}
(Optional) Set child-parent relationship between your spans:
{% tab title="Swift" %}

```swift
let responseDecodingSpan = tracer.spanBuilder(spanName: "response decoding")
    .setParent(networkRequestSpan) // make it child of `networkRequestSpan`
    .startSpan()

// ... decode HTTP response data ...
responseDecodingSpan.end()
```

{% /tab %}
(Optional) Provide additional attributes alongside your span:
{% tab title="Swift" %}

```swift
span.setAttribute(key: "http.url", value: url)
```

{% /tab %}
(Optional) Attach an error to a span:
{% tab title="Swift" %}

```swift
span.status = .error(description: "Failed to decode response")
```

{% /tab %}
(Optional) Add span links to your span:
{% tab title="Swift" %}

```swift
let linkedSpan = tracer.spanBuilder(spanName: "linked span").startSpan()
linkedSpan.end()

let spanWithLinks = tracer.spanBuilder(spanName: "span with links")
    .addLink(spanContext: linkedSpan.context)
    .startSpan()
spanWithLinks.end()
```

{% /tab %}
