2026-10-30 18:10:34 +03:00
2026-10-30 18:10:34 +03:00
2026-10-30 15:07:27 +03:00
2026-10-30 18:10:34 +03:00
2026-10-30 15:07:27 +03:00
2026-10-30 18:10:34 +03:00

Insight iOS SDK Developer Guide

This document describes the integration of the Insight iOS SDK with your iOS application.

Introduction

Insight iOS SDK collects location information and event data to track user interactions within the iOS application where it's installed. This data can be used for analyzing user behavior, improving user experience, and generating insights.

Table of Contents

1. Quick Start

Get up and running with Insight SDK in 5 minutes:

Add the SDK

Via CocoaPods:

pod 'InsightSDK', :git => 'https://insight-dl.apps.sccc.sa/sccc/iOS-SDK-test.git'

Add required frameworks

(see Integration section)

Configure location permissions

(see Configuring Permissions)

Initialize the SDK

UIKit:
// In AppDelegate.swift
import InsightSDK

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let sdkConfig = SdkConfiguration(
            apiKey: "YOUR_SECRET_KEY_HERE"
        )

        Insight.shared.start(config: sdkConfig, user: nil)
    return true
}
SwiftUI:

Create AppDelegate.swift with initialization code

Add

@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate

to your App struct.

For complete setup instructions, continue reading below.

2. Requirements

In order to integrate the Insight iOS SDK, make sure you are:

  • Targeting iOS version 13 or higher

  • Targeting the Swift 5 compiler

  • Registered on the Insight Portal

    • You need to create a Insight Access Key for the iOS platform if not created already.

Note: Make sure that you declare that "your app uses IDFA" on App Store Connect if you are using IDFA integration. Otherwise, your app may be rejected on review. Insight iOS SDK collects IDFA from the device when permitted by the user, in full compliance with the Apple requirements. Insight doesn't trigger the permission dialog; you need to trigger this if needed.

3. Integration

Adding the Insight iOS SDK

The Insight iOS SDK can be added via Swift Package Manager, CocoaPods, or manually.

Swift Package Manager Installation

Add Package Dependency

In Xcode, go to File → Add Package Dependencies...

Enter Repository URL

Enter the following URL in the search field:

https://insight-dl.apps.sccc.sa/sccc/iOS-SDK-test.git
Configure Package

Select the version and version rule (recommended: "Up to Next Major Version") and add the package to your target.

CocoaPods Installation

Referencing the InsightSDK pod in the Podfile will be sufficient to add the Insight iOS SDK to your project.

Create Podfile

If your project doesn't have a Podfile, then you can create one by running the following command on the terminal:

pod init
Reference InsightSDK in Podfile

Reference InsightSDK in the Podfile:

pod 'InsightSDK', :git => 'https://insight-dl.apps.sccc.sa/sccc/iOS-SDK-test.git'
Install pods

Install pods by running the following command on the terminal:

pod install

Manual Installation

Download the SDK

You can download the SDK from the following repository:

https://insight-dl.apps.sccc.sa/sccc/iOS-SDK-test.git
Copy the xcframework

Copy "InsightSDK.xcframework" folder by dragging and dropping into your app using project navigator in Xcode. After copying the xcframework into your app, the color of the xcframework shall be blue.

Mark Embed and Sign

Go to project settings "Frameworks, Libraries and Embedded Content" section. Choose "Embed & Sign" for InsightSDK.xcframework.

Adding Required Frameworks

Insight iOS SDK utilizes the following frameworks. Please make sure that your project references all of them:

  • AdSupport.framework
  • CoreLocation.framework
  • CoreTelephony.framework
  • SystemConfiguration.framework

Configuring Permissions

In order to provide proper notifications and proper beacon tracking, you need to get permissions from the application user, after your application is installed. Per iOS user guides, applications can ask for required permissions with their own sentences. The permissions can be configured in the Info.plist file.

Insight iOS SDK uses the iBeacon protocol which requires location permission by default. Insight iOS SDK needs to detect beacons and geofences even when the app is in the background or killed. Therefore, you have to ask your users for "Always usage of location" permission.

Users are able to give location usage permission only when the application is in use. As a result, applications have to ask for two different types of location permissions: WhenInUse or AlwaysAndWhenInUse.

Your application should include both descriptors given below for location permission:

  • NSLocationAlwaysAndWhenInUseUsageDescription
  • NSLocationWhenInUseUsageDescription

In the description field of location permission entries, we recommend that you encourage your users to allow "Always use my location", in order to have a better performance of the system. In the below subsections, we provide some sample description text. Please check and consider them.

Always And When In Use

This descriptor is used for iOS 11 and later. It provides permission for both when in use and when killed.

Sample Text: "This application uses your location in order to inform you about interesting offers nearby. We advise you to choose the Always option to get the offers even when you are not using the application!"

You can insert it into your Info.plist file in the following syntax.

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string><# insert always and when in use usage description text #></string>

When In Use

This descriptor is used in all iOS versions. It provides permission for only when the application is in use. We advise you to warn your users about very low performance when receiving nearby offers.

Sample Text: "This application uses your location in order to inform you about interesting offers nearby. Allowing location when in use only may result in poor performance in finding nearby offers!"

You can insert it into your Info.plist file in the following syntax.

<key>NSLocationWhenInUseUsageDescription</key>
<string><# insert when in use usage description text #></string>

4. Usage

In order to utilize the capabilities of the Insight iOS SDK, it needs to be started at some point in your application's lifecycle.

Entering the Insight Platform Access Key

Insight iOS SDK requires the Insight Platform Access Key. You may need to create one for the iOS platform at the Insight Publisher Portal. If you do not have an account at the Insight Publisher Portal, please contact us at sdk@insight.apps.sccc.sa. You can set your key in your application's Info.plist file with the Insight Platform Access Key key:

<key>Insight Platform Access Key</key>
<string>YOUR_SECRET_KEY_HERE</string>

Alternatively, you can provide the Insight Platform Access Key via the SDK start method as documented in the next section.

UIKit Apps

For traditional UIKit applications, initialize the SDK in your AppDelegate.swift:

import UIKit
import InsightSDK

@UIApplicationMain
class AppDelegate: NSObject, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // ....
        startInsightSDK()
        // ...
        return true
    }

    func startInsightSDK() {
        let sdkConfig = SdkConfiguration(
            apiKey: "YOUR_SECRET_KEY_HERE"
        )

        // If you have a "User" class/struct you need to use "InsightSDK.User" to prevent the conflict
        let sdkUser = User(
            userId: "YOUR_APP_USERS_UNIQUE_IDENTIFIER_FOR_YOUR_PLATFORM_HERE",
            gender: YOUR_APP_USERS_GENDER_HERE, // .female or .male
            yearOfBirth: YOUR_APP_USERS_BIRTH_YEAR_HERE,
            displayName: "YOUR_APP_USERS_USERNAME_HERE",
            email: "YOUR_APP_USERS_EMAIL_HERE",
            phoneNumber: "YOUR_APP_USERS_PHONE_NUMBER_HERE",
            other: [
                "sp1" : "special property 1 value",
                "sp2" : "special property 2 value"
            ]
        )

        Insight.shared.start(config: sdkConfig, user: sdkUser, completion: { sdkState in
            switch sdkState {
            case .success:
                debugPrint("InsightSDK version: \(Insight.shared.version) started")

            case .skipped:
                debugPrint("InsightSDK version: \(Insight.shared.version) start skipped")

            case .failure:
                debugPrint("InsightSDK version: \(Insight.shared.version) failed")

            @unknown default:
                debugPrint("InsightSDK version: \(Insight.shared.version) start state unknown")
            }
        })
    }
}

Simple Initialization

You can start the Insight iOS SDK by simply invoking the start method of the shared instance:

let sdkConfig = SdkConfiguration(
    apiKey: "YOUR_SECRET_KEY_HERE"
)
Insight.shared.start(config: sdkConfig, user: nil)

SwiftUI Apps

For SwiftUI applications (iOS 14+), you need to create an AppDelegate.swift file and use @UIApplicationDelegateAdaptor to ensure the SDK initializes properly.

Create AppDelegate.swift

Create a new file called AppDelegate.swift with your SDK initialization:

import UIKit
import InsightSDK

// AppDelegate to handle lifecycle events
class AppDelegate: NSObject, UIApplicationDelegate {
    let insightSDK = InsightSDKManager()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        insightSDK.startInsightSDK()
        return true
    }
}

Create an SDK manager to access SDK easier:

import SwiftUI
import InsightSDK

class InsightSDKManager: ObservableObject {

    @Published var insightSDKStatus: String = "..."

    func startInsightSDK() {
        let sdkConfig = SdkConfiguration(
            apiKey: "YOUR_SECRET_KEY_HERE",
            pushToken: "" // when you don't have a push token use empty string
        )

        Insight.shared.start(config: sdkConfig, user: nil, completion: { [weak self] sdkState in
            guard let self else { return }
            DispatchQueue.main.async {
                switch sdkState {
                case .success:
                    self.insightSDKStatus = "Started"
                    debugPrint("InsightSDK version: \(Insight.shared.version) started")

                case .skipped:
                    self.insightSDKStatus = "Skipped"
                    debugPrint("InsightSDK version: \(Insight.shared.version) start skipped")

                case .failure:
                    self.insightSDKStatus = "Failed"
                    debugPrint("InsightSDK version: \(Insight.shared.version) failed")

                @unknown default:
                    self.insightSDKStatus = "Unknown"
                    debugPrint("InsightSDK version: \(Insight.shared.version) start state unknown")
                }
            }
        })
    }
}

Connect AppDelegate to SwiftUI App

In your main SwiftUI App file, add the @UIApplicationDelegateAdaptor:

import SwiftUI

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appDelegate.insightSDK)
        }
    }
}

Configuration Options

SdkConfiguration Parameters

The SdkConfiguration class contains the following properties:

Property Type Description
apiKey String API Key generated in Insight Platform for the app.
pushToken String? Push notification token for the device.
logLevel LogLevel Logging verbosity level (default: .error).

User Parameters

The user parameter allows you to enhance the audience data by providing information about the primary user (subscriber) of your application. You can give any information that makes the subscriber unique in your application's understanding. The User class contains the following:

Property Type Example Description
userId String? "42" Unique identifier of the user
gender UserGender? .female Gender of the user (.female or .male)
yearOfBirth Int? 1999 Year of birth of the user
email String? "mail@me.com" Email address of the user
displayName String? "John Doe" Display name of the user
phoneNumber String? "+96653612345" Mobile phone number of the user
isPIIHashed Bool? true Whether to hash user info
other Dictionary<String,String>? ["key": "value"] Extra information for the user

Note: email and phoneNumber details are never sent in plain-text to the Insight Platform if the isPIIHashed property is set to true (default true). These values are always irreversibly hashed so that no personally identifiable information is stored.

Completion Handler

The completion parameter allows you to execute your business logic after the Insight iOS SDK initialization succeeds or fails.

Screen Recording (preview)

Screen recording captures the screen as a series of masked frames so user sessions can be replayed for diagnostics. It runs on iOS 13 and newer, in UIKit and SwiftUI apps alike. A screenshot frame costs about 70 ms of main-thread time on an iPhone 15 Pro Max, and the SDK caps that work at 100 ms per second.

There is nothing to configure in your app. Every screen recording setting comes from the server, on the same configuration response the rest of the SDK already reads, and until the server sends any the SDK runs on the defaults in the table below. That includes whether it records at all: there is no local switch, and turning it off for an app is a server-side change.

Navigation needs no code in most apps. The SDK captures a new screen when a view controller appears, when a presentation closes, and when a SwiftUI NavigationStack pushes or pops, a TabView changes tab or a sheet appears. Two cases need one event from you; see New screens the SDK cannot see.

By default the SDK records text and images as drawn: privacyText and privacyImages both default to allow. The SDK masks the following at every privacy level, whatever the server sends: secure text entry fields and inputs whose textContentType names a password, a one-time code, a card, a phone number, an e-mail address, a name, an address or a birthdate; WKWebView; video, camera, Metal and OpenGL layers; MKMapView; PencilKit canvases; content another process draws; and custom views the SDK does not recognize, such as a UIView that paints itself in draw(_:). A PII scan also masks e-mail addresses, card numbers and other personal data in text recorded in clear; see piiRules below. To exclude any view from capture, set view.screenRecordingMask = true (also available from Objective-C), or put the string screen-recording-mask in its accessibilityIdentifier; in SwiftUI, apply .screenRecordingMask().

The SDK uploads recordings in batches from a queue of its own on the device. SdkConfiguration.networking.batchingEnabled picks the endpoint for recordings as it does for events: with batching on, the default, each batch goes to /sdk/ingest/bundles as one bundle message; with batching off, it goes to /sdk/screen-recording/shots. Recordings travel through the same network stack, session token and certificate pinning as every other request.

Each recording carries the session id the server issued. A recording made before the device has one, on a fresh install or an offline launch, stays on the device and uploads once the SDK receives an id, in the same process or a later launch. The seven-day maxRecordAgeHours limit below applies while it waits. Insight.shared.clearScreenRecordings() deletes every stored recording, buffered or queued, and abandons an upload in flight; clearStoredData() does the same as part of a wider erasure.

What the server can send, and what applies until it does:

Setting Default Description
enabled true Master switch. Nothing is captured or stored when false.
mode screenshot screenshot or wireframe. A change applies at the next app launch. Records name the new mode from the next time the app comes to the foreground, so until that launch the mode a record names and the mode of its frames can differ. In wireframe mode a SwiftUI screen records as one grey placeholder.
privacyText allow maskAll, maskInputs, or allow.
privacyImages allow maskAll, maskNonBundled, or allow. maskNonBundled shows a UIImageView only when its image is a symbol image (UIImage(systemName:) or a custom symbol). It does NOT show your compiled-in PNGs: nothing in UIImage says which asset a bitmap came from, so an app asset and a downloaded photo are indistinguishable and both mask. Every SwiftUI image masks at this setting too, SF Symbols included, and so does every SwiftUI shape.
privacyTouch show show or hide. hide emits no touch data at all. If hide was in effect when the app launched, a change to show waits for the next launch.
imageQualityPercent 30 JPEG quality of each frame, 1 to 100. A change applies at the next app launch.
maxFrameLongEdgePx 1280 Frames are rendered so the long edge stays within this. A change applies at the next app launch.
throttleMs 0 Minimum interval between ordinary captures. 0 means the mode default: 1000 ms in screenshot mode, 250 ms in wireframe mode. The SDK captures at once, outside the interval, when a new screen appears (a view controller appears, a presentation closes, the key window changes, or a SwiftUI NavigationStack or TabView navigates), the keyboard settles, the screen rotates or the app returns to the foreground. A change applies at the next app launch.
privacyMaskViewClasses empty Runtime class names whose instances are masked with their whole subtree. See below.
privacyUnmaskViewClasses empty The same, in the other direction: the text and image settings are relaxed for those views.
privacyMaskTags empty Accepted and stored. This version applies it to nothing on iOS, because SwiftUI content exposes no tag, role or text to the SDK while it records. Use the marks in your code instead.
privacyUnmaskTags empty The same, in the other direction. Stored and not applied on iOS.
privacyRules empty Rules by tag, role, text or description, optionally per screen. Stored and not applied on iOS in this version.
piiRules all on PII detectors for text recorded in clear: email, iban, card, phone, nationalId, ip, and custom, which switches piiCustomPatterns. Each key takes true or false, and a key the server leaves out stays on. The scan reads UIKit text such as a UILabel; it does not read a SwiftUI Text (see below). In screenshot mode a match masks the whole text element; in wireframe mode each match becomes ***.
piiCustomPatterns empty Extra patterns for the PII scan. NSRegularExpression compiles them on iOS, so keep to the subset both platforms accept: literals, character classes, ., anchors, groups, alternation, greedy and lazy quantifiers, \d, \w, \s and their negations; no lookbehind, named groups or backreferences. They apply while custom in piiRules is on. The SDK reads at most 16 entries of at most 256 characters each; it drops and counts an entry past the sixteenth, a longer entry and an entry that does not compile.
frustrationEnabled true Detects rage taps and dead taps. false turns detection off and leaves the touch stream as it is.
frustrationKinds both on The kinds to detect: rageTap and deadTap, each true or false. errorTap is accepted and reserved; nothing in this version emits it.
frustrationRageTapCount 3 Taps that make a rage tap, the first one included. Each later tap lands within frustrationRageRadiusDp and frustrationRageWindowMs of the first.
frustrationRageRadiusDp 44 Rage tap radius, read as points on iOS, measured from the first tap.
frustrationRageWindowMs 1000 Rage tap window in milliseconds, counted from the first tap.
frustrationDeadTapMs 1500 A tap is a dead tap when the screen shows no visible change within this many milliseconds.
wifiOnly false When true, uploads wait for an unmetered network, such as Wi-Fi, and records stay queued until then.
maxRecordAgeHours 168 The SDK deletes a queued record captured more than this many hours ago instead of uploading it. 168 hours is seven days.

A privacy change that masks more, such as a stricter privacyText or an added mask rule, applies at once. One that masks less applies the next time the app comes to the foreground.

An unrecognized setting, an unrecognized value, an unrecognized map key and a value of the wrong type each leave that one setting or map entry at its default and are counted as screen_recording_degraded_total{reason=carrier_unrecognized}; none of them rejects the rest of the response. The map keys are camelCase: a piiRules key spelled national_id or a frustrationKinds key spelled rage_tap is dropped, and that entry stays on.

The SDK keeps this counter, like every other counter this section names, in process memory. Nothing uploads the counters yet; server-side reporting comes in a later version. To see them, set logLevel to .trace in SdkConfiguration: the SDK then logs each increment as a telemetry <name> +1 line, which you can watch live in Xcode's console or with log stream. At the default .error level screen recording logs only failures: an install that did not complete, a record it could not write or read, a request it could not build.

New screens the SDK cannot see

The SDK captures a new screen as soon as it appears when a view controller is shown, a presentation is dismissed, the key window changes, or a SwiftUI NavigationStack pushes or pops, a TabView changes tab, or a sheet or cover appears. Two navigations leave no such trace: SwiftUI content your app swaps on state (an if or a switch in a view body), and a SwiftUI screen hosted as a child of a UIKit navigation or tab bar controller. The SDK then records the new content on its ordinary schedule, at most once per second by default, so a screen the user leaves within that second may have no frame at all.

Log a screen view event when the new content appears. The SDK treats the next frame as a new screen and records it outside the one-per-second limit:

.onAppear {
    Insight.shared.logEvent(InsightEventOtherScreenView(screenClass: "Checkout", screenName: "Checkout"))
}

The recording names screens by view controller class. A SwiftUI screen gets SwiftUI's own controller names, so every destination of one NavigationStack shares one name and so does every tab of one TabView; the name in your event does not reach the recording.

Masking whole view classes

Tagging individual views does not scale to "mask every balance label in the app", and an app cannot tag views it does not own, such as a third-party UI library's. privacyMaskViewClasses takes the class names instead; every instance of a listed class, and of any subclass, is masked together with everything drawn inside it. Your app does not set the list; ask for the class names to be added to the server-side settings for your app.

Names are runtime class names, matched exactly: a Swift class is module-qualified (MyApp.BalanceLabel) and an Objective-C or UIKit class is bare (UILabel), which is what NSClassFromString accepts. There is no substring matching: Label matches nothing, it does not mask every label in the app. An entry containing * is a pattern, and * stands for any run of characters: MyApp.Wallet* matches every class whose name starts that way, subclasses included. The SDK counts an exact name that resolves to no class as screen_recording_degraded_total{reason=mask_class_unresolved} and otherwise ignores it, so a typo hides nothing and rejects nothing. A pattern that matches nothing is not counted, because a pattern with no instance on the current screen is normal; check a pattern rule by looking at a recording.

Two more things worth knowing before you rely on the lists:

  • A view whose own code sets screenRecordingUnmask = true, or carries the screen-recording-unmask token in its accessibilityIdentifier, is not masked by a class rule matching that same view: an explicit local decision in your source wins over a class rule. It does not work the other way through the tree, though, since a class rule masks the whole subtree under the view it matched and an unmask inside that subtree carves no exception out of it.
  • If a view matches both lists, it is masked. An ambiguous configuration must not be the way content leaks.

Class rules match UIKit views, never SwiftUI content. SwiftUI's own classes are private and a view struct has no class, so no entry in either list can reach a single SwiftUI element. A UIKit view you host with UIViewRepresentable is still a UIKit view and a class rule reaches it, and a pattern that matches your hosting view's runtime class hides the whole SwiftUI screen inside it. For single elements inside SwiftUI, use .screenRecordingMask() and .screenRecordingUnmask() in your code; the server's tag and rule settings are stored on iOS and applied to nothing in this version.

SwiftUI screens

In screenshot mode the SDK masks, scans and withholds taps on a SwiftUI screen as it does on a UIKit one, with the differences below. Everything here was measured on the iOS 18.6 and 26.5 simulators.

Marks. .screenRecordingMask() hides the element and withholds taps on it; .screenRecordingUnmask() relaxes the text and image settings for it. A UIKit view you host under a marked element is hidden with it, taps included. A mark covers the element's layout frame: a child you move out with .offset keeps its pixels and its taps where it draws, so mark that child too, and apply a mark before a transform so it turns with the content:

Text(cardNumber).screenRecordingMask().rotationEffect(.degrees(20))   // hides the rotated text
Text(cardNumber).rotationEffect(.degrees(20)).screenRecordingMask()   // hides the unrotated frame; the ends show

Personal data in a Text is not scanned. The SDK finds card numbers, e-mail addresses and the like in a UILabel and masks them at the default text setting, but SwiftUI draws its text without exposing the string, so the same card number in a Text shows. Mark such text with .screenRecordingMask(), or have the server send privacyText: maskAll.

What SwiftUI hides that UIKit shows. Each is safe and costs you pixels:

  • At privacyImages maskAll or maskNonBundled, every SwiftUI image hides, SF Symbols included, and so does every shape (Path, Circle, a stroked outline), because SwiftUI draws a shape and a symbol the same way.
  • A Canvas, content under .drawingGroup() and charts drawn the same way are always hidden, at every setting, and .screenRecordingUnmask() does not expose them.
  • At those two image settings a sheet, a popover or a Menu records as a black block. UIKit presentations do the same.
  • A plain text field hides what the user typed even at the default text setting, in UIKit too.

What SwiftUI shows that UIKit hides. Mark these yourself:

  • The selection of a menu-style Picker at privacyText maskInputs. Wheel pickers, toggles, sliders and date pickers hide as their UIKit twins do.
  • On iOS 26, .screenRecordingUnmask() also relaxes text from an overlapping sibling whose centre falls inside the unmasked element. Keep unmasked elements off secret text, or mark the secret text.

Presentations record. .sheet, .fullScreenCover, .popover, .alert, .confirmationDialog, Menu and .contextMenu all live in your app's window, so they are recorded with their masks and their taps pass the same checks. A window of your own that is not the key window, such as a toast in a window of its own, is not recorded.

Touches on masked content

The SDK withholds a tap only when it lands on a secure or sensitive input, a web view, a video, camera or GPU-backed view, a map, a PencilKit canvas, or an element your app marks with screenRecordingMask, the screen-recording-mask identifier token or .screenRecordingMask(). A withheld tap leaves no coordinates, no rage or dead tap built from it, and the whole gesture goes with it. A tap on a UIKit view hosted under a SwiftUI mark is withheld too.

The SDK records a tap on content hidden only by a privacy setting, a class rule, the PII scan or the rule that masks unrecognized custom views, and a tap beside a withheld element. To withhold taps on such content, mark it in your code. Two cases to know about:

  • A signature pad your app draws itself, in draw(_:) or as a SwiftUI Canvas, masks its pixels through the unrecognized-content rule and ships its taps, so a viewer can replay the stroke. Mark the pad. PencilKit's PKCanvasView withholds them on its own.
  • A video or GPU layer (AVPlayerLayer, CAMetalLayer) you add as a sublayer of an ordinary view is hidden in the frame, but a tap on it is recorded, because the SDK tests taps against views. Mark the view that holds the layer.

In a UIKit screen the check asks the topmost drawn view under the finger, so a later sibling drawn over a marked view, transparent or not, takes the tap back. Inside a SwiftUI screen every drawn element under the finger is asked, so a clear overlay does not. privacyTouch = hide records no touches at all.

5. Deprecations

Due to Apple's ongoing privacy enhancements, several features have been deprecated or require special permissions:

IDFA

Since iOS 14, Apple has introduced new privacy features that require user permission to access the IDFA. You'll need to request permission from the user before you can access the identifier.

Here's how to do that:

  • Add the AppTrackingTransparency framework to your project and import it:
import AppTrackingTransparency
  • Request permission from the user:
if #available(iOS 14, *) {
    ATTrackingManager.requestTrackingAuthorization { status in
        switch status {
        case .authorized:
            // Tracking authorization dialog was shown
            // and we are authorized
            debugPrint("Authorized")
            
            // Now that we are authorized we can get the IDFA
            let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
            debugPrint("IDFA: \(idfa)")
        case .denied:
            // Tracking authorization dialog was
            // shown and permission is denied
            debugPrint("Denied")
        case .notDetermined:
            // Tracking authorization dialog has not been shown
            debugPrint("Not Determined")
        case .restricted:
            // Tracking is restricted by some policy
            debugPrint("Restricted")
        @unknown default:
            debugPrint("Unknown")
        }
    }
} else {
    // iOS 14 not available, just get the IDFA
    let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
    debugPrint("IDFA: \(idfa)")
}
  • Add the NSUserTrackingUsageDescription key to your Info.plist file. This is the message that will be shown to the user when requesting IDFA access permission:
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>

Remember that users can choose to deny this permission, in which case you won't be able to access their IDFA.

Insight SDK doesn't immediately collect the IDFA when initialized. It waits for ATT permission to be granted. On the next start of the SDK, it will collect this information if the user has granted the permission.

Device Name

Starting with iOS 16, Apple restricted access to the user-defined device name for privacy reasons. This was done to prevent apps from potentially identifying users or devices without explicit permission.

For apps that genuinely need access to the device name (like device management or networking apps), Apple provides an entitlement called Access device name (com.apple.developer.device-information.user-assigned-device-name). However, this entitlement requires approval from Apple, and you need to justify why your app needs this information. If you don't have this entitlement, your app will only get generic device names like "iPhone" or "iPad".

Reference contains relevant information from Apple.

If you have acquired permissions, Insight SDK will collect this information.

Carrier Info

Starting iOS 16, carrier name and code information are deprecated. Reference 1 and Reference 2 contains relevant information from Apple.

6. Troubleshooting

Common Issues

SDK not starting:

  • Verify API key is correct
  • Verify API URL is correct
  • Check that the device can connect to the API endpoint
  • Check if SSL pinning is required and the SSL certificate is correctly set

Location not working:

  • Verify location permissions in Info.plist
  • Check that user has granted location permission
  • For background location, ensure "Always" permission is granted

Not reporting events in a SwiftUI app:

  • Make sure you've created AppDelegate.swift
  • Verify @UIApplicationDelegateAdaptor is properly configured
  • Check that SDK initialization code is in didFinishLaunchingWithOptions

7. Changelog

  • 1.0.0 (Released 2026-05-06)
    • Initial release
S
Description
No description provided
Readme 18 MiB
Languages
Objective-C 98.8%
Ruby 0.6%
Swift 0.5%
C 0.1%