Skip to content
Docs
Browse Developers

iOS SDK

Add the kontala-ios Swift package and capture screens, taps and events in your iOS app, built with UIKit or SwiftUI.

kontala-ios captures what people do in your native iOS app, built with UIKit or SwiftUI, the way the website tag captures a site. It records every screen they see, every control they tap, who signs in, what forms and searches sent, how far they scrolled, where they struggled, how fast each screen was, and your app's own events.

Requirements

  • iOS 13 or later.
  • Swift Package Manager. The SDK has no dependencies beyond Apple's frameworks.

There is no CocoaPods pod: CocoaPods' trunk takes no new pods after December 2026.

1. Find your write key

Open the property in Kontala and find its Events API card. It shows the property's write key (pk_live_...) and the Events API URL to send to.

The write key is public: every copy of your app carries it, as every page carries the tag's. Never put a server key (ksk_live_...) in an app.

2. Add the package

In Xcode, choose File > Add Package Dependencies, enter https://github.com/operationfb/kontala-ios, choose Up to Next Minor Version from 0.1.0, and add the Kontala library to your app's target.

Or in Package.swift:

dependencies: [
    .package(url: "https://github.com/operationfb/kontala-ios", .upToNextMinor(from: "0.1.0")),
],
targets: [
    .target(name: "Shop", dependencies: [.product(name: "Kontala", package: "kontala-ios")]),
]

While the SDK is at 0.x, a minor version may change its API, so take patch releases alone.

3. Start it

Call Kontala.start as the app launches, on the main thread:

import Kontala

@main
struct ShopApp: App {
    init() { Kontala.start(writeKey: "pk_live_...", endpoint: "https://konta.la/v1/events") }
    var body: some Scene { WindowGroup { ContentView() } }
}

In a UIKit app, call it in application(_:didFinishLaunchingWithOptions:):

func application(
    _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    Kontala.start(writeKey: "pk_live_...", endpoint: "https://konta.la/v1/events")
    return true
}

Use the write key and endpoint from your property's Events API card. View controllers are screens by themselves; a SwiftUI screen is named by its navigation title, or by .kontalaScreen (below).

Every other Kontala method may be called from any thread, and before start: those calls are kept and applied in order.

4. Platform setup

No setup is needed. The SDK ships an iOS privacy manifest, which Xcode adds to your app's privacy report.

If you want the IDFA, your app shows the App Tracking Transparency prompt, never the SDK. Add NSUserTrackingUsageDescription to Info.plist, then call this when your app chooses:

Kontala.requestTrackingAuthorization { status in }

5. Check that it works

Start the app with debug logging on:

Kontala.start(writeKey: "pk_live_...", endpoint: "https://konta.la/v1/events", options: KontalaOptions(debug: true))

The log, under the subsystem la.konta.kontala in Console, shows every event as it is captured, and every event the API refused, with its reason.

A debug build, and any build in the simulator, marks its events as a developer's. Kontala leaves them out of visitor counts by default, as it does for a development server.

Optional setup

Name screens and mark controls

OnMarkerDoes
A view controllerKontalaScreenDeclares the screen it shows: its name, page type and data
A SwiftUI view.kontalaScreen(...)The same, for the screen it is shown in
A viewview.kontalaEvent = .addToCartDeclares the click type of a control, or of every control in it
A viewview.kontalaMask = trueA tap in it is sent as its role alone: no id, label, text or class
A viewview.kontalaIgnore = trueNothing in it is captured
A SwiftUI view.kontalaEvent(...), .kontalaMask(), .kontalaIgnore()The same, for what the view draws
ProductView(product: product)
    .kontalaScreen("/product/\(product.id)", pageType: .productDetail)

A SwiftUI control is captured as a tap only where .kontalaEvent marks it. A text field never sends what is typed into it.

Identify signed-in users

Kontala.identify(user: "customer-42", org: "acme", traits: ["plan": "pro"])

Every later event carries the user and organisation. Call Kontala.identify() with neither to log out, or Kontala.reset() to also forget the install and session.

Track your own events

Kontala.track("wishlisted", properties: ["product_id": "42"])

Custom events arrive while the property's data layer captures the Events API's events.

The SDK starts with consent granted. To wait for your consent banner instead, start undecided and answer when the visitor chooses:

Kontala.start(
    writeKey: "pk_live_...", endpoint: "https://konta.la/v1/events",
    options: KontalaOptions(consent: .unknown))

// Later, from your banner:
Kontala.consent(.granted)

Kontala.optOut(true) stops all capture, sending and storage on the device, across launches. See Consent for how Kontala treats each state.

Web pages in the app

If your app shows pages of your website in a WKWebView, the SDK shares its visitor and visit with them through WebKit's cookie store, so one person is counted once. Attach a web view for the closest link: the page then takes the app's consent and signed-in user.

final class HelpViewController: UIViewController {
    private let webView = WKWebView()
    private var attachment: KontalaWebViewAttachment?

    override func viewDidLoad() {
        super.viewDidLoad()
        webView.frame = view.bounds
        view.addSubview(webView)
        attachment = Kontala.attachWebView(webView)
        webView.load(URLRequest(url: URL(string: "https://shop.example.com/help")!))
    }

    deinit { attachment?.detach() }
}

Attach a web view before its first page loads, and call detach() when it goes.

Troubleshooting

  • A SwiftUI screen is missing. It has neither a .kontalaScreen nor a navigation title: declare it.
  • No SwiftUI taps arrive. A SwiftUI control is a tap only where .kontalaEvent marks it.
  • No taps arrive. Turn clicks on for the property in Kontala.
  • No custom events arrive. The property's data layer is off, or its capture rules do not include the Events API.
  • Every row reads as a developer's. It is a debug build, or the simulator.
  • Nothing arrives at all. The write key is wrong or revoked, or the app cannot reach the endpoint. Events wait in the app's queue until it can.

App Store privacy details

What the SDK sends is yours to declare in App Store Connect's privacy details:

App privacy detailsWhat the SDK sends
Identifiers: Device IDA random install id; on consented events, the IDFV, and the IDFA where the visitor authorised tracking
Identifiers: User IDThe ids Kontala.identify names
Contact info: Email addressThe email a login names
Usage data: Product interactionScreens, taps, swipes, scroll depth, time on screen and your events
Search historyWhat a search looked for
User content: Other user contentWhat your app's forms sent
Diagnostics: Crash dataExceptions your app did not catch
Diagnostics: Performance dataHow fast each screen was
Diagnostics: Other diagnostic dataRage and dead taps
Location: Coarse locationCountry, region and city, derived from each request's address

Each is used for analytics and linked to the user where your app identifies them. None is used for tracking: the IDFA goes to Kontala alone and is never joined with another company's data.

Licence

The SDK is provided under the Kontala SDK License.

Was this helpful?