iOS app in SwiftUI instrumentation

SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

Overview

This document contains instructions on how to set up OpenTelemetry instrumentation in your iOS applications built using Swift and view your application traces in SigNoz.

Prerequisites

  • A SwiftUI-based iOS application in Xcode.
  • Swift toolchain installed; see Swift getting started.
  • Access to a SigNoz Cloud account or self-hosted SigNoz instance.

Send traces to SigNoz

You can test the sample app for SwiftUI.

Step 1: Add OpenTelemetry dependencies

Install opentelemetry-swift and grpc-swift in Package.swift.

Package.swift
dependencies: [
      .package(url: "https://github.com/open-telemetry/opentelemetry-swift.git", .upToNextMajor(from: "1.9.1")),
      .package(url: "https://github.com/grpc/grpc-swift", from: "1.15.0"),
  ],
  targets: [
      .executableTarget(
          name: "<service_name>",
          dependencies: [
              .product(name: "OpenTelemetryApi", package: "opentelemetry-swift"),
              .product(name: "OpenTelemetrySdk", package: "opentelemetry-swift"),
              .product(name: "StdoutExporter", package: "opentelemetry-swift"),
              .product(name: "ResourceExtension", package: "opentelemetry-swift"),
              .product(name: "ZipkinExporter", package: "opentelemetry-swift"),
              .product(name: "OpenTelemetryProtocolExporter", package: "opentelemetry-swift"),
              .product(name: "SignPostIntegration", package: "opentelemetry-swift"),
              .product(name: "GRPC", package: "grpc-swift")
          ],
          path: "."
      )
  ]

<service_name> is the name of your service.

Step 2: Initialize the tracer

Create OpentelemetrySetup.swift and configure the exporter.

OpentelemetrySetup.swift
// OpenTelemetrySetup.swift
import Foundation
import GRPC
import NIO
import NIOSSL
import OpenTelemetryApi
import OpenTelemetryProtocolExporterCommon
import OpenTelemetryProtocolExporterGrpc
import OpenTelemetrySdk
import ResourceExtension
import StdoutExporter

struct OpenTelemetrySetup {
    static func configureOpenTelemetry() {
        let resource = DefaultResources().get().merging(other: Resource(attributes: [
            "service.name": AttributeValue.string("<service_name>"),
            "service.version": AttributeValue.string("<service_version>"),
        ]))
        
        let otlpConfiguration: OtlpConfiguration = OtlpConfiguration(timeout: TimeInterval(10), headers: [("signoz-ingestion-key", "<your-ingestion-key>")])
        
        let grpcChannel = ClientConnection.usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads: 1)).connect(host: "ingest.<region>.signoz.cloud", port: 443)
        
        let otlpTraceExporter = OtlpTraceExporter(channel: grpcChannel, config: otlpConfiguration)
        let stdoutExporter = StdoutExporter()
        
        let spanExporter = MultiSpanExporter(spanExporters: [otlpTraceExporter, stdoutExporter])
        
        let spanProcessor = SimpleSpanProcessor(spanExporter: spanExporter)
        
        OpenTelemetry.registerTracerProvider(tracerProvider:
            TracerProviderBuilder()
                .add(spanProcessor: spanProcessor)
                .with(resource: resource)
                .build()
        )
    }
}

Verify these values:

  • <service_name>: logical name of your iOS service; this is what you will see in SigNoz.
  • <service_version> (optional): Your release version, image tag, or git SHA (e.g., 1.4.2, a01dbef8).
  • <your-ingestion-key>: Your SigNoz ingestion key
  • <region>: Your SigNoz Cloud region

Set service.version to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:

  • Bash / shell: service.version=$(git rev-parse --short HEAD)
  • GitHub Actions: service.version=${{ github.sha }}
  • GitLab CI: service.version=$CI_COMMIT_SHORT_SHA
  • Kubernetes: inject from your Helm chart image tag or CI variable

Using self-hosted SigNoz? Most steps are identical. Update the endpoint and remove the ingestion key header as shown in Cloud → Self-Hosted.

Once you replace the content of the file, you need to add init in the <project_name>.swift file

init() {
        OpenTelemetrySetup.configureOpenTelemetry()
    }

Step 3: Send telemetry data to SigNoz

To send telemetry data to SigNoz, you can create a function to add spans and data. But prior to that you need to import OpenTelemetryApi & create instance of tracer, using the following snippet

ContentView.swift
import OpenTelemetryApi // Import OpenTelemetryApi for the tracer

//this should be inside ContentView Struct
let tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "SwiftExample", instrumentationVersion: "semver:0.1.0")

// Function to simulate work and create a span
    func doWork() {
        let sampleKey = "sampleKey"
        let sampleValue = "sampleValue"
        
        // Start a new span named "doWork"
        let childSpan = tracer.spanBuilder(spanName: "doWork")
            .setSpanKind(spanKind: .client)
            .startSpan()
        
        // Set an attribute on the span
        childSpan.setAttribute(key: sampleKey, value: sampleValue)
        
        // Simulate some work by sleeping for a random interval
        Thread.sleep(forTimeInterval: Double.random(in: 0 ..< 10) / 100)
        
        // End the span
        childSpan.end()
    }
    

Step 4: Run the app

Run your application from Xcode.

Validate

  • In SigNoz, go to Traces Explorer and confirm that the traces for your service (for example <service_name>) are present.
  • Open a recent trace and verify that spans from your iOS app are present with the attributes you set.

Troubleshooting

  • If you do not see your iOS service in SigNoz, confirm the endpoint/port is reachable from the simulator or device and that the ingestion key (for Cloud) is correct.

Next steps

Last updated: May 27, 2026

Edit on GitHub

Was this page helpful?

Your response helps us improve this page.