Add Sumly to an iOS or macOS app

One Swift file with no dependencies, for iOS, iPadOS, macOS and watchOS. It sends screens and events under the person RevenueCat knows, so their screens and their purchases meet.

Drawn with an example line.

Not yet run in a real app. Sumly.swift builds and follows the same rules as the React Native file, which runs in our own apps, but it has not run in a shipped app yet. Try it in a test build first, and tell us if anything is off.

Step by step

  1. 1

    In Sumly, open Visitors and copy your project's public key (sl_…). Download https://sumly.dev/sdk/Sumly.swift and add it to your app's target in Xcode.

  2. 2

    As the app starts, call Sumly.configure(siteKey: "sl_…"). After Purchases.configure, and again after each logIn or logOut, call Sumly.identify(Purchases.shared.appUserID).

  3. 3

    Count screens: .sumlyScreen("Paywall") on a SwiftUI view counts it each time it appears; in UIKit, Sumly.screen in viewDidAppear. In your privacy manifest, declare UserDefaults with reason CA92.1, if it is not there already.

In the App's init, or didFinishLaunching.

import SwiftUI
import RevenueCat

@main
struct MyApp: App {
    init() {
        Sumly.configure(siteKey: "sl_your_key")
        Purchases.configure(withAPIKey: "appl_…")
        Sumly.identify(Purchases.shared.appUserID)
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

// after signing in or out
_ = try await Purchases.shared.logIn(user.id)
Sumly.identify(Purchases.shared.appUserID)

Or let your coding assistant do it

Paste this into Claude Code, Cursor or Codex in your project. It fits the code to how your project is built, asks you for the dashboard steps and leaves the keys to you.

See what it says
Set up Swift and SwiftUI for Sumly in this project.

Sumly (https://sumly.dev) shows revenue next to the visits and app users it came from. The full guide is https://sumly.dev/install/swift; read it if anything below is unclear.

Steps:
1. In Sumly, open Visitors and copy your project's public key (`sl_…`). Download https://sumly.dev/sdk/Sumly.swift and add it to your app's target in Xcode.
2. As the app starts, call `Sumly.configure(siteKey: "sl_…")`. After `Purchases.configure`, and again after each `logIn` or `logOut`, call `Sumly.identify(Purchases.shared.appUserID)`.
3. Count screens: `.sumlyScreen("Paywall")` on a SwiftUI view counts it each time it appears; in UIKit, `Sumly.screen` in `viewDidAppear`. In your privacy manifest, declare UserDefaults with reason CA92.1, if it is not there already.

Setup: In the App's init, or didFinishLaunching.
```
import SwiftUI
import RevenueCat

@main
struct MyApp: App {
    init() {
        Sumly.configure(siteKey: "sl_your_key")
        Purchases.configure(withAPIKey: "appl_…")
        Sumly.identify(Purchases.shared.appUserID)
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

// after signing in or out
_ = try await Purchases.shared.logIn(user.id)
Sumly.identify(Purchases.shared.appUserID)
```

Screens: SwiftUI's NavigationStack has no hook for a change of screen, so each screen says so as it appears.
```
// SwiftUI
PaywallView()
    .sumlyScreen("Paywall")

// UIKit
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    Sumly.screen("Paywall")
}

// events
Sumly.track("trial_started", props: ["plan": "yearly"])
```

Consent: Where your app asks first.
```
Sumly.configure(siteKey: "sl_your_key", waitForConsent: true)

Sumly.consent(true)    // when the person agrees
Sumly.consent(false)   // when they refuse, or take it back
```

Own domain: Optional: your own address takes app events too.
```
Sumly.configure(siteKey: "sl_your_key", endpoint: URL(string: "https://signal.example.com"))
```

Keep in mind: No advertising id and no tracking across apps, so no App Tracking Transparency prompt. In App Privacy, declare Product Interaction, User ID and Coarse Location, used for analytics. The queue is kept in UserDefaults: offline, screens and events wait and go once the network is back.

How to work:
- Look at how this project is built first, and fit the code to its framework and its way of doing things; the examples above are a starting point, not something to paste as is.
- Steps that happen in a dashboard (Sumly, or Swift and SwiftUI's own) are mine: tell me exactly what to click, then wait for me.
- Keys the code needs belong in environment variables, never in the code or the repository. Never ask me to paste a secret key into this chat; tell me which variable to set.
- Change only what this needs, show me the changes before you commit, and tell me how to check that it works.
- sl_your_key stands for the project's public key; it is on the Visitors page in Sumly. Ask me for it.

Consent

Where your app asks first, start with waitForConsent: nothing is kept or sent until consent(true), and consent(false) stops sending and empties the queue. The answer is remembered.

Purchases

Purchases do not come through the app: Sumly reads them from RevenueCat, Adapty or Superwall. Give identify the same person they know: RevenueCat's app user id (the anonymous one too), or the user id you pass to Adapty.identify or Superwall.identify. Each purchase then shows the screens and the source that came before it.

Your own domain

Optional. The own address of your site's script (one DNS record on Visitors, on Starter and Growth) takes app events too: give it as the endpoint and the app sends to /api/v1/events there.

Good to know

  • No advertising id and no tracking across apps, so no App Tracking Transparency prompt. In App Privacy, declare Product Interaction, User ID and Coarse Location, used for analytics.
  • The queue is kept in UserDefaults: offline, screens and events wait and go once the network is back.

From Swift and SwiftUI's own documentation, checked 4 November 2026: revenuecat.com/docs/customers/identifying-customers, developer.apple.com/documentation/swiftui/view/onappear(perform:), developer.apple.com/documentation/uikit/uiviewcontroller/viewdidappear(_:) .

Other apps

Try it with your own projects

Sign in with Google or a code by e-mail and connect your first project. Free for one project, and 14 days of a paid plan with no card.

Start free

Or look around first: open the live demo.