Files
iOS-SDK-test/README.md
T

886 lines
38 KiB
Markdown
Raw Normal View History

2026-10-30 15:07:27 +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
- [Insight iOS SDK Developer Guide](#insight-ios-sdk-developer-guide)
- [Introduction](#introduction)
- [Table of Contents](#table-of-contents)
2026-10-31 23:39:07 +03:00
- [1. Quick start](#1-quick-start)
- [Add the SDK](#add-the-sdk)
- [Add required frameworks](#add-required-frameworks)
- [Configure location permissions (optional)](#configure-location-permissions-optional)
- [Initialize the SDK](#initialize-the-sdk)
- [UIKit](#uikit)
- [SwiftUI](#swiftui)
2026-10-30 15:07:27 +03:00
- [2. Requirements](#2-requirements)
- [3. Integration](#3-integration)
- [Adding the Insight iOS SDK](#adding-the-insight-ios-sdk)
2026-10-31 23:39:07 +03:00
- [Swift Package Manager installation](#swift-package-manager-installation)
- [Add package dependency](#add-package-dependency)
- [Enter repository URL](#enter-repository-url)
- [Configure package](#configure-package)
- [CocoaPods installation](#cocoapods-installation)
2026-10-30 15:07:27 +03:00
- [Create Podfile](#create-podfile)
- [Reference InsightSDK in Podfile](#reference-insightsdk-in-podfile)
- [Install pods](#install-pods)
2026-10-31 23:39:07 +03:00
- [Manual installation](#manual-installation)
2026-10-30 15:07:27 +03:00
- [Download the SDK](#download-the-sdk)
- [Copy the xcframework](#copy-the-xcframework)
- [Mark Embed and Sign](#mark-embed-and-sign)
2026-10-31 23:39:07 +03:00
- [Adding required frameworks](#adding-required-frameworks)
- [Configuring permissions](#configuring-permissions)
- [Always and when in use](#always-and-when-in-use)
- [When in use](#when-in-use)
2026-10-30 15:07:27 +03:00
- [4. Usage](#4-usage)
- [Entering the Insight Platform Access Key](#entering-the-insight-platform-access-key)
2026-10-31 23:39:07 +03:00
- [UIKit apps](#uikit-apps)
- [Simple initialization](#simple-initialization)
- [SwiftUI apps](#swiftui-apps)
2026-10-30 15:07:27 +03:00
- [Create AppDelegate.swift](#create-appdelegateswift)
2026-10-31 23:39:07 +03:00
- [Connect AppDelegate to the SwiftUI app](#connect-appdelegate-to-the-swiftui-app)
- [Configuration options](#configuration-options)
- [SdkConfiguration parameters](#sdkconfiguration-parameters)
- [User parameters](#user-parameters)
- [Completion handler](#completion-handler)
- [Stopping, restarting and changing configuration](#stopping-restarting-and-changing-configuration)
- [Stopping](#stopping)
- [Changing the user](#changing-the-user)
- [Changing the API key](#changing-the-api-key)
- [Restarting](#restarting)
- [Clearing stored data](#clearing-stored-data)
- [Network performance tracking](#network-performance-tracking)
- [URLSession integration](#urlsession-integration)
- [What gets tracked](#what-gets-tracked)
- [Which hosts get measured](#which-hosts-get-measured)
- [Screen recording (preview)](#screen-recording-preview)
- [Overview](#overview)
- [What you need to do](#what-you-need-to-do)
- [API reference](#api-reference)
- [Masking](#masking)
- [Touches](#touches)
- [Known limits](#known-limits)
2026-10-30 15:07:27 +03:00
- [5. Deprecations](#5-deprecations)
- [IDFA](#idfa)
2026-10-31 23:39:07 +03:00
- [Device name](#device-name)
- [Carrier info](#carrier-info)
2026-10-30 15:07:27 +03:00
- [6. Troubleshooting](#6-troubleshooting)
2026-10-31 23:39:07 +03:00
- [Common issues](#common-issues)
2026-10-30 15:07:27 +03:00
- [7. Changelog](#7-changelog)
2026-10-31 23:39:07 +03:00
## 1. Quick start
2026-10-30 15:07:27 +03:00
Get up and running with Insight SDK in 5 minutes:
2026-10-31 23:39:07 +03:00
### Add the SDK
2026-10-30 15:07:27 +03:00
Via CocoaPods:
```ruby
pod 'InsightSDK', :git => 'https://insight-dl.apps.sccc.sa/sccc/iOS-SDK-test.git'
```
2026-10-31 23:39:07 +03:00
### Add required frameworks
2026-10-30 15:07:27 +03:00
(see [Integration](#3-integration) section)
2026-10-31 23:39:07 +03:00
### Configure location permissions (optional)
(see [Configuring permissions](#configuring-permissions))
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
### Initialize the SDK
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
#### UIKit
2026-10-30 15:07:27 +03:00
```swift
// In AppDelegate.swift
import InsightSDK
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
2026-10-31 23:39:07 +03:00
let sdkConfig = SdkConfiguration(
apiKey: "YOUR_SECRET_KEY_HERE"
)
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
Insight.shared.start(config: sdkConfig, user: nil)
2026-10-30 15:07:27 +03:00
return true
}
```
2026-10-31 23:39:07 +03:00
#### SwiftUI
2026-10-30 15:07:27 +03:00
Create AppDelegate.swift with initialization code
Add
```swift
@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:
2026-10-31 23:39:07 +03:00
* Targeting iOS version 15 or higher
2026-10-30 15:07:27 +03:00
* 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](https://developer.apple.com/documentation/apptrackingtransparency). 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.
2026-10-31 23:39:07 +03:00
#### Swift Package Manager installation
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
##### Add package dependency
2026-10-30 15:07:27 +03:00
In Xcode, go to **File** → **Add Package Dependencies...**
2026-10-31 23:39:07 +03:00
##### Enter repository URL
2026-10-30 15:07:27 +03:00
Enter the following URL in the search field:
```
https://insight-dl.apps.sccc.sa/sccc/iOS-SDK-test.git
```
2026-10-31 23:39:07 +03:00
##### Configure package
2026-10-30 15:07:27 +03:00
Select the version and version rule (recommended: "Up to Next Major Version") and add the package to your target.
2026-10-31 23:39:07 +03:00
#### CocoaPods installation
2026-10-30 15:07:27 +03:00
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:
```bash
pod init
```
##### Reference InsightSDK in Podfile
Reference `InsightSDK` in the `Podfile`:
```ruby
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:
```bash
pod install
```
2026-10-31 23:39:07 +03:00
#### Manual installation
2026-10-30 15:07:27 +03:00
##### 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.
2026-10-31 23:39:07 +03:00
### Adding required frameworks
2026-10-30 15:07:27 +03:00
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
2026-10-31 23:39:07 +03:00
### Configuring permissions
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
The SDK asks the user for no permission. Your app decides whether to ask for location and notification permissions, and the SDK uses a permission only after the user grants it. Location is optional: without it the SDK works and sends no location.
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
If your app asks for location permission, Apple requires two things:
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
1. **A purpose string in `Info.plist`** for each kind of location permission your app requests: `NSLocationWhenInUseUsageDescription`, and `NSLocationAlwaysAndWhenInUseUsageDescription` if you also request Always. Without it, iOS shows the user no prompt, and App Store Connect can reject the build.
2. **Location in your app's privacy declarations.** The SDK sends the device location to Insight once the user allows it. Declare Precise Location, linked to the user, for analytics, in your app's privacy manifest (`PrivacyInfo.xcprivacy`) and in the App Privacy details in App Store Connect.
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
With Always permission, the SDK also receives location updates while your app is in the background. In the subsections below, we provide sample description text.
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
#### Always and when in use
2026-10-30 15:07:27 +03:00
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.
```xml
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string><# insert always and when in use usage description text #></string>
```
2026-10-31 23:39:07 +03:00
#### When in use
2026-10-30 15:07:27 +03:00
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.
```xml
<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
2026-10-30 18:10:34 +03:00
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:
2026-10-30 15:07:27 +03:00
```xml
<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.
2026-10-31 23:39:07 +03:00
### UIKit apps
2026-10-30 15:07:27 +03:00
For traditional UIKit applications, initialize the SDK in your `AppDelegate.swift`:
```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")
}
})
}
}
```
2026-10-31 23:39:07 +03:00
#### Simple initialization
2026-10-30 15:07:27 +03:00
You can start the Insight iOS SDK by simply invoking the `start` method of the shared instance:
```swift
2026-10-31 23:39:07 +03:00
import InsightSDK
2026-10-30 15:07:27 +03:00
let sdkConfig = SdkConfiguration(
apiKey: "YOUR_SECRET_KEY_HERE"
)
Insight.shared.start(config: sdkConfig, user: nil)
```
2026-10-31 23:39:07 +03:00
### SwiftUI apps
2026-10-30 15:07:27 +03:00
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:
```swift
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:
```swift
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")
}
}
})
}
}
```
2026-10-31 23:39:07 +03:00
#### Connect AppDelegate to the SwiftUI app
2026-10-30 15:07:27 +03:00
In your main SwiftUI App file, add the `@UIApplicationDelegateAdaptor`:
```swift
import SwiftUI
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
2026-10-31 23:39:07 +03:00
2026-10-30 15:07:27 +03:00
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(appDelegate.insightSDK)
}
}
}
```
2026-10-31 23:39:07 +03:00
### Configuration options
2026-10-30 15:07:27 +03:00
2026-10-31 23:39:07 +03:00
#### SdkConfiguration parameters
2026-10-30 15:07:27 +03:00
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). |
2026-10-31 23:39:07 +03:00
#### User parameters
2026-10-30 15:07:27 +03:00
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.
2026-10-31 23:39:07 +03:00
#### Completion handler
2026-10-30 15:07:27 +03:00
The `completion` parameter allows you to execute your business logic after the Insight iOS SDK initialization succeeds or fails.
2026-10-31 23:39:07 +03:00
### Stopping, restarting and changing configuration
`start(config:user:completion:)` covers the first launch. A settings screen that changes the user or the API key needs the calls below. Call each of them on `Insight.shared`.
#### Stopping
`stop()` and `stop(completion:)` return at once. From the call, the SDK collects nothing. Event logging, crash reporting, location monitoring, screen tracking, network performance tracking and screen recording stop. An event that you log answers its callback with an `APIError` whose `code` is `-4`, and the SDK does not store it.
Then the SDK sends what it holds for at most 5 seconds, in the background. It sends the stored crash reports first, then the queued events and the queued screen recordings together. Whatever did not leave stays queued and goes out after your next `start`. The stop deletes nothing.
`stop(completion:)` calls `completion` once, on the main queue, when the SDK has sent what it could. This happens at most 5 seconds after the call, or at once when the SDK was not started. The SDK does not cancel a request that is still in progress at 5 seconds. A second `stop` before the report joins the first and gets the same report. A `start` or `restart` that you call before the report waits for it and runs after it. After the report, the SDK sends nothing until your next start succeeds.
For screen recording, a stop ends the open recording and adds its last part to the queue that the stop sends. The next `start` turns screen recording on again.
```swift
import InsightSDK
Insight.shared.stop(completion: {
debugPrint("InsightSDK stopped")
})
```
#### Changing the user
The SDK sends the `User` when a session starts. To send a changed user, such as a new display name, call `restart(user:config:)` with the new `User`. The SDK stops, waits for the stop's report and starts again with the new `User`. A call to `stop()` and then to `start(config:user:completion:)` does the same, because the start waits for the stop's report.
```swift
import InsightSDK
let sdkUser = User(
userId: "YOUR_APP_USERS_UNIQUE_IDENTIFIER_FOR_YOUR_PLATFORM_HERE",
gender: YOUR_APP_USERS_GENDER_HERE, // .female or .male
displayName: "YOUR_APP_USERS_NEW_USERNAME_HERE"
)
Insight.shared.restart(user: sdkUser)
```
#### Changing the API key
To use a new API key, pass a new `SdkConfiguration` to `restart(user:config:)`. The SDK stops, then starts with the new configuration once the stop has reported. The change deletes nothing. New events, crash reports and screen recordings go out with the new key. What the SDK queued under the old key keeps going out with the old key.
2026-10-30 15:07:27 +03:00
```swift
2026-10-31 23:39:07 +03:00
import InsightSDK
let sdkConfig = SdkConfiguration(
apiKey: "YOUR_NEW_SECRET_KEY_HERE"
)
Insight.shared.restart(config: sdkConfig)
```
#### Restarting
`restart(user:config:)` stops the SDK and starts it again once the stop has reported. Both parameters are optional. A `nil` user or configuration means the one from the most recent start. When the SDK is not running, `restart` only starts it. The stop sends what the SDK holds for at most 5 seconds and keeps the rest, as [Stopping](#stopping) describes.
Events that your app logs between the `restart` call and the end of the new start wait in memory, in order. When the start ends, the SDK logs them. If event logging is off at that time, each of them gets the error `-4`. A plain `stop()` still refuses events with `-4`.
```swift
import InsightSDK
Insight.shared.restart()
```
### Clearing stored data
Each method below erases one part of what the SDK keeps on the device. None of them calls `stop()`. Call each of them on `Insight.shared`:
| Method | What it clears | What it keeps |
|--------|----------------|---------------|
| `clearStoredData()` | The stored crash reports and every stored screen recording. It also stops a recording upload in progress. | Queued events and health messages. |
| `clearCrashReports()` | The stored crash reports. | Everything else, screen recordings included. |
| `clearHealthMessages()` | The messages that you logged with `logHealthMessage(_:)`. | Everything else. |
| `clearScreenRecordings()` | Every stored screen recording and its upload queue. It also stops an upload in progress. It works before `start`. | Everything else. |
| `clearRequestQueues()` | Every queued event that waits for upload, for every API key. | Everything else, screen recordings included. |
`clearStoredData()` and `clearScreenRecordings()` wait for the main thread when you call them from another thread. Data that the server already has needs a server-side deletion.
`flushBatchRequests()` erases nothing. It asks the SDK to send the queued events now and returns at once. Before a start succeeds, and between `stop()` and the next successful start, it sends nothing.
```swift
import InsightSDK
// Screen recordings only: the stored recordings, their queue and any upload in progress
Insight.shared.clearScreenRecordings()
// Crash reports and screen recordings
Insight.shared.clearStoredData()
```
### Network performance tracking
Insight iOS SDK tracks the performance of the HTTP requests that your app makes with `URLSession`. You can monitor API response times and status codes.
#### URLSession integration
You write no code. The SDK tracks requests while your server settings turn network performance tracking on. It measures the requests that your app starts with these `URLSession` methods:
- `dataTask(with:)` and `dataTask(with:completionHandler:)`, with a `URLRequest` or a `URL`
- `uploadTask(with:from:completionHandler:)`
- `downloadTask(with:completionHandler:)`, with a `URLRequest`
The SDK adds its measurement to these methods at run time, through method swizzling. It measures requests on `URLSession.shared` and on every session that your app or a library creates. Your session delegate still gets each call. After `stop()`, the SDK measures nothing until the next start.
#### What gets tracked
The network performance tracking captures:
- **Request URL and method** (GET, POST, etc.)
- **Response time** (total duration from request start to completion)
- **HTTP status codes** (200, 404, 500, etc.)
- **Request and response sizes**
The SDK removes the user name, password, query and fragment from each URL. For a download task, the response size is 0. The SDK records a request only when it gets an HTTP response, so a request that fails with no response leaves no record.
#### Which hosts get measured
The Insight platform settings can name the hosts to measure. When they name any, the SDK measures requests to those hosts alone and skips the rest. When they name none, the SDK measures requests to every host. In both cases, the SDK skips the Insight host that it sends its own data to. It also skips every URL whose scheme is not `http` or `https`.
> **Note:** The SDK sends each measurement to the Insight platform.
### Screen recording (preview)
> **Preview:** Screen recording is in preview. Its behavior can change in a
> later release.
#### Overview
**Screen recording** captures masked frames of your app's screens, so your
team can replay a user session. It runs on iOS 15 or later, in UIKit and
SwiftUI apps. A frame costs about 70 ms of main-thread time on an iPhone 15
Pro Max. The SDK limits that work to 100 ms in each second.
Screen recording is off until your app's server settings turn it on. The
same settings control the privacy level and the frame quality. Your app has
nothing to configure, and the SDK has no local switch. When the settings
turn recording on, the SDK starts to record at once. Some other changes to
the server settings apply at the next app launch.
#### What you need to do
In most apps, you do not need to write code. The SDK captures a new screen
when a view controller appears, a presentation closes, or the key window
changes. In SwiftUI, it also captures one when a `NavigationStack` pushes or
pops, a `TabView` changes tab, or a sheet or cover appears.
Some changes give the SDK no signal. An example is SwiftUI content that your
app swaps on state, with an `if` or a `switch` in a view body. The SDK then
records the new content on its normal schedule, at most once per second by
default. A screen that the user leaves within that second can have no frame.
To record a new screen at once, log a screen view event when it appears. The
SDK treats the next frame as a new screen and records it outside the
once-per-second limit:
```swift
import InsightSDK
2026-10-30 15:07:27 +03:00
.onAppear {
Insight.shared.logEvent(InsightEventOtherScreenView(screenClass: "Checkout", screenName: "Checkout"))
}
```
2026-10-31 23:39:07 +03:00
To record a change inside one screen, such as a view that your app swaps on
a state change, call `requestScreenRecordingCapture()`:
```swift
import InsightSDK
Insight.shared.requestScreenRecordingCapture()
```
The SDK captures the screen at once. The normal capture limits and privacy
rules still apply. A call before `start`, while the SDK is stopped, or while
the app is in the background does nothing.
#### API reference
The table lists every public screen recording API:
| API | Use it to | Notes |
|---|---|---|
| `var screenRecordingMask: Bool` | Mask a UIKit view and its subviews. | A property on `UIView`, also in Objective-C. The default is `false`. The SDK also withholds taps on the view. |
| `var screenRecordingUnmask: Bool` | Show the text and images of a UIKit view and its subviews. | A property on `UIView`, also in Objective-C. The default is `false`. It never unmasks always-masked content. |
| `screen-recording-mask` in `accessibilityIdentifier` | Mask a UIKit view through its identifier. | The identifier can hold other text too. It works as `screenRecordingMask` does. |
| `screen-recording-unmask` in `accessibilityIdentifier` | Unmask a UIKit view through its identifier. | The identifier can hold other text too. It works as `screenRecordingUnmask` does. |
| `func screenRecordingMask() -> some View` | Mask a SwiftUI view and its children. | A SwiftUI modifier. The SDK also withholds taps on the view. |
| `func screenRecordingUnmask() -> some View` | Show the text and images of a SwiftUI view and its children. | A SwiftUI modifier. It never unmasks always-masked content. |
| `func requestScreenRecordingCapture()` | Capture the screen after a change that the SDK cannot see. | Call it on `Insight.shared` from any thread. It returns at once. |
| `func clearScreenRecordings()` | Delete every screen recording that the device stores. | Call it on `Insight.shared` from any thread. It also stops an upload in progress, and it works before `start`. |
| `func clearStoredData()` | Delete the SDK's stored user data on the device. | It deletes every stored recording and the pending crash reports. Data that the server already has needs a server-side deletion. |
| `InsightEventOtherScreenView(screenClass: String, screenName: String, parameters: [String: Value] = [:])` | Mark a new screen that the SDK cannot see. | Log it with `Insight.shared.logEvent(_:callback:)`. The recording does not show `screenName`, but a server rule for named screens matches it. |
> **Note:** `clearScreenRecordings()` and `clearStoredData()` wait for the
> main thread when you call them from another thread.
Use the `screenRecordingMask` or `screenRecordingUnmask` property to mark a
UIKit view. For example:
```swift
import InsightSDK
cardNumberField.screenRecordingMask = true
headlineLabel.screenRecordingUnmask = true
```
You can also set the property from Objective-C:
`self.cardNumberField.screenRecordingMask = YES;`.
Put a mask token in the `accessibilityIdentifier` to mark a view without the
property. The sample uses the identifier `checkout.card`:
2026-10-30 15:07:27 +03:00
```swift
2026-10-31 23:39:07 +03:00
cardNumberField.accessibilityIdentifier = "checkout.card screen-recording-mask"
2026-10-30 15:07:27 +03:00
```
2026-10-31 23:39:07 +03:00
Use the `screenRecordingMask()` and `screenRecordingUnmask()` modifiers to
mark a SwiftUI view. For example:
```swift
import InsightSDK
Text(cardNumber).screenRecordingMask()
Text(headline).screenRecordingUnmask()
```
The SDK masks the card number and shows the headline in each frame.
#### Masking
By default, the SDK records text and images as drawn. If the server sets a
stricter privacy level, the SDK masks more.
The SDK always masks the following content, whatever the server sends. No
mark or rule can unmask it:
- Secure text entry fields
- 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 that another process draws
- Custom views that the SDK does not recognize, such as a `UIView` that
paints itself in `draw(_:)`
A scan for personal data (PII) also masks e-mail addresses, card numbers,
and similar data in UIKit text that the SDK records in clear.
To keep other content out of a recording, mask it with a property, an
identifier token, or a modifier. To show text and images that the privacy
level masks, unmask the view. Three rules decide when marks and server rules
meet:
- An unmask in code on a view beats a server rule that masks the same
view.
- A mask wins when a view matches both a mask and an unmask.
- A mask covers the whole subtree. An unmask inside a masked view does
not unmask its content.
The server can also mask or unmask by class name or by rule. A rule matches a
UIKit view by its `accessibilityIdentifier`, its `accessibilityLabel`, its
text, or its kind of view. A rule can apply on every screen or on named
screens only. A screen name is the `screenName` of the latest
`InsightEventOtherScreenView` that your app logged. Without one, it is the
class name of the top view controller. Your app does not set class lists or
rules. Ask for them in your app's server-side settings.
Give each class as its runtime class name. The SDK matches the name exactly:
- A Swift class has its module name: `MyApp.BalanceLabel`.
- An Objective-C or UIKit class has no prefix: `UILabel`.
- The SDK does no substring match, so `Label` matches no class.
- In an entry with `*`, the `*` stands for any run of characters. For
example, `MyApp.Wallet*` matches every class whose name starts that way.
- A match includes the subclasses of the class.
- The SDK ignores an exact name that matches no class. To check a rule, look
at a recording.
Class names and server rules reach UIKit views only. A UIKit view that you
host with `UIViewRepresentable` is still a UIKit view. For an element inside
SwiftUI, use `screenRecordingMask()` and `screenRecordingUnmask()`.
#### Touches
The SDK withholds a tap when it lands on one of the following:
- A secure or sensitive input
- A web view
- A video, camera, or GPU-backed view
- A map
- A PencilKit canvas
- An element that your app masks with the property, the identifier token, or
the modifier
A withheld tap leaves no coordinates in the recording, and the SDK drops the
whole gesture. The SDK records taps on other masked content. That includes content
that only the privacy level, a server rule, or the scan for personal data
masks, and unrecognized custom views. To withhold taps on such
content, mark it in your code. Two cases need a mark:
- A signature pad that your app draws itself, in `draw(_:)` or as a SwiftUI
`Canvas`. The SDK masks its pixels but records its taps, so a viewer can
replay the stroke. Mark the pad. `PKCanvasView` withholds its taps without
a mark.
- A video or GPU layer (`AVPlayerLayer`, `CAMetalLayer`) that you add to an
ordinary view. The SDK hides the layer in the frame but records a tap on
it. Mark the view that holds the layer.
In a UIKit screen, the SDK asks only the topmost drawn view under the finger.
A view drawn over a marked view, clear or not, takes the tap back. In a
SwiftUI screen, the SDK asks every drawn element under the finger, so a
clear overlay does not take the tap. If the server turns touch recording
off, the SDK records no touches.
#### Known limits
- The SDK does not scan SwiftUI `Text` for personal data. A card number in a
`Text` shows in the frame. Mark such text with `screenRecordingMask()`.
- A mark covers the element's layout frame. A child that you move out with
`.offset` shows where it draws. Mark that child too.
- A mark applied after a rotation covers the unrotated frame, so the ends of
the content show. Apply the mark before the transform:
`Text(cardNumber).screenRecordingMask().rotationEffect(.degrees(20))`.
- When the server masks images, every SwiftUI image, SF Symbol, and shape
hides. No workaround exists.
- The SDK always hides a SwiftUI `Canvas`, content under `.drawingGroup()`,
and charts drawn the same way. `screenRecordingUnmask()` does not show
them. No workaround exists.
- A plain text field hides what the user typed at the default text level.
No workaround exists.
- The selection of a menu-style `Picker` shows when the server masks input
text. Mark the picker with `screenRecordingMask()`.
- On iOS 26, `screenRecordingUnmask()` also shows text from an overlapping
sibling whose center falls inside the element. Keep unmasked elements off
secret text, or mark the secret text.
- The SDK does not record a window of your own that is not the key window,
such as a toast window. No workaround exists.
- In SwiftUI, every destination of one `NavigationStack` shares one screen
name in the recording, and so does every tab of one `TabView`. No
workaround exists.
2026-10-30 15:07:27 +03:00
## 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:
2026-10-31 23:39:07 +03:00
- Add the `AppTrackingTransparency` framework to your project and import it, together with `AdSupport` for the identifier:
2026-10-30 15:07:27 +03:00
```swift
import AppTrackingTransparency
2026-10-31 23:39:07 +03:00
import AdSupport
2026-10-30 15:07:27 +03:00
```
- Request permission from the user:
```swift
2026-10-31 23:39:07 +03:00
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")
2026-10-30 15:07:27 +03:00
}
}
```
- 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:
```xml
<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.
2026-10-31 23:39:07 +03:00
### Device name
2026-10-30 15:07:27 +03:00
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](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name) contains relevant information from Apple.
If you have acquired permissions, Insight SDK will collect this information.
2026-10-31 23:39:07 +03:00
### Carrier info
2026-10-30 15:07:27 +03:00
Starting iOS 16, carrier name and code information are deprecated. [Reference 1](https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/servicesubscribercellularproviders) and [Reference 2](https://forums.developer.apple.com/forums/thread/714876) contains relevant information from Apple.
## 6. Troubleshooting
2026-10-31 23:39:07 +03:00
### Common issues
2026-10-30 15:07:27 +03:00
**SDK not starting:**
- Verify API key is correct
- Check that the device can connect to the API endpoint
**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