Mobile RUM - iOS SDK

The Mobile RUM SDK provides a customizable suite of tools to analyze and optimize the performance of iOS applications. Track network changes, detect crashes, identify slow or frozen frames and more. To see an example of how to deploy the Mobile RUM iOS SDK, navigate to our GitHub repository.

Prerequisites

iOS 13+, macOS 10.15+, and tvOS 13+ are supported. Confirm the available SDKs with:

1xcodebuild -showsdks

Tip: Ensure your app targets HTTPS endpoints; iOS App Transport Security (ATS) blocks clear‑text HTTP by default.

Install & Instrument Your iOS Application

1 Install Swift Package

Add the package to your project using Swift Package Manager. This brings in the RUM runtime and public APIs used below. Package.swift (server‑side or multi‑package setups):

1.package(url: "https://github.com/middleware-labs/middleware-ios", from: "1.0.0"),

Xcode UI: In Xcode, File → Add Packages…, paste the repository URL, select the version rule (exact or up to next major), and add the package to your app target.

2 Initialize Middleware iOS SDK

Initialise the SDK as early as possible so the app starts and the first screen is captured. The example below shows a SwiftUI app initialising in App.init(). Provide your target, access token, and identity fields (serviceName, projectName, deploymentEnvironment). Add a stable release tag via globalAttributes(["app.version": …]) to correlate sessions and crashes with deployments.

1import SwiftUI
2import MiddlewareRum
3
4@main
5struct YourApp: App {
6    init() {
7        do {
8            try MiddlewareRumBuilder()
9                .globalAttributes(["app.version" : "1.0.0"])
10                .target("<target>")
11                .serviceName("Mobile-SDK-iOS")
12                .projectName("Mobile-SDK-iOS")
13                .rumAccessToken("<MW_API_KEY>")
14                .deploymentEnvironment("PROD")
15                .build()
16        } catch {
17            // Handle init errors (e.g., invalid config)
18            print("RUM init error: \(error)")
19        }
20    }
21
22    var body: some Scene {
23        WindowGroup { ContentView() }
24    }
25}

UIKit AppDelegate example (for non‑SwiftUI projects):

1import UIKit
2import MiddlewareRum
3
4@main
5class AppDelegate: UIResponder, UIApplicationDelegate {
6    func application(_ application: UIApplication,
7                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
8        do {
9            try MiddlewareRumBuilder()
10                .globalAttributes(["app.version" : Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""]) 
11                .target("<target>")
12                .serviceName("MyApp")
13                .projectName("MyApp")
14                .rumAccessToken("<MW_API_KEY>")
15                .deploymentEnvironment("PROD")
16                .build()
17        } catch {
18            print("RUM init error: \(error)")
19        }
20        return true
21    }
22}

Consent gating (optional): If you gate analytics on user consent, perform the MiddlewareRumBuilder() initialisation only after consent is granted. To disable just session recording (keeping metrics/logs), see Session Recording below.

Custom Configurations

Logs

Use logs to capture notable client‑side events and correlate them with sessions and replays. Prefer concise, structured messages; avoid secrets.

1MiddlewareRum.info("Some information")
2MiddlewareRum.debug("Some information")
3MiddlewareRum.trace("Some information")
4MiddlewareRum.warning("Some information")
5MiddlewareRum.error("Some information")
6MiddlewareRum.critical("Some information")

Errors to Traces

Promote important errors to traces so they’re visible in APM views and timelines.

1MiddlewareRum.addError("Error, unable to process")

Exceptions

Crashes are captured automatically; use exceptions for handled failures you still want to investigate.

1MiddlewareRum.addException(e: NSException(name: NSExceptionName(rawValue: "RuntimeException"),
2                                          reason: "I am a custom exception"))

Set Your Screen Name

Name key screens to make navigation and drill‑downs easier in dashboards (pair with Routing/URL where available).

1MiddlewareRum.setScreenName("WebView")

Set Global Attributes

Attach stable keys (release, plan, tenant) used for filtering and grouping. Avoid PII; prefer IDs or hashed values.

1MiddlewareRum.setGlobalAttributes(["some": "value"])

WebView Instrumentation

If your app embeds web content, integrate the WebView so Browser RUM and Mobile RUM can be correlated for hybrid journeys.

1MiddlewareRum.integrateWebViewWithBrowserRum(view: webView)

Session Recording

Session Replay captures what the user saw and did—use it to understand regressions and validate fixes. Recordings are batched and uploaded efficiently.

  • Maximum duration: 4 hours per session.
  • Idle timeout: 15 minutes of inactivity ends the recording; activity after the timeout creates a new session.
  • Default: Recording is enabled. To disable it at initialisation, call .disableRecording() on the builder.

Disable recording example:

1try MiddlewareRumBuilder()
2    .globalAttributes(["customerId" : "123456"])
3    .target("<target>")
4    .serviceName("Mobile-SDK-iOS")
5    .projectName("Mobile-SDK-iOS")
6    .rumAccessToken("<MW_API_KEY>")
7    .deploymentEnvironment("PROD")
8    .disableRecording()
9    .build()

Privacy

Masking happens on‑device before upload. Mark views that may contain sensitive content (payments, OTPs, tokens) so they are blurred in all recordings. Password fields are masked automatically by default.

1// SwiftUI
2Text("Very important sensitive text").sensitive()
3
4// UIKit
5MiddlewareRum.addIgnoredView(view)

Review high‑risk screens regularly and apply masking to any additional fields that could contain secrets or PII.

Instrumentation Attributes

Use the following builder methods to configure the SDK. These switches impact client‑side collection and do not require server changes.

MethodDescription
.rumAccessToken(String)Sets RUM account access token to authorize client to send telemetry to Middleware
.target(String)Sets target URL to the location you will send telemetry data to (e.g., your Middleware ingest URL)
.serviceName(String)Sets service name for your application
.deploymentEnvironment(String)Sets environment attribute on spans generated by instrumentation(e.g. PROD & DEV)
.disableCrashReportingInstrumentation()Disable crash reporting (which is enabled by default)
.disableNetworkMonitoring()Disable HTTP Instrumentation (which is enabled by default)
.disableSlowRenderingDetection()Disable slow/frozen frame renders (which is enabled by default)
.slowFrameDetectionThresholdMs(Double)Sets default polling for slow render detection. Default value is 16.7 milliseconds
.frozenFrameDetectionThresholdMs(Double)Sets default polling for frozen render detection. Default value is 700 milliseconds

Troubleshooting

Start here if data isn’t appearing or specific signals are missing.

  • No data appears: Verify rumAccessToken and target are correct, and that initialisation runs once at app start. Check that your device has network connectivity.
  • Nothing from web content: Ensure you’ve called integrateWebViewWithBrowserRum(view:) on the active WebView instance.
  • High slow/frozen frame counts: Reduce main‑thread work. A frame > 16.7 ms is considered slow; > 700 ms is frozen. Profile with Instruments (Time Profiler, Core Animation).
  • Privacy concerns: Confirm sensitive views are annotated with .sensitive() (SwiftUI) or addIgnoredView (UIKit). Review masking after UI changes.
  • ATS blocked calls: The iOS ATS policy blocks non‑TLS endpoints; ensure your APIs and target use HTTPS. For dev‑only exceptions, add scoped ATS exceptions in Info.plist.

Need assistance or want to learn more about Middleware? Contact our support team at [email protected] or join our Slack channel.