# Push notifications

 There's a new version available!

These pages cover version 2 of our SDK, but a newer version is available. In general, we suggest that you update to the latest version to take advantage of new features and fixes.

*   Are you new to our SDKs? [Check out the latest docs.](/integrations/sdk/ios/getting-started)
*   Otherwise, [learn about updating to the latest version](/integrations/sdk/ios/whats-new/)

Our iOS SDK supports push notifications over APN or FCM. Use this page to get started with either service.

This page is part of a setup flow for the SDK. Before you continue, make sure you've implemented previous features—i.e. you can't receive push notifications before you identify people!

## Before you begin[](#before-you-begin)

This page explains how to receive push notifications using our SDK. However, before you can send push notifications to your audience, you need to enable Customer.io to send push notifications through your preferred service: [Apple Push Notification Service (APNs)](/journeys/push-getting-started/#for-ios) or [Firebase Cloud Messaging (FCM)](/push-getting-started/#for-android).

This process lets you receive basic push notifications in your app—a title and a message body. To send a more complicated push, complete the process on this page, and then see our [rich push](/integrations/sdk/ios/2.x/rich-push) documentation.

## Install the push package[](#install-the-push-package)

Before you can receive push notifications, you need to install the push package supporting the push service you use—APNs or FCM.

1.  Use Swift Package Manager to install your push package. See our [Getting Started](/integrations/sdk/ios/2.x/getting-started/#install) page for installation instructions.
    
    *   APNs: install `MessagingPushAPN`
    *   FCM: install `MessagingPushFCM`
2.  Enable the *Push Notifications* capability [in XCode](https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app).
    

## Register for push notifications[](#push-with-apns)

The instructions in this section set you up to receive simple push notifications with a `body` and `title`. After you follow these instructions, you’ll need to do a bit more work to support [rich push notifications](#rich-push).

🎉Updated in version 2.11.0

The SDK automatically handles push registration and push clicks for you. However, you’ll still need to identify users before you can send them push notifications.

 Using version 2.10 or earlier?

As of version 2.11, we automatically register device tokens and handle push clicks. [Follow our upgrade guide](/integrations/sdk/ios/2.x/update-210-to-211#upgrade-2.10) to remove unnecessary code and increase compatibility with 3rd party SDKs in your app.

1.  After you initialize the SDK, register for remote push to receive a device token from your push service. Your code changes slightly depending on the push service you use.
    
     APNs
    
    #### APNs[](#APNs)
    
    ```swift
    import CioTracking
    import CioMessagingPushAPN
    
    class AppDelegate: NSObject, UIApplicationDelegate {
    
     func application(
         _ application: UIApplication,
         didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
     ) -> Bool {        
         CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY")
         
         // Initialize Customer.io push features after you initialize the SDK: 
         MessagingPushAPN.initialize { config in
             // Automatically register push device tokens to the Customer.io SDK
             config.autoFetchDeviceToken = true
             // When your app is in the foreground and a push is delivered, show the push
             config.showPushAppInForeground = true
         }
         
         return true
     }
    }
    ```
    
     FCM
    
    #### FCM[](#FCM)
    
    ```swift
    import CioMessagingPushFCM
    import CioTracking
    import Firebase
    import FirebaseMessaging
    
    class AppDelegate: NSObject, UIApplicationDelegate {
     func application(
         _ application: UIApplication,
         didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
     ) -> Bool {        
         FirebaseApp.configure() 
         
         CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY")
    
         // Initialize Customer.io push features after you initialize the SDK: 
         MessagingPushFCM.initialize { config in
             // Automatically register push device tokens to the Customer.io SDK
             config.autoFetchDeviceToken = true
             // When your app is in the foreground and a push is delivered, show the push
             config.showPushAppInForeground = true
         } 
    
         return true
     }
    }
    ```
    
2.  [Identify the person](/integrations/sdk/ios/2.x/identify) if you have not already. Even after you add a device token, you can’t use it until you associate it with a person.
    
    ```swift
    CustomerIO.shared.identify(identifier: "989388339", body: ["first_name": firstName]) 
    ```
    

When you identify a person, you should see their device token in your workspace. You can send a simple push notification to test your implementation.

Note that when you [identify a different person](/integrations/sdk/ios/2.x/identify) or [stop identifying a person](/integrations/sdk/ios/2.x/identify/#clearIdentify), the SDK automatically removes the device token from any previously identified profile. This ensures that a device token is only registered to the *currently identified profile* in the SDK and prevents you from sending duplicate messages messaging the wrong person.

## Set up rich push[](#rich-push)

This process prepares your app to receive push notifications with images and links.

1.  [Add a Service App Extension to your project in Xcode](https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications).
    
2.  You should now see a new file added to your Xcode project. The file is probably named `NotificationService` and looks similar to this.
    
    ```swift
    import UserNotifications
    
    class NotificationService: UNNotificationServiceExtension {
    
     override func didReceive(
         _ request: UNNotificationRequest,
         withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
     ) {
    
     }
    
     override func serviceExtensionTimeWillExpire() {
    
     }
    }
    ```
    
3.  Modify this file by selecting the push package you want to import and calling the appropriate Customer.io functions. Your code changes if:
    
    *   Customer.io is your only push/rich push provider
    *   Customer.io **is not** your only provider
    *   You want to take advantage of push features outside the Customer.io, like action buttons; in this case, you’ll need to set your own completion handler.
    
     Customer.io push only
    
    #### Customer.io push only[](#Customer.io push only)
    
    ```
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    ```
    
    ```swift
    // Keep the import for your push provider—FCM or APN, and
    // remove the other import statement
    import CioMessagingPushFCM
    import CioMessagingPushAPN
    import UserNotifications
    import CioTracking
       
    class NotificationService: UNNotificationServiceExtension {
       
        override func didReceive(
            _ request: UNNotificationRequest,
            withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
        ) {
            // Because of the behavior of Notification Service Extensions in iOS, you need to 
            // initialize the Customer.io SDK in your host app and in your Notification Service.         
            // The last parameter optionally allows you to configure the SDK. 
            CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.US) { config in
                config.autoTrackPushEvents = true 
            }
    
            // For simple apps that only use Customer.io for sending rich push messages,
            // This 1 line of code is all that you need!
            MessagingPush.shared.didReceive(request, withContentHandler: contentHandler) 
        }
       
        override func serviceExtensionTimeWillExpire() {
            MessagingPush.shared.serviceExtensionTimeWillExpire()
        }
    }
       
    ```
    
     Multiple push services
    
    #### Multiple push services[](#Multiple push services)
    
    ```
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    ```
    
    ```swift
    // Keep the import for your push provider—FCM or APN, and
    // remove the other import statement
    import CioMessagingPushFCM
    import CioMessagingPushAPN
    import UserNotifications
    import CioTracking
    
    class NotificationService: UNNotificationServiceExtension {
    
     override func didReceive(
         _ request: UNNotificationRequest,
         withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
     ) {
         // Because of the behavior of Notification Service Extensions in iOS, you need to 
         // initialize the Customer.io SDK in your host app and in your Notification Service.         
         // The last parameter optionally allows you to configure the SDK. 
         CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.US) { config in
             config.autoTrackPushEvents = true 
         }
    
         // If you use a service other than Customer.io to send rich push,
         // you can check if the SDK handled the rich push for you. If it did not, you
         // know that the push was *not* sent by Customer.io and you can try another way.
         let handled = MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
         if !handled {
             // Rich push was *not* sent by Customer.io. Handle the rich push in another way.
         }
     }
    
     override func serviceExtensionTimeWillExpire() {
         MessagingPush.shared.serviceExtensionTimeWillExpire()
     }
    }
    ```
    
     Custom completion handler
    
    #### Custom completion handler[](#Custom completion handler)
    
    ```
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    ```
    
    ```swift
    // Keep the import for your push provider—FCM or APN, and
    // remove the other import statement
    import CioMessagingPushFCM
    import CioMessagingPushAPN
    import UserNotifications
    import CioTracking
    
    class NotificationService: UNNotificationServiceExtension {
    
     override func didReceive(
         _ request: UNNotificationRequest,
         withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
     ) {
         // Because of the behavior of Notification Service Extensions in iOS, you need to 
         // initialize the Customer.io SDK in your host app and in your Notification Service.         
         // The last parameter optionally allows you to configure the SDK. 
         CustomerIO.initialize(siteId: "YOUR SITE ID", apiKey: "YOUR API KEY", region: Region.US) { config in
             config.autoTrackPushEvents = true 
         }
    
         // If you need to add features, like showing action buttons in your push, 
         // you can set your own completion handler.
         MessagingPush.shared.didReceive(request) { notificationContent in
             if let mutableContent = notificationContent.mutableCopy() as? UNMutableNotificationContent {
                 // Modify the push notification like adding action buttons!
             }
             contentHandler(notificationContent)
         }
     }
    
     override func serviceExtensionTimeWillExpire() {
         MessagingPush.shared.serviceExtensionTimeWillExpire()
     }
    }
    ```
    

Your app can now display rich push notifications in your app, including images, etc. However, if you want to enable deep links, you should continue to the [Deep links](#deep-links) section below.

## Deep links[](#deep-links)

Deep links let you open a specific page in your app instead of opening the device’s web browser. Want to open a screen in your app or perform an action when a push notification or in-app button is clicked? Deep links work great for this!

Setup deep linking in your app. There are two ways to do this; you can do both if you want.

*   **Universal Links**: universal links let you open your mobile app instead of a web browser when someone interacts with a *URL on your website*. For example: `https://your-social-media-app.com/profile?username=dana`—notice how this URL is the same format as a webpage.
*   **App scheme**: app scheme deep links are quick and easy to setup. Example of an app scheme deep link: `your-social-media-app://profile?username=dana`. Notice how this URL is *not* a URL that could show a webpage if your mobile app is not installed.

Universal Links provide a fallback for links if your audience doesn’t have your app installed, but they take longer to set up than *App Scheme* deep links. App Scheme links are easier to set up but won’t work if your audience doesn’t have your app installed.

### Set up Universal Links[](#universal-links-deep-links)

To enable Universal Links in your iOS app, follow the instructions [on the Apple documentation website](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app). Be sure to complete all of the steps required including [making modifications to your website to host a new file](https://developer.apple.com/documentation/Xcode/supporting-associated-domains) and [making modifications to your mobile app’s code to handle the deep link](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app).

 Install iOS SDK 2.0.6 or later

Earlier versions of the SDK had an issue causing both your app and browser to open when users tapped a universal link.

Depending on how you set up your mobile app (SwiftUI, UIKit, watchOS, etc), you may need to [handle deep links in multiple functions](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) in your code. One of the functions you are required to have in your app is:

```swift
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        guard let universalLinkUrl = userActivity.webpageURL else {
            return false 
        }

        // Parse `universalLinkUrl` object to perform the action you want in your app. 

        // return true from this function if your app handled the deep link. 
        // return false from this function if your app did not handle the deep link and you want sdk to open the URL in a browser.
    }
}
```

 Check universal links using your Notes app

Try creating a note with a universal link and tapping the link to double-check that the link opens in your app and not in a browser window. This is an easy way to make sure that you’ve set up universal links correctly.

If your links are opening Safari instead of your app, [check this Apple document to troubleshoot](https://developer.apple.com/documentation/technotes/tn3155-debugging-universal-links).

### Setup App Scheme Deep Links[](#app-scheme-deep-links)

1.  Open your Xcode project and go to your project’s settings. Select your app **Target**, click the **Info** tab, and then click **URL Types** > to create a new URL Type.
    
    [![visual of the typed instructions in the sentence above to create a new URL type](https://docs.customer.io/images/xcode_appscheme_urltypes.jpeg)](#bbf5a38ebbb81ce018f4e79f703853b4-lightbox)
    
2.  Enter a unique value for your app for URL Schemes.
    
    [![visual of the typed instructions in the sentence above to enter a unique value for URL scheme](https://docs.customer.io/images/xcode_appscheme_makeurltype.jpeg)](#e9aefb85a68022dce00ef35fabc0ab4f-lightbox)
    

## Capture push metrics[](#capture-push-metrics)

Customer.io supports device-side metrics that help you determine the efficacy of your push notifications: `delivered` when a push notification is received by the app and `opened` when a push notification is clicked.

If you already configured [rich push notifications](/integrations/sdk/ios/2.x/rich-push/), the SDK will automatically track `opened` and `delivered` events for push notifications originating from Customer.io.

Otherwise, you can:

*   [Record push metrics with `UserNotifications`](#metrics-userNotifications).
*   [Extract delivery ID and Delivery Token parameters directly](#metrics-direct).

### Capture push metrics with `UserNotifications`[](#metrics-userNotifications)

If you’re using a version of iOS that supports `UserNotifications`, you can track metrics using our `UNNotificationContent` helper.

```swift
func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
) {
    // This 1 line of code might be all that you need!
    MessagingPush.shared.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)

    // If you use `UserNotifications` for more then Customer.io push notifications, you can check 
    // if the SDK handled the push for you or not. 
    let handled = MessagingPush.shared.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)
    if !handled {
        // Notification was *not* displayed by Customer.io. Handle the notification yourself. 
    }
}
```

### Extract delivery ID and token[](#metrics-direct)

If you’re not using a version of iOS that supports `UserNotifications`, you should send the push metric manually by extracting the `CIO-Delivery-ID` and `CIO-Delivery-Token` parameters directly to track push metrics.

```swift
guard let deliveryID: String = notificationContent.userInfo["CIO-Delivery-ID"] as? String, 
      let deviceToken: String = notificationContent.userInfo["CIO-Delivery-Token"] as? String else {
    // Not a push notification delivered by Customer.io
    return
}

MessagingPush.shared.trackMetric(deliveryID: deliveryID, event: .delivered, deviceToken: deviceToken)
```

### Disable automatic push tracking[](#disable-automatic-push-tracking)

Automatic push metric recording is enabled by default when you install the SDK. You can disable this behavior in the SDK’s configuration.

```swift
CustomerIO.initialize(...) { config in 
  config.autoTrackPushEvents = false
}
```

## Test your push implementation[](#test-your-push-implementation)

After you set up push notifications, you should send some test messages. You can send messages through the Customer.io push composer. If your app is set up to use keys outside the standard ones that our SDK supports, you’ll want to send a [custom payload](/journeys/push-custom-payloads/#getting-started-with-custom-payloads).

[![The custom payload editor for a push notification](https://docs.customer.io/images/push-custom-ios.png)](#0c9b0c5b97db4dbadfe8437d8b8fe49c-lightbox)

The payloads below represent what your app can expect to receive from Customer.io. If you use a custom payload, you’ll need to use the format(s) below to make sure that the SDK receives your message properly.

When testing, you should:

*   Set the `link` to the deep link URL that you want to open when your tester taps your notification.
*   Set the `image` to the URL of an image you want to show in your notification. It’s important that the image URL starts with `https://` and *not* `http://` or the image might not show up.
    
     APNS payload
    
    #### APNS payload[](#APNS payload)
    
    ```json
    {
        "aps": {
            // basic iOS message and options go here
            "mutable-content": 1,
            "sound": "default",
            "alert": {
                "title": "string", //(optional) The title of the notification.
                "body": "string" //(optional) The message you want to send.
            }
        },
        "CIO": {
            "push": {
                "link": "string", //generally a deep link, i.e. my-app:://...
                "image": "string" //HTTPS URL of your image, including file extension
            }
        }
    }
    ```
    
    *   CIO object
        
        Contains options supported by the Customer.io SDK.
        
        *   push object
            
            Required Describes push notification options supported by the CIO SDK.
            
    
     FCM payload
    
    #### FCM payload[](#FCM payload)
    
    ```json
    {
      "message": {
        "apns": {
          "payload": {
            "aps": {
              // basic iOS message and options go here
              "mutable-content": 1,
              "sound": "default",
              "alert": {
                "title": "string", //(optional) The title of the notification.
                "body": "string" //(optional) The message you want to send.
               }
            },
            "CIO": {
              "push": {
                "link": "string", //generally a deep link, i.e. my-app://... or https://yourwebsite.com/...
                "image": "string" //HTTPS URL of your image, including file extension
              }
            }
          },
          "headers": {
            // (optional) headers to send to the Apple Push Notification Service.
            "apns-priority": 10
          }
        } 
      }
    }
    ```
    
    *   message object
        
        Required The base object for all FCM payloads.
        
        *   apns object
            
            Required Defines a payload for iOS devices sent through Firebase Cloud Messaging (FCM).
            
            *   headers object
                
                Headers defined by [Apple’s payload reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns) that you want to pass through FCM.
                
            *   payload object
                
                Required Contains a push payload.
                
                *   CIO object
                    
                    Contains properties interpreted by the Customer.io iOS SDK.
                    
                    *   push object
                        
                        Required A push payload for the iOS SDK.
                        
                *   *Custom key-value pairs\** any type
                    
                    Additional properties that you've set up your app to interpret outside of the Customer.io SDK.
                    
    

## Sound in push notifications[](#sound-in-push-notifications)

When you send a push notification to iOS devices that uses our SDK, you can opt to send the *Default* system sound or no sound at all. If your audience’s phone is set to vibrate, or they’ve disabled sound permissions for your app, the *Default* setting will cause the device to vibrate rather than playing a sound.

In most cases, you should use the *Default* sound setting to make sure your audience hears (or feels) your message. But, before you send sound, you should understand:

1.  Your app needs permission from your users to play sounds. This is done by your app, not our SDKs. [Here’s an example from our iOS sample app](https://github.com/customerio/customerio-ios/blob/main/Apps/APN-UIKit/APN%20UIKit/Util/NotificationUtil.swift#L12-L13) showing how to request sound permissions.
2.  iOS users can go into *System Settings* and disable sound permissions for your app. Enabling the *Default* setting doesn’t guarantee that your audience hears a sound when your message is delivered!

 We don’t support custom sounds yet

If you want to send a custom sound, you’ll need to handle it on your own, outside the SDK and use a custom payload when you set up your push notifications.