Push notifications SDK for iOS

Push notifications are currently in beta and are coming soon for all users. If you’re interested in early access to push notifications, contact us at help@ortto.com.

This page details how to install Ortto’s iOS software development kit (SDK) in your app to deliver push notifications to contacts.

The following instructions assume your app is built using Xcode.

Each of the code snippets provided is copyable. Simply hover over the snippet and click the copy icon in the top-right corner.

swift copy
Example code snippet showing copy function

These instructions cover the key steps to installing the Ortto iOS SDK and configuring your app to handle Ortto’s push notifications:

Once you complete these key steps, you’ll be ready to create and send push campaigns.


iOS developers have 2 options for enabling push notifications:

If using Firebase, you’ll need to:

  1. Create a new (or use an existing) Firebase project and configure Google Cloud roles and permissions.

  2. Upload the .json file created in your Firebase project to Ortto, so that Ortto’s notifications APIs can access your Firebase data.

Learn about creating the Firebase project and enabling Ortto access in Firebase cloud messaging setup.

If using APNS, in your Ortto account Settings  Push notifications  iOS notifications  Setup you simply need to select the Keys tab and provide the keys and IDs specified.

Push notifications only work on real devices and the iOS simulator will not be able to register for push notifications from Apple.


There are three key elements to the SDK installation:

  1. Install the and initialize SDK — install and initialize the relevant Firebase or APNs packages along with Ortto’s iOS SDK.

  2. Create a service extension — enable your app to receive notifications when the customer does not have the app open.

  3. Firebase additional setup — required if using Firebase Cloud Messaging.

  4. Deep links — enable deep linking in push notifications.

  5. Authorization token — register the contact’s device with Ortto.

Install and initialize the SDK

  1. In Xcode, in your app’s project, select File  Add Packages.

    add packages
  2. In the package manager, paste the URL for Ortto’s iOS SDK GitHub repository: https://github.com/autopilot3/ortto-push-ios-sdk.

    ortto sdk

    At Dependency Rule, we recommend you set Up to Next Major Version to keep your app up to date with the latest SDK, including new features that are added.

    major version

    Click Add package.

  3. You’ll see a list of packages available to install.

    Select OrttoPushSDKCore (required, this is the SDK for Ortto’s push notifications), and choose either OrttoPushMessagingAPNS (required for APNs-based projects) or OrttoPushMessagingFCM (required for Firebase-based projects) as relevant.

    ortto package list
    Example selection for installing Ortto SDK and APNS packages

    Click Add package.

  4. To install OrttoPushSDKCore, add the following to your project’s AppDelegate object:

    import OrttoPushSDKCore
    class AppDelegate: UIResponder, UIApplicationDelegate {
    	func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    		// Prepare Ortto SDK
    		let datasourceID = Bundle.main.object(forInfoDictionaryKey: "OrttoApplicationKey") as? String
    		let endpoint = Bundle.main.object(forInfoDictionaryKey: "OrttoEndpoint") as? String
        //see note below regarding push endpoint regions
    		Ortto.initialize(datasourceID: datasourceID!, endpoint: endpoint!, shouldSkipNonExistingContacts: true, allowsAnonUsers: false)
      func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    		PushMessaging.shared.registerDeviceToken(apnsToken: deviceToken)
    	func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let handled = PushMessaging.shared.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)
    	    if !handled {
            // tell the app that we have finished processing the user’s action / response
      func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    //			PushM
      // Receive displayed notifications for iOS 10 devices.
      func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
        return [[.alert, .sound]]

    Your <OrttoApplicationKey> value can be found in your Ortto account, at Settings  Push notifications  iOS notifications  Application key.

    Ortto’s default push API service endpoint is: https://push-api.autopilotapp.com/.

    Ortto customers who have their instance region set to Australia or Europe will need to use specific push endpoints relative to the region:

    • Australia: https://push-api.au.autopilotapp.com/

    • Europe: https://push-api.eu.autopilotapp.com/

Learn more about shouldSkipNonExistingContacts under Skip non-existing contacts and allowsAnonUsers under Unidentified users in the Identify people section.

Create a service extension

A service extension is required to enable your app to receive notifications when the customer does not have the app open (the app is running in the background or not running at all). The service is a special registered class that iOS passes notifications to.

To add the service extension, in Xcode:

  1. Navigate to the File  New  Target.

  2. At Choose a template…​ search for "notification" in the modal.

  3. Select Notification Service Extension.

  4. Click Next.

  5. Configure the extension target.

  6. Click Finish.

Once the extension target is added, modify it as follows:

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {

        self.contentHandler = contentHandler
        let handled = PushMessaging.shared.didReceive(request, withContentHandler: contentHandler)
        if !handled {

    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler,
            let bestAttemptContent =  bestAttemptContent {
1 Call the PushMessaging.shared.didReceive() method with the UNNotificationRequest object. The function will return true if Ortto has handled the notification and false if Ortto has ignored the notification request.
2 If the handled var is equal to false, this means you need to handle the processing of the notification request yourself.
3 If the notification request timeout is hit (30 seconds) you will have a chance to quickly modify the UNMutableNotificationContent object before it is presented to the contact.

Ensure your NotificationService extension target has access to the required SDK packages.

check packages
Example required packages for using APNS to send notifications

Firebase additional setup

If you are using Firebase, in addition to the setup described in Firebase cloud messaging setup, you’ll need to perform a few extra steps.

In your AppDelegate object (<project>/AppDelegate.swift):

  1. Add the following to the didFinishLaunchingWithOptions method:

    // Set up firebase
    // Assign the AppDelegate to Firebase
    Messaging.messaging().delegate = self
  2. Extend the Firebase MessagingDelegate protocol to intercept Firebase messages:

    extension AppDelegate: MessagingDelegate {
      // [START refresh_token]
      func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        PushMessaging.shared.messaging(messaging, didReceiveRegistrationToken: fcmToken)
          name: Notification.Name("FCMToken"),
          object: nil,
          userInfo: [:]

All actions utilize deeplinks and are routed to your SceneDelegate. Add code similar to the below to your SceneDelegate (<project>/SceneDelegate.swift) to intercept these inbound deep links and route to your controller:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {

      guard let context = URLContexts.first else { (2)

      guard let navController = window?.rootViewController as?  UINavigationController else {

      guard let vc = navController.storyboard?. instantiateViewController(identifier: "controller_deeplink") as? DeeplinkViewController else {

      vc.modalPresentationStyle = .fullScreen (5)
      vc.deepLink = context.url.absoluteString (1)
      navController.present(vc, animated: true)
1 To get an iOS deeplink value to use in a push campaign (at the Content step, as a button destination — see screenshot below), access it from here using the following steps.
2 Look for a URL context passed into the scene method.
3 Get the navigation controller for the scene.
4 Route and instantiate a new controller to handle the deeplink.
5 Present the controller to the contact in the navigation controller.
deeplink ui

Authorization token

Authorization is handled automatically by your AppDelegate. Ensure you are passing along the appropriate token to the PushMessaging shared instance like below:

# APNs
PushMessaging.shared.registerDeviceToken(apnsToken: deviceToken)

# Firebase
PushMessaging.shared.registerDeviceToken(fcmToken: deviceToken)

Identify people

Push notifications cannot be sent to anonymous contacts. A contact is considered anonymous when they are not logged in to the app or they cannot be identified using the identify function.

As such, you need to identify contacts who are subscribed to push and recognize them when they log in to your app. Once logged in, the contact can receive notifications.

Identifying people is also necessary for tracking events.

The identify method can capture the following contact attributes:

  • firstName,

  • lastName,

  • contactId,

  • email,

  • externalId,

  • phone, and

  • acceptsGDPR.

You must identify contacts by a minimum of 1 of the following attributes:

  • email,

  • phone

  • contactId, or

  • externalId.

Additional attributes are optional.

To identify contacts, where relevant (such as your login or main activity), create a UserIdentifier object:

let user = UserIdentifier(
    contactID: "abc123",
    email: "name@domain.com",
    phone: "+61404040404",
    externalID: currentUser?.uid,
    firstName: "Potato",
    lastName: "Head"

Ortto.shared.identify(userIdentifier: user)

The UserIdentifier object:

  • saves the contact’s information on the device and enables tracked events to be associated with the contact, and

  • associates the authorization token with the contact to handle push notifications (using OrttoPushSDKCore).

The SDK can only identify one contact at a time, and will save the most recently identified contact. If Jane Smith is identified, then the identify function calls John Smith, the SDK will consider John Smith the contact using the app.

We recommend updating the contact data at least every 2 months with an identify() call to capture any contact attribute changes. This function calls Ortto’s API to collect the current contact attribute data.

Ortto.shared.identify(userIdentifier: user);

Unidentified users

Unidentified users are people who have allowed push notifications but for whom you do not yet have any identifying information.

By default, unidentified users will not be added as a contact to your CDP until they are identified (allowsAnonUsers is set to false). However, Ortto will store the permission response so that if the user becomes a CDP contact in future, we can associate the notification permission response with them.

If preferred, you can enable unidentified users to be automatically added as contacts to your CDP. Ortto will use the user’s device token (FCM/APNs) and platform type (Android/iOS) to identify the user. To enable unidentified users to be added to your CDP, set allowsAnonUsers to true.

Capturing unidentified users as contacts may result in duplicate contacts.

Permission prompts

iOS push notification permissions are obtained by the contact (subscriber) accepting the notification request prompt per the app install. Apps are able to query notifications to see the current status of the notification permission.

To obtain a contact’s iOS push notification permission, you need to register your app delegate as the UNUserNotificationCenterDelegate.

If the contact has not yet accepted the Ortto-specific notification permission, iOS will prompt the contact to accept it. To enable this at the`AppDelegate` object, add application.registerForRemoteNotifications():

class AppDelegate: UIApplicationDelegate, UNUserNotificationCenterDelegate {

if #available(iOS 10.0, *) {
  // For iOS 10 display notification (sent via APNS)
  UNUserNotificationCenter.current().delegate = self

  let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    options: authOptions,
    completionHandler: { _, _ in }
} else {
  let settings: UIUserNotificationSettings =
    UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)


let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
    if let error = error {
        print("err: \(error.localizedDescription)")

Set push permission

We give you more control over contacts' push notification permissions with the setPermission(Permission) method. Use this method if you wish for further control around how Ortto understands your contacts' messaging preferences.

// Let the SDK determine if the user has granted permission (Default)

// The user has explicitly granted permission

// Opt the user out of push notifications

Skip non-existing contacts

The Ortto class initializer Ortto.initialize accepts a third parameter named skipNonExistingContacts which controls whether the Ortto API should ignore all permission requests for contacts it cannot identify.

This parameter is optional and defaults to false.

// Ignore all requests for contacts which do not exist in your Ortto CDP
		datasourceID: datasourceID!,
		endpoint: endpoint,
		skipNonExistingContacts: true,
    allowsAnonUsers: false

Track actions and events

Delivery events

Push message delivery (receipt) is automatically tracked in the Ortto SDK. Delivery events will be reflected in the Ortto app as a Delivered Push activity associated with a contact.

Click tracking

The Ortto iOS SDK automatically tracks which action the contact clicked in the notification message before calling UIApplication.shared.open(url, options: [:], completionHandler: nil) with the deep link string.

This method will populate the Clicked push activity for a contact, including the deep link URL in the activity attributes.

Ortto setup

In Ortto, at Settings  Push notifications  iOS notifications. Setup, you have 3 options by which to enable Ortto to send push notification campaign data to your app:

The Bundle ID can be found in Xcode in your project at Targets  General  Identity.

bundle id

Once the SDK installation and configuration is complete, and you have have provided the required credentials in the Ortto setup, Ortto will wait until it detects activity from your app before your iOS platform can be switched ON. Ortto needs to receive an initial request from your app to enable push permissions for a contact (via the permission prompt or an explicitly set push permission), which confirms that your app is correctly configured and is ready to deliver notifications to subscribers. Once the activity is successfully detected, Ortto sets your iOS notifications to ON, and you can select the platform when creating a push campaign.