iOS RUM SDK
Install and configure the Last9 iOS RUM SDK. Swift API, CDN-hosted CocoaPods podspec and SPM XCFramework, automatic instrumentation for sessions, views, network, errors, and resource sampling.
Real User Monitoring for iOS apps. Automatic instrumentation for sessions, views, network requests, errors, and resource metrics via OpenTelemetry.
Prerequisites
- iOS 15.1+
- Swift 5.9+
- Dependencies (resolved transitively):
OpenTelemetry-Swift-Api ~> 1.10,OpenTelemetry-Swift-Sdk ~> 1.10 - A Last9 RUM client token and OTLP endpoint
CDN artifacts
| Artifact | URL |
|---|---|
| Podspec | https://cdn.last9.io/rum-sdk/ios/builds/0.3.1/Last9RUM.podspec |
| XCFramework | https://cdn.last9.io/rum-sdk/ios/builds/0.3.1/Last9RUM.xcframework.zip |
| Checksum | https://cdn.last9.io/rum-sdk/ios/builds/0.3.1/Last9RUM.xcframework.zip.sha256 |
Staging builds use the -alpha suffix.
Installation
-
Add to your
Podfilepod 'Last9RUM', :podspec => 'https://cdn.last9.io/rum-sdk/ios/builds/0.3.1/Last9RUM.podspec' -
Install
pod install
-
Fetch the checksum
curl -sL https://cdn.last9.io/rum-sdk/ios/builds/0.3.1/Last9RUM.xcframework.zip.sha256 -
Add a binary target to
Package.swift.binaryTarget(name: "Last9RUM",url: "https://cdn.last9.io/rum-sdk/ios/builds/0.3.1/Last9RUM.xcframework.zip",checksum: "<sha256 from previous step>")
Initialization
import Last9RUM
@mainclass AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool {
var config = L9RumConfig( baseUrl: "https://otlp-ext-aps1.last9.io/v1/otlp/organizations/<org>", clientToken: "your-client-token", serviceName: "my-ios-app", serviceVersion: "1.0.0", deploymentEnvironment: "production" ) config.origin = "https://app.last9.io"
L9Rum.shared.initialize(config: config) return true }}import Last9RUMimport SwiftUI
@mainstruct MyApp: App { init() { var config = L9RumConfig( baseUrl: "https://otlp-ext-aps1.last9.io/v1/otlp/organizations/<org>", clientToken: "your-client-token", serviceName: "my-ios-app", serviceVersion: "1.0.0", deploymentEnvironment: "production" ) config.origin = "https://app.last9.io" L9Rum.shared.initialize(config: config) }
var body: some Scene { WindowGroup { ContentView() } }}Configuration
var config = L9RumConfig( // --- Required --------------------------------------------------------- baseUrl: "https://otlp-ext-aps1.last9.io/v1/otlp/organizations/<org>", clientToken: "your-client-token", serviceName: "my-ios-app", serviceVersion: "1.0.0", deploymentEnvironment: "production")
// --- Optional -------------------------------------------------------------
// Origin sent as X-LAST9-ORIGIN header.// Required for client_monitoring tokens.config.origin = "https://app.last9.io"
// Specific build identifier (maps to app.build_id)config.appBuildId = "1.0.0-build-42"
// Unique per-install ID (NOT a hardware ID). Persists across launches.config.appInstallationId = nil
// Session sampling rate: 0-100 (percentage). 100 = sample everything.config.sampleRate = 100
// Print debug logs to consoleconfig.debugLogs = false
// Automatically trace HTTP requests via URLProtocolconfig.networkInstrumentation = true
// Automatically capture unhandled exceptionsconfig.errorInstrumentation = true
// Max spans per export batchconfig.maxExportBatchSize = 100
// Export timeout in millisecondsconfig.exportTimeoutMs = 30_000
// Periodically sample memory and CPUconfig.resourceMonitoringEnabled = true
// Interval between resource samples (ms)config.resourceSamplingIntervalMs = 30_000
// When true, each HTTP request gets its own traceId// instead of sharing the current view's traceIdconfig.isolateTracePerRequest = false
// Custom resource attributes added to every spanconfig.resourceAttributes = [ "app.platform": "ios",]
// W3C Baggage propagation on outgoing requestsconfig.baggage = L9BaggageConfig()config.baggage.enabled = falseconfig.baggage.allowedKeys = ["session.id", "user.id"]config.baggage.maxTotalBytes = 8192config.baggage.trackedUrlPatterns = []config.baggage.warnAtPercentage = 80API reference
Identify a user
L9Rum.shared.identify(userId: "user-123", attributes: [ "email": "user@example.com", "plan": "premium",])Clear user on sign-out
L9Rum.shared.clearUser()Capture errors
do { try riskyOperation()} catch { L9Rum.shared.captureError(error, context: ["screen": "checkout"])}Track views
L9Rum.shared.startView("ProductDetailsScreen")L9Rum.shared.setViewName("Product #42")Custom events
L9Rum.shared.addEvent("purchase_completed", attributes: [ "product_id": "12345", "amount": 29.99,])Global span attributes
// Inject attributes into every spanL9Rum.shared.spanAttributes([ "experiment": "checkout_v2", "feature_flag": "new_cart",])
// ClearL9Rum.shared.spanAttributes(nil)Session ID
let sessionId: String? = L9Rum.shared.getSessionId()Flush pending data
L9Rum.shared.flush()Next steps
Once data is flowing, explore it in Discover > Applications — performance, errors, and sessions.
Troubleshooting
Please get in touch with us on Discord or Email if you have any questions.