Mobile integration

iOS SDK Integration

In this section you will find information on how to integrate the MobSur SDK in your native iOS application. The SDK shows surveys and, since version 1.2, in-app message experiments.


Prerequisites

  • Supported Destinations: iPhone and iPad
  • Minimum version of iOS: 15.0
  • Xcode 26 or later

Installation Guide

The recommended type of integration is with the Swift Package Manager.

Alternatively, you can download the .xcframework file and manually import it in your project. CocoaPods only has version 1.1, without experiments.

Option 1: Swift Package Manager installation

Swift Package Manager is recommended by Apple way of including third-party libraries in your project. The process is quick and easy, and you can update the SDK with just a simple click.

Integration steps:

  1. Open your project or workspace in XCode
  2. On the main menu select File → Add Packages…
  3. In the Package Manager, you should paste the SDK URL in the search bar. https://github.com/eden-tech-labs/MobSur_iOS_SDK
  4. Pick Up to Next Major Version from 1.2.0.
  5. Click Add Package in the bottom right corner and add the MobSur_iOS_SDK library to your app target.
  6. Then proceed to the Integration Guide

Or in Package.swift:

.package(url: "https://github.com/eden-tech-labs/MobSur_iOS_SDK", from: "1.2.0")

Option 2: Using Cocoapods

If this is your first pod dependency, follow the instructions on cocoapods.org If you already have Podfile in your project you should add the following:

target 'YourAppTarget' do

    #Other Pod related information

    pod 'MobSurSDK', '~> 1.1'
end

After that open the console, navigate to the project directory and run pod install The pod should be installed and you can proceed to the Integration Guide.

CocoaPods stays on 1.1

CocoaPods trunk becomes read-only on December 2, 2026, so 1.1.x is the last MobSur release published there. Version 1.2 and later, which add in-app message experiments, ship through Swift Package Manager and the XCFramework download.

Option 3: XCFramework installation

This type of installation is suitable if you want to keep everything related to your project local and do not depend on the network traffic.

iOS add framework example

  1. Download MobSur_iOS_SDK.xcframework.zip from the latest release
  2. Extract it so you can see MobSur_iOS_SDK.xcframework
  3. Open your project or workspace in XCode
  4. In the Project Navigator (shortcut ⌘ + 1) make sure you see the Frameworks folder under your project.
  5. Drag and drop the extracted MobSur_iOS_SDK.xcframework in the Frameworks folder.
  6. In the newly opened window make sure your target and Copy items if needed are selected.
  7. Click the Finish button.
  8. Under your target's General → Frameworks, Libraries, and Embedded Content, set it to Embed & Sign.

Integration Guide

After you’ve completed one of the installation steps above, you should have the MobSur SDK in your project. The next step is to initialize it and show your first survey.

Initialization of the SDK should be done as early as possible in your app initialization, but the right place depends on your project and its’ needs.

It’s a good practice to do this in the AppDelegate so the event tracking may start as soon as possible.

App ID!

You can get the App ID from the MobSur Dashboard.
More information is available here

If you are using UIKit

Open your AppDelegate file and add the initialization code in the didFinishLaunchingWithOptions method.

Do not forget to import the SDK in the beginning of the file import MobSur_iOS_SDK

The user id is defined by you and it is used to distinguish different users, answering the surveys.

import UIKit
import MobSur_iOS_SDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  
	func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: 
	[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
	  
		// userID and debug are optional parameters.
		// If you don't know the user ID yet, pass nil and call updateUser(id:) later.
		MobSurSDK.shared.setup(appID: "YourAppID", userID: "123", debug: true)
	  
		// Remaining contents of didFinishLaunchingWithOptions method  
	  
	  return true
	}
  
// Remaining contents of your AppDelegate Class

}

If you are using Swift UI

import SwiftUI
import MobSur_iOS_SDK

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        MobSurSDK.shared.setup(appID: "YourAppID", userID: "123", debug: true)
        return true
    }
}

@main
struct MobSur_iOS_DemoApp: App {

    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

If you do not know the user id during initialization and/or when the user id is changed (logout/switch user) you should call the updateUser method. Do not forget to import the SDK in the beginning of your file import MobSur_iOS_SDK

func userLoggedIn(newUserId: String) {

	// Other login related logic...

	MobSurSDK.shared.updateUser(id: newUserId)
}

Right after you set the user ID, the SDK fetches the eligible surveys for this person.

The user ID identifies the person answering. MobSur uses it to sample your audience, to avoid asking someone who already answered, to apply the time between surveys, and to count monthly tracked users.

  • Use an ID that stays the same for the same person, such as your account ID.
  • If you pass nil and no ID was set before, the SDK creates a random ID once and keeps it on the device.

Don't use a new random ID per launch

Every launch would then look like a new person: people who already answered would be asked again, and every launch would count as another monthly tracked user.

When the ID changes, the SDK forgets the previous person's cached surveys and experiments, occurrence counters and completed surveys. Attributes are kept, and so is the record of experiments each person has run, so switching accounts and back never shows someone an experiment twice.

Describe the person (attributes)

MobSurSDK.shared.setAttributes(["is_subscribed": false, "days_since_install": 7])

Attributes decide which experiments a person is in.

  • Values must be strings, numbers or booleans. Anything else is ignored, and logged in debug mode.
  • They are merged into the ones set before and kept across launches. A nil value removes a key.
  • When anything changes, the SDK fetches again and keeps the occurrence counts. No experiment runs until that fetch succeeds.
  • You can call it before setup.

Handle the call to action and keep messages off your screens

MobSurSDK.shared.onAction = { action in
    // e.g. "myapp://paywall", after the message sheet has closed
    router.open(action)
}
MobSurSDK.shared.canShowOverlay = {
    !paywallIsOnScreen
}
  • onAction receives an experiment message's call to action after the person taps it and the sheet has closed. Without it, the action is opened with UIApplication.open(_:) if it is a URL.
  • canShowOverlay is checked right before a survey or message would appear, after the rule's delay. Return false while your own paywall, onboarding or another modal flow is on screen: nothing appears, nothing is reported, and the session's slot stays free, so a later event can try again.

Both are called on the main thread and can be set at any time.

Every SDK method can be called from any thread and never throws. Calls made before setup are ignored, except setAttributes(_:), onAction and canShowOverlay.

Launching your survey (Events)

MobSur surveys are triggered by events in your app. These events are identified by name which is of type String.

Event name!

The name of the event should be the same as the one in the Dashboard.
You can check it here

As a best practice, you should wrap all your event tracking in one class that sends them to all related services. This way you can reuse these events with other services and easily switch to another provider if needed.

class EventTracker {
	static func purchaseFinished() {
		eventFired(name: "PurchaseFinished")
	}

	private static func eventFired(name: String) {
		MobSurSDK.shared.event(name: name)
		// Other event related logic may go here
	}
}

You can extend it to fit your needs.

Here’s an example usage in a simple shopping cart view.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Cart overview")

						// Other important parts of your UI ...
            
            Button("Confirm my order") {
                EventTracker.purchaseFinished()
            }
        }
    }
}

In reality, the logic may be separated into other classes that manage the cart logic or other user behavior.

How the launch settings behave

  • App event is matched exactly, including case.
  • From / Through occurrence: the SDK counts each event per survey on the device, across launches. For example, start at 3 to ask after the third time.
  • Delay after event: the SDK waits this long before showing the survey. If the app can't show it by then (the app is in the background, an alert or a transition is on screen, or canShowOverlay returns false), nothing opens, the event that selected it isn't counted, and a later event can try again.
  • At most one survey or experiment runs per app session, and a survey the person finished never opens again. Experiments are checked first.
  • If the person closes a survey without finishing, a later session can show it again while the count is inside the occurrence range. Set Through occurrence to limit repeats.
  • Audience, platforms, languages, versions, dates, response target and time between surveys are applied by the server. iPad counts as the iOS platform.
  • The SDK fetches surveys and experiments on setup, when the user ID or the attributes change, and on an event when nothing was requested for 6 hours in this app session.

In-app message experiments

Your team can run an experiment from MobSur: a short in-app message (an optional image, a title, a body, a call to action and a dismiss button) shown to part of an audience, while the rest (the control arm) see nothing. Comparing the two arms shows what the message changes.

  • The server picks who is in the experiment from the platform, the app version and your attributes, assigns each person an arm once, and sends it with the surveys.
  • Experiments use the same launch settings as surveys (event, From / Through occurrence, delay) and are checked before surveys on each event(name:) call. They share the one-per-session rule.
  • Treatment: after the delay the message appears in a bottom sheet, in system fonts and colors (light and dark) with your app's tint color on the call to action. Tapping it calls onAction. The dismiss button or a swipe closes it.
  • Control: nothing appears, but the exposure is still reported and the session's slot is used, so both arms are measured under the same conditions.
  • Each experiment runs at most once per person on the device.

The SDK reports exposed, cta_tapped and dismissed to MobSur. Events are queued on the device and sent in order. Failed sends are retried with backoff, and at the next launch, so an offline exposure is still counted later. These calls don't count towards monthly tracked users.

Experiments are off until your team runs one in MobSur, so nothing changes for apps that only use surveys.

Privacy manifest

The SDK includes its own PrivacyInfo.xcprivacy. It declares UserDefaults access (reason CA92.1) and the data MobSur collects: the user ID, survey answers, survey and experiment interactions (a survey received, opened, started or completed; a message shown, tapped or dismissed) and a coarse location derived by the server from the IP address. Nothing is used for tracking. Include these in your app's privacy details on App Store Connect.

Each request also sends the attributes you set with setAttributes(_:). Declare whatever they contain (for example subscription status) in your App Store privacy details too.

Troubleshooting

If you have done everything from the installation and integration guide, but you still do not see the survey you expect, you can check the following steps too.

  1. Make sure the AppID is correct.
  2. Check that the event name matches the dashboard exactly and that the occurrence range includes this occurrence.
  3. Remember that only one survey or experiment runs per app session. Relaunch the app to try again.
  4. If you set canShowOverlay, check that it returns true when the survey should appear.
  5. Try setting debug: true in the setup method and check the console for messages starting with MobSur:.

Upgrading from 1.1.x

Version 1.2 is source-compatible with 1.1. Install it with Swift Package Manager or the XCFramework, since CocoaPods stays on 1.1. Things to know:

  • Minimum iOS is 15.0 (was 12.0).
  • New: setAttributes(_:), onAction and canShowOverlay.
  • Experiments are off until your team runs one in MobSur, so nothing changes for apps that only use surveys, except the next point.
  • A dropped survey no longer counts its event. When a survey can't appear after its delay, the event that selected it isn't counted, so a "from 1 through 1" rule gets another chance.
  • If your app has paywalls, onboarding or other full-screen flows, set canShowOverlay so neither surveys nor messages appear on top of them.

Upgrading from 1.0.x

Version 1.1 keeps setup(appID:userID:debug:), updateUser(id:) and event(name:) unchanged, and keeps the user ID you set before. It now:

  • sends the platform as ios on iPad as well, so iPads match iOS platform targeting;
  • keeps working when one survey or rule can't be read, instead of dropping all of them;
  • stops counting while a survey is waiting or on screen, and never reopens a finished survey;
  • clears the previous person's data when the user ID changes;
  • ships a privacy manifest.

Sample project

A sample project can be found in our GitHub repository. It was written for version 1.0.

Previous
Getting started