Hero
Back to all guides

How to Add Analytics to Swift Apps

Add privacy-first analytics to your iOS, macOS, tvOS, and watchOS apps with OpenPanel's Swift SDK.

OpenPanel Team

12/15/2025

Beginner
10 min

Introduction

Understanding how users interact with your native Apple apps requires solid analytics. OpenPanel's Swift SDK gives you event tracking, user identification, and screen view analytics across iOS, macOS, tvOS, and watchOS platforms.

Since native apps can't rely on CORS headers for authentication like web apps do, the Swift SDK uses a client secret for secure server-side authentication. This makes it suitable for production apps where you need reliable, privacy-respecting analytics. OpenPanel is an open-source alternative to Mixpanel and Amplitude that you can self-host for complete data ownership.

Prerequisites

  • Xcode project set up (iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+)
  • OpenPanel account (sign up free)
  • Your Client ID and Client Secret from the OpenPanel dashboard

Important: Native app tracking requires a clientSecret for authentication.

Step 1: Add Swift package

The OpenPanel Swift SDK is distributed through Swift Package Manager. Open your project in Xcode, then go to File and select Add Packages. Enter the repository URL and click Add Package.

https://github.com/Openpanel-dev/swift-sdk

If you're working with a Package.swift file directly, add OpenPanel as a dependency instead.

dependencies: [
    .package(url: "https://github.com/Openpanel-dev/swift-sdk")
]

Step 2: Initialize OpenPanel

Before tracking any events, you need to initialize the SDK when your app launches. This should happen early in your app's lifecycle so the SDK is available throughout your application.

For UIKit apps, add the initialization to your AppDelegate's application(_:didFinishLaunchingWithOptions:) method.

AppDelegate.swift
import UIKit
import OpenPanel

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        OpenPanel.initialize(options: .init(
            clientId: "YOUR_CLIENT_ID",
            clientSecret: "YOUR_CLIENT_SECRET"
        ))
        
        return true
    }
}

For SwiftUI apps, initialize the SDK in your App struct's initializer.

MyApp.swift
import SwiftUI
import OpenPanel

@main
struct MyApp: App {
    init() {
        OpenPanel.initialize(options: .init(
            clientId: "YOUR_CLIENT_ID",
            clientSecret: "YOUR_CLIENT_SECRET"
        ))
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Automatic lifecycle tracking

You can enable automatic lifecycle tracking by setting automaticTracking: true. This will track app_opened and app_closed events for you.

OpenPanel.initialize(options: .init(
    clientId: "YOUR_CLIENT_ID",
    clientSecret: "YOUR_CLIENT_SECRET",
    automaticTracking: true
))

Step 3: Track events

Once initialized, you can track events anywhere in your app by calling OpenPanel.track. Each event has a name and optional properties that provide additional context.

SignupButton.swift
import SwiftUI
import OpenPanel

struct SignupButton: View {
    var body: some View {
        Button("Sign Up") {
            OpenPanel.track(
                name: "button_clicked",
                properties: [
                    "button_name": "signup",
                    "button_location": "hero"
                ]
            )
        }
    }
}

Properties can be any key-value pairs relevant to the event. Common patterns include tracking form submissions, purchases, and feature usage. Keep event names consistent across your app by using snake_case and being descriptive about what action occurred.

Set global properties

If you have properties that should be sent with every event, set them once using setGlobalProperties. This is useful for app version, build number, or device information.

OpenPanel.setGlobalProperties([
    "app_version": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "",
    "platform": UIDevice.current.systemName
])

Step 4: Identify users

When a user signs in, call identify to associate their events with their profile. This enables you to track user journeys across sessions and understand individual user behavior.

AuthService.swift
OpenPanel.identify(payload: IdentifyPayload(
    profileId: user.id,
    firstName: user.firstName,
    lastName: user.lastName,
    email: user.email,
    properties: [
        "plan": user.plan,
        "signup_date": user.createdAt.ISO8601Format()
    ]
))

The profileId should be a unique identifier for the user, typically from your authentication system. Additional properties like firstName, lastName, and email help you recognize users in your dashboard.

Clear user data on logout

When a user logs out, call clear to reset the local state. This ensures subsequent events aren't incorrectly attributed to the previous user.

func logout() {
    OpenPanel.clear()
}

Increment user properties

You can also increment numeric properties on user profiles. This is useful for tracking counts like logins or purchases without needing to fetch and update the current value.

OpenPanel.increment(payload: IncrementPayload(
    profileId: user.id,
    property: "login_count"
))

Step 5: Track screen views

Tracking screen views helps you understand how users navigate through your app. In SwiftUI, use the onAppear modifier to track when a view becomes visible.

HomeView.swift
struct HomeView: View {
    var body: some View {
        VStack {
            Text("Home")
        }
        .onAppear {
            OpenPanel.track(
                name: "screen_view",
                properties: ["screen_name": "HomeScreen"]
            )
        }
    }
}

In UIKit, override viewDidAppear in your view controllers.

HomeViewController.swift
class HomeViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        OpenPanel.track(
            name: "screen_view",
            properties: [
                "screen_name": "HomeScreen",
                "screen_class": String(describing: type(of: self))
            ]
        )
    }
}

The OpenPanel SDK is designed to be thread-safe. You can call its methods from any thread without additional synchronization.

Verify your setup

Run your app in the simulator or on a physical device and perform some actions. Navigate between screens and tap a few buttons to generate events. Then open your OpenPanel dashboard and check the real-time view.

Not seeing events?

  • Check the Xcode console for any error messages
  • Verify that your Client ID and Client Secret are correct
  • Confirm that you included the clientSecret parameter (required for native apps)
  • Test with a stable network connection first

Next steps

The Swift SDK reference covers additional configuration options like event filtering and disabling tracking. If you're building a cross-platform mobile app, the React Native analytics guide shows how to set up OpenPanel in that environment.

FAQ

Why do I need a clientSecret for native apps?

Native apps can't use CORS headers for authentication like web applications can. The clientSecret provides secure server-side authentication for your events, ensuring they're properly validated before being recorded.

Does OpenPanel work with both SwiftUI and UIKit?

Yes. OpenPanel works with both UIKit and SwiftUI. Use the .onAppear modifier in SwiftUI views or lifecycle methods like viewDidAppear in UIKit view controllers to track screen views and other events.

Can I track events when the user is offline?

OpenPanel queues events locally and sends them when network connectivity is restored. Events won't be lost if the user temporarily goes offline.

Is OpenPanel GDPR compliant?

Yes. OpenPanel is designed for GDPR compliance with data minimization and support for data subject rights. With self-hosting, you also eliminate international data transfer concerns entirely. See the cookieless analytics article for more details.

Loved by builders everywhere

From indie hackers to global teams, OpenPanel helps people understand their users effortlessly.

  • Steven Tey
    Steven Tey
    @steventey

    Open-source Mixpanel alternative just dropped → http://git.new/openpanel

    It combines the power of Mixpanel + the ease of use of @PlausibleHQ into a fully open-source product.

    Built by @CarlLindesvard and it’s already tracking 750K+ events 🤩

  • Pontus Abrahamsson - oss/acc
    Pontus Abrahamsson - oss/acc
    @pontusab

    Thanks, OpenPanel is a beast, love it!

  • Piotr Kulpinski
    Piotr Kulpinski
    @piotrkulpinski

    The Overview tab in OpenPanel is great. It has everything I need from my analytics: the stats, the graph, traffic sources, locations, devices, etc.

    The UI is beautiful ✨ Clean, modern look, very pleasing to the eye.

  • greg hodson 🍜
    greg hodson 🍜
    @h0dson

    i second this, openpanel is killing it

  • Jacob 🍀 Build in Public
    Jacob 🍀 Build in Public
    @javayhuwx

    🤯 wow, it's amazing! Just integrate @OpenPanelDev into http://indiehackers.site last night, and now I can see visitors coming from all round the world.

    OpenPanel has a more beautiful UI and much more powerful features when compared to Umami.

    #buildinpublic #indiehackers

  • Lee
    Lee
    @DutchEngIishman

    Day two of marketing.

    I like this upward trend..

    P.S. website went live on Sunday

    P.P.S. Openpanel by @CarlLindesvard is awesome.

Ready to understand your users better?
Start tracking in minutes

Join thousands of companies using OpenPanel. Free 30-day trial, no credit card required. Self-host for free or use our cloud.

Get started now