# Set up rich push

Set up your app to support push notifications with images and deep links.

## 1\. Add a service extension to your project[](#1-add-a-service-extension-to-your-project)

[Add a Service App Extension to your project in Xcode](https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications).

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() {
   
    }
}
```

## 2\. Update the service extension[](#2-update-the-service-extension)

 Xcode 16.3+ users

If you encounter errors like “not available due to missing import of defining module ‘CioMessagingPush’”, go to your NotificationServiceExtension target’s **Build Settings** and set **Member Import Visibility** (`SWIFT_MEMBER_IMPORT_VISIBILITY`) to “Package” or disable it.

Modify your new `NotificationService` extension 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.

 App Groups for delivery tracking

The code samples below include a commented-out `.appGroupId()` line. To improve push delivery metric reliability, [set up App Groups](/integrations/sdk/ios/push/app-groups/) and enable that line with your App Group identifier.

 Customer.io push only

#### Customer.io push only[](#Customer.io push only)

```swift
// Keep the import for your push provider—FCM or APN, and
// remove the other import statement
import CioMessagingPushAPN 
import CioMessagingPushFCM 
import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
       // Use `MessagingPushFCM` if you are using FCM as push service provider
       MessagingPushAPN.initializeForExtension(
            withConfig: MessagingPushConfigBuilder(cdpApiKey: "YOUR_CDP_API_KEY")
                // Optional: specify region where your Customer.io account is located (.US or .EU). Default: US
                .region(.US)
                // Optional: set App Group ID for reliable push delivery tracking
                // .appGroupId("group.com.example.myapp.cio")
                .build()
       )

       MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
    }

    override func serviceExtensionTimeWillExpire() {
        MessagingPush.shared.serviceExtensionTimeWillExpire()
    }
}
```

 Multiple push services

#### Multiple push services[](#Multiple push services)

```swift
// Keep the import for your push provider—FCM or APN, and
// remove the other import statement
import CioMessagingPushFCM
import CioMessagingPushAPN
import UserNotifications
   
class NotificationService: UNNotificationServiceExtension {
   
    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        // Due to the behavior of Notification Service Extensions in iOS, you need to 
        // initialize the Push Module in both your host app and in your Notification Service.         
        // The config builder also lets you you to configure the push module.
       // Use `MessagingPushFCM` if you use FCM as your push service provider
       MessagingPushAPN.initializeForExtension(
            withConfig: MessagingPushConfigBuilder(cdpApiKey: "YOUR_CDP_API_KEY")
                .autoTrackPushEvents(true)
                // Optional: specify region where your Customer.io account is located (.US or .EU). Default: US
                .region(.US)
                // Optional: set App Group ID for reliable push delivery tracking
                // .appGroupId("group.com.example.myapp.cio")
                .build()
       )

        // 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)

```swift
// Keep the import for your push provider—FCM or APN, and
// remove the other import statement
import CioMessagingPushFCM
import CioMessagingPushAPN
import UserNotifications
import CioDataPipelines
   
class NotificationService: UNNotificationServiceExtension {
   
    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        // Due to the behavior of Notification Service Extensions in iOS, you need to 
        // initialize the Push Module in both your host app and in your Notification Service.         
        // The config builder also lets you you to configure the push module.
        // Use `MessagingPushFCM` if you use FCM as your push service provider
       MessagingPushAPN.initializeForExtension(
            withConfig: MessagingPushConfigBuilder(cdpApiKey: "YOUR_CDP_API_KEY")
                .autoTrackPushEvents(true)
                // Optional: specify region where your Customer.io account is located (.US or .EU). Default: US
                .region(.US)
                // Optional: set App Group ID for reliable push delivery tracking
                // .appGroupId("group.com.example.myapp.cio")
                .build()
       )

        // 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. See [Deep Links](/integrations/sdk/ios/push/deep-links) to enable deep links in your push notifications.

## Improve delivery metrics with App Groups[](#improve-delivery-metrics-with-app-groups)

For the most reliable push delivery tracking, set up [App Groups for push tracking](/integrations/sdk/ios/push/app-groups/). App Groups let the SDK recover delivery metrics that iOS might otherwise discard when it terminates the Notification Service Extension. Without this setup, you may lose some delivery data.