> ## Documentation Index
> Fetch the complete documentation index at: https://docs.honeycomb.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Send iOS Data to Honeycomb with Swift

> Instrument your iOS application with the Honeycomb OpenTelemetry Swift SDK and send telemetry to Honeycomb to monitor real device performance.

The [Honeycomb OpenTelemetry Swift SDK](https://github.com/honeycombio/honeycomb-opentelemetry-swift) is Honeycomb's distribution of [OpenTelemetry Swift](https://github.com/open-telemetry/opentelemetry-swift).
It simplifies adding instrumentation to your iOS applications and sending telemetry to Honeycomb.

This page briefly covers usage of the SDK.
If you just want to see some code, check out the [examples on GitHub](https://github.com/honeycombio/honeycomb-opentelemetry-swift/tree/main/Examples).

## Before You Begin

Before you can add instrumentation to your iOS application, you will need to do a few things.

### Get Your Honeycomb API Key

To send data to Honeycomb, you need to:

1. Sign up for a Honeycomb account.
   To sign up, decide whether you would like Honeycomb to store your data in a US-based or EU-based location, then [create a Honeycomb account in the US](https://ui.honeycomb.io/signup) or [create a Honeycomb account in the EU](https://ui.eu1.honeycomb.io/signup).

2. [Create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key).
   To get started, you can create a key that you expect to swap out when you deploy to production.
   Name it something helpful, perhaps noting that it's a Getting Started key.
   Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later!

<Tip>
  For setup, make sure you select the "Can create datasets" checkbox so that your data will show up in Honeycomb.
  Later, when you replace this key with a permanent one, you can uncheck that box.
</Tip>

### Install the Honeycomb Swift SDK

Add [Honeycomb OpenTelemetry Swift](https://github.com/honeycombio/honeycomb-opentelemetry-swift) to your application's dependencies.
The Honeycomb Swift SDK is compatible with applications targeting iOS 13+.

<Tabs>
  <Tab title="Xcode">
    If you manage dependencies in Xcode:

    1. In Xcode, select **File > Add Package Dependencies...**
    2. Enter `https://github.com/honeycombio/honeycomb-opentelemetry-swift` as the repository URL.
    3. Get the version number for the [latest release](https://github.com/honeycombio/honeycomb-opentelemetry-swift/releases).
    4. Add the `Honeycomb` package to your [application's target dependencies](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).
  </Tab>

  <Tab title="Package.swift">
    If you manage dependencies with `Package.swift`:

    1. Add Honeycomb OpenTelemetry Swift as a package dependency:

       ```swift theme={}
       dependencies: [
       .package(url: "https://github.com/honeycombio/honeycomb-opentelemetry-swift.git",
               from: "2.2.1")
       ],
       ```

    2. Add `Honeycomb` as a target dependency:

       ```swift theme={}
       dependencies: [
       .product(name: "Honeycomb", package: "honeycomb-opentelemetry-swift"),
       ],
       ```
  </Tab>
</Tabs>

## Configuration

| Option                                   | Description                                                                                                                                                                                                                                                                                                                                                     |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| APIKey                                   | `String`<br />Your [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key).<br />**Required** if sending telemetry directly to Honeycomb.                                                                                                                                                                                           |
| tracesAPIKey                             | `String`<br />Dedicated Ingest API Key to use when sending traces. Overrides `APIKey` for traces.                                                                                                                                                                                                                                                               |
| metricsAPIKey                            | `String`<br />Dedicated Ingest API Key to use when sending metrics. Overrides `APIKey` for metrics.                                                                                                                                                                                                                                                             |
| logsAPIKey                               | `String`<br />Dedicated Ingest API Key to use when sending logs. Overrides `APIKey` for logs.                                                                                                                                                                                                                                                                   |
| dataset                                  | `String`<br />Name of the [dataset](/configure/datasets/manage/) to send telemetry data to.<br />**Required** if using Honeycomb Classic.                                                                                                                                                                                                                       |
| metricsDataset                           | `String`<br />Name of the dataset to send metrics to. Overrides `dataset` for metrics.                                                                                                                                                                                                                                                                          |
| APIEndpoint                              | `String`<br />Telemetry is sent to this URL. For Honeycomb EU instances set this as `https://api.eu1.honeycomb.io:443`. If you're using an OpenTelemetry Collector, provide your collector URL instead.<br />Default: `https://api.honeycomb.io:443` (US instance)                                                                                              |
| tracesEndpoint                           | `String`<br />API endpoint to send traces to.                                                                                                                                                                                                                                                                                                                   |
| metricsEndpoint                          | `String`<br />API endpoint to send metrics to.                                                                                                                                                                                                                                                                                                                  |
| logsEndpoint                             | `String`<br />API endpoint to send logs to.                                                                                                                                                                                                                                                                                                                     |
| sampleRate                               | `Int`<br />Sample rate to apply. For example, a `sampleRate` of `40` means 1 in 40 traces will be exported. Default: `1`<br />                                                                                                                                                                                                                                  |
| sessionTimeout                           | `TimeInterval`<br />Maximum length of time, in seconds, for a single user session. Used to generate `session.id` span attribute.<br />Default: `TimeInterval(60 * 60 * 4)` (4 hours)                                                                                                                                                                            |
| serviceName                              | `String`<br />The name of your application. Used as the value for `service.name` resource attribute.                                                                                                                                                                                                                                                            |
| serviceVersion                           | `String`<br />Current version of your application. Used as the value for `service.version` resource attribute.                                                                                                                                                                                                                                                  |
| resourceAttributes                       | `Dictionary<String, String>`<br />Attributes to attach to outgoing resources.                                                                                                                                                                                                                                                                                   |
| headers                                  | `Dictionary<String, String>`<br />Headers to add to exported telemetry data.                                                                                                                                                                                                                                                                                    |
| tracesHeaders                            | `Dictionary<String, String>`<br />Headers to add to exported trace data.                                                                                                                                                                                                                                                                                        |
| metricsHeaders                           | `Dictionary<String, String>`<br />Headers to add to exported metrics data.                                                                                                                                                                                                                                                                                      |
| logsHeaders                              | `Dictionary<String, String>`<br />Headers to add to exported logs data.                                                                                                                                                                                                                                                                                         |
| timeout                                  | `TimeInterval`<br />Timeout used by exporter when sending data.                                                                                                                                                                                                                                                                                                 |
| tracesTimeout                            | `TimeInterval`<br />Timeout used by traces exporter. Overrides `timeout` for trace data.                                                                                                                                                                                                                                                                        |
| metricsTimeout                           | `TimeInterval`<br />Timeout used by metrics exporter. Overrides `timeout` for metrics data.                                                                                                                                                                                                                                                                     |
| logsTimeout                              | `TimeInterval`<br />Timeout used by logs exporter. Overrides `timeout` for logs data.                                                                                                                                                                                                                                                                           |
| protocol                                 | `enum HoneycombOptions.OTLPProtocol`<br />Protocol to use when sending data.<br />Default: `.httpProtobuf`                                                                                                                                                                                                                                                      |
| tracesProtocol                           | `enum HoneycombOptions.OTLPProtocol`<br />Overrides `protocol` for trace data.                                                                                                                                                                                                                                                                                  |
| metricsProtocol                          | `enum HoneycombOptions.OTLPProtocol`<br />Overrides `protocol` for metrics data.                                                                                                                                                                                                                                                                                |
| logsProtocol                             | `enum HoneycombOptions.OTLPProtocol`<br />Overrides `protocol` for logs data.                                                                                                                                                                                                                                                                                   |
| spanProcessor                            | `OpenTelemetryApi.SpanProcessor`<br />Additional span processor to use.                                                                                                                                                                                                                                                                                         |
| metricKitInstrumentationEnabled          | `Bool`<br />Enable MetricKit instrumentation.<br />Default: `true`                                                                                                                                                                                                                                                                                              |
| urlSessionInstrumentationEnabled         | `Bool`<br />Enable URLSession instrumentation.<br />Default: `true`                                                                                                                                                                                                                                                                                             |
| uiKitInstrumentationEnabled              | `Bool`<br />Enable UIKit view instrumentation.<br />Default: `true`                                                                                                                                                                                                                                                                                             |
| touchInstrumentationEnabled              | `Bool`<br />Enable UIKit touch instrumentation. Default: `false`                                                                                                                                                                                                                                                                                                |
| unhandledExceptionInstrumentationEnabled | `Bool`<br />Enable unhandled exception instrumentation.<br />Default: `true`                                                                                                                                                                                                                                                                                    |
| offlineCachingEnabled                    | `Bool`<br />Enable offline caching for telemetry. When offline caching is enabled, telemetry is cached during network failures. The SDK will retry exporting telemetry for up to 18 hours. Offline caching also adds a minimum delay of 5 seconds to telemetry exports.<br />**Offline caching is an alpha feature and may be unstable.**<br />Default: `false` |

### Enable Auto-Instrumentation

[Automatic instrumentation packages](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#auto-instrumentation) are enabled or disabled in your configuration.

```swift theme={}
import Honeycomb
import SwiftUI

@main
struct ExampleApp: App {
    init() {
        do {
            let options = try HoneycombOptions.Builder()
                .setAPIKey("YOUR-API-KEY")
                .setServiceName("YOUR-SERVICE-NAME")
                // Enable or disable auto-instrumentation packages
                .setMetricKitInstrumentationEnabled(true)
                .setURLSessionInstrumentationEnabled(true)
                .setUIKitInstrumentationEnabled(true)
                .setTouchInstrumentationEnabled(false)
                .setUnhandledExceptionInstrumentationEnabled(true)
                .setDebug(true)
                .build()
            try Honeycomb.configure(options: options)
        } catch {
            NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise()
        }
    }

    var body: some Scene {
        Text("Hello world!")
    }
}
```

### Add Resource Attributes

Resource attributes are available on every span your instrumentation emits.
Adding custom, application-specific attributes makes it easier to correlate your data to important business information.

You can add extra resource attributes during SDK configuration with the `.setResourceAttributes()` method.

```swift theme={}
import Honeycomb
import SwiftUI

@main
struct ExampleApp: App {
    init() {
        do {
            let options = try HoneycombOptions.Builder()
                .setAPIKey("YOUR-API-KEY")
                .setServiceName("YOUR-SERVICE-NAME")
                .setDebug(true)
                .setResourceAttributes(["app.ab_test": "test c"])
                .build()
            try Honeycomb.configure(options: options)
        } catch {
            NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise()
        }
    }

    var body: some Scene {
        Text("Hello world!")
    }
}
```

### Enable Sampling

The Honeycomb Swift SDK includes optional [deterministic head sampling](/manage-data-volume/sample/).
To enable sampling, call `.setSampleRate()` with your desired sample rate as an `Int` value.
The sample rate is `1` by default, meaning every trace is exported.

The example below sets a `sampleRate` of `40`, meaning 1 in 40 traces will be exported.

```swift theme={}
// ...
let options = try HoneycombOptions.Builder()
                .setAPIKey("YOUR-API-KEY")
                .setServiceName("YOUR-SERVICE-NAME")
                .setServiceVersion("0.0.1")
                .sampleRate(40)
                .setDebug(true)
                .build()
            try Honeycomb.configure(options: options)
```

## Custom Instrumentation

Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, or manual, instrumentation.

To add your own custom instrumentation, [include the OpenTelemetryApi as a dependency](https://github.com/open-telemetry/opentelemetry-swift) in your application.

### Add Attributes to an Active Span

You can retrieve the currently active span in a trace and add attributes to it.
This lets you add more context to traces and gives you more ways to group or filter traces in your queries:

```swift theme={}
import OpenTelemetryApi

func applyDiscountCode(discountCode: String) {
  let currentSpan = OpenTelemetry.instance.contextProvider.activeSpan
  currentSpan.setAttribute("app.cart.discount_code", discountCode)
}
```

In the above example, we add an `app.cart.discount_code` attribute to the current span.
This lets us use the `app.cart.discount_code` field in `WHERE` or `GROUP BY` clauses in the Honeycomb query builder.

### Acquire a Tracer

For manual tracing, you need to acquire a tracer:

```swift theme={}
import OpenTelemetryApi

let tracer = OpenTelemetry.instance.tracerProvider.get(
    instrumentationName: "my-application-tracer",
    instrumentationVersion: "1.0.0"
)
```

### Create Spans

Create custom spans to get a clear view of the critical parts in your application.

```swift theme={}
import OpenTelemetryApi

let tracer = OpenTelemetry.instance.tracerProvider.get(
    instrumentationName: "my-application-tracer",
    instrumentationVersion: "1.0.0"
)

func generateNewLevel() {
  let span = tracer.spanBuilder(spanName: "newLevel").startSpan()
  // do some work
  span.end()
}
```

## Custom Span Processing

Span processors provide hooks for when a span starts and when it ends.
This lets you mutate spans after they have been created by automatic or manual instrumentation.

Here's a basic example of a span processor that adds an attribute to spans when they start:

```swift theme={}
import Foundation
import OpenTelemetryApi
import OpenTelemetrySdk

internal class BasicSpanProcessor: SpanProcessor {
    public let isStartRequired = true
    public let isEndRequired = false

    public func onStart(
        parentContext: SpanContext?,
        span: any ReadableSpan
    ) {
        span.setAttribute(
            key: "app.metadata",
            value: "extra metadata"
        )
    }

    func onEnd(span: any OpenTelemetrySdk.ReadableSpan) {}

    func shutdown(explicitTimeout: TimeInterval?) {}

    func forceFlush(timeout: TimeInterval?) {}
}
```

Add the span processor to your SDK configuration to enable it:

```swift theme={}
import Honeycomb
import SwiftUI

@main
struct ExampleApp: App {
    init() {
        do {
            let options = try HoneycombOptions.Builder()
                .setAPIKey("YOUR-API-KEY")
                .setServiceName("YOUR-SERVICE-NAME")
                .setSpanProcessor(BasicSpanProcessor())
                .setDebug(true)
                .build()
            try Honeycomb.configure(options: options)
        } catch {
            NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise()
        }
    }

    var body: some Scene {
        Text("Hello world!")
    }
}
```

## Manual Instrumentation Utilities

The Honeycomb Swift SDK provides utilities for manually instrumenting [SwiftUI views](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#swiftui-view-instrumentation), [SwiftUI navigation](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#swiftui-navigation-instrumentation), and [logging errors or exceptions](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#manual-error-logging).

* [Example: SwiftUI View Instrumentation](https://github.com/honeycombio/honeycomb-opentelemetry-swift/blob/main/Examples/SmokeTest/SmokeTest/ViewInstrumentationView.swift)
* [Example: SwiftUI Navigation Instrumentation](https://github.com/honeycombio/honeycomb-opentelemetry-swift/blob/main/Examples/SmokeTest/SmokeTest/NavigationExamplesView.swift)

### SwiftUI View

Trace render timings of your views by wrapping them with `HoneycombInstrumentedView(name: String)`.

```swift theme={}
var body: some View {
    HoneycombInstrumentedView(name: "main view") {
        VStack {
            Text("Hello main view!")
        }
    }
}
```

### SwiftUI Navigation

The SDK provides a view modifier for manually tracing a [NavigationStack](https://developer.apple.com/documentation/swiftui/navigationstack) when you are [managing navigation state externally](https://developer.apple.com/documentation/swiftui/navigationstack#Manage-navigation-state).

The `instrumentNavigation(path: String)` view modifier creates spans on `path` changes (`NavigationTo`, `NavigationFrom`) with attributes for the full navigation path and what triggered the navigation.

```swift theme={}
import Honeycomb
import SwiftUI

struct Fruit: Identifiable, Equatable, Hashable, Codable {
    let name: String
    let color: String
    var id: String {
        name
    }
}

let fruits = [
    Fruit(name: "Apple", color: "Red"),
    Fruit(name: "Banana", color: "Yellow"),
]

func fruit(from id: Fruit.ID?) -> Fruit? {
    if let fruitId = id {
        if let index = fruits.firstIndex(where: { $0.id == fruitId }) {
            return fruits[index]
        }
    }
    return nil
}

struct FruitDetails: View {
    let fruit: Fruit
    var body: some View {
        Text("\(fruit.name) is \(fruit.color)")
    }
}

struct ExampleNavigationStackView: View {
    @State private var presentedFruits: [Fruit] = []
    var body: some View {
        NavigationStack(path: $presentedFruits) {
            List(fruits) { fruit in
                NavigationLink(fruit.name, value: fruit)
            }
            .navigationDestination(for: Fruit.self) { fruit in
                FruitDetails(fruit: fruit)
            }
        }
        .instrumentNavigation(path: presentedFruits) // View Modifier
    }
}
```

For other navigation components, such as `TabView` or `NavigationSplitView`, you can use the `Honeycomb.setCurrentScreen(path: Any)` function to trace navigation.

```swift theme={}
import Honeycomb
import SwiftUI

struct ExampleTabView: View {
    var body: some View {
        TabView {
            ViewA()
                .padding()
                .tabItem { Label("View A") }
                .onAppear {
                    Honeycomb.setCurrentScreen(path: "View A")
                }

            ViewB()
                .padding()
                .tabItem { Label("View B") }
                .onAppear {
                    Honeycomb.setCurrentScreen(path: "View B")
                }

            ViewC()
                .padding()
                .tabItem { Label("View C") }
                .onAppear {
                    Honeycomb.setCurrentScreen(path: "View C")
                }
        }
    }
}
```

### Log Errors and Exceptions

The `Honeycomb.log()` method records any `Error`, `NSError`, or `NSException` as a log record.
You can use `Honeycomb.log()` for logging exceptions you catch in your own code that are not logged by the SDK.

```swift theme={}
do {
    try thisFunctionMayThrow()
}
catch let error {
    Honeycomb.log(
        error: error,
        attributes: [
            "user.name": AttributeValue.string(currentUser.name),
            "user.id": AttributeValue.int(currentUser.id)
        ],
        thread: Thread.current
    );
}
```

## Trace Header Propagation

If you are connecting your app to a backend service that you wish to view as a unified trace with your app, you will need to manually add headers to all your outgoing requests.
You must also create a span and set it as the active span.
The span's context will be used to generate the headers needed for trace propagation.

```swift theme={}
import OpenTelemetryApi

private struct HttpTextMapSetter: Setter {
    func set(carrier: inout [String: String], key: String, value: String) {
        carrier[key] = value
    }
}

private let textMapSetter = HttpTextMapSetter()

func makeBackendRequest(data: Data) async throws {
    let url = URL(string: "https://mybackendservice")
    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    request.httpBody = data

    let allHeaders: [String: String] = []

    let span = OpenTelemetry.instance.tracerProvider.get(
        instrumentationName: "mybackendservice.network",
        instrumentationVersion: getCurrentAppVersion()
    )
    .spanBuilder(spanName: "backendRequest")
    // The span must be made the active span or else the network autoinstrumentation 
    // will not be attached to the trace.
    .setActive(true)
    .startSpan()
    defer {
        span.end()
    }

    // Add the required headers to the `allHeaders` Dictionary
    OpenTelemetry.instance.propagators.textMapPropagator.inject(
        spanContext: span.context,
        carrier: &allHeaders,
        setter: textMapSetter
    )

    allHeaders.forEach({ (key: String, value: String) in
        request.setValue(value, forHTTPHeaderField: key)
    })

    let session = URLSession(configuration: URLSessionConfiguration.default)

    let (data, response) = try await session.data(for: request)

     // process your response data as normal
}
```

## Troubleshooting

To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions).
