> This page is part of the [Customer.io documentation](https://docs.customer.io). For the complete index, see [llms.txt](https://docs.customer.io/llms.txt).
> Last updated: September 2, 2026
> To take actions in Customer.io from an agent, use the [Customer.io CLI](https://docs.customer.io/ai/cli/get-started.md) or the [MCP server](https://docs.customer.io/ai/mcp/get-started.md).

# Integrate your app

Before you can send push notifications, you need to set up your workspace to send push notifications through your push provider and configure your app to receive push notifications. You can do this with or without our SDKs providing flexibility in how you send and receive push notifications.

When you integrate with us, you have some choices depending on the push platform you use (APNs, FCM) and whether or not you want to use [our SDKs](/sdk/)—though **we strongly recommend that you use our SDKs** if possible to simplify your integration process.

But, before you can send and receive push notifications with Customer.io, **you must**:

1.  Generate and add certificates for your push service, Apple Push Notification service (APNs) and/or Firebase Cloud Messaging (FCM).

2.  Configure push in your app. You can do this with [our SDKs](/integrations/sdk/) or integrate directly with our API. Our SDKs provide a ready-made interface to configure push. If you want to integrate Customer.io without using our SDKs, you’ll need to write your own code to:

    *   Identify profiles and set their device tokens
    *   Send events representing your users’ actions back to Customer.io
3.  Send yourself a push notification to test your implementation.

## Generate and add push certificates

Before you can send a push notification, you need to generate certificates from Apple’s push notification service (APNs) and/or Google’s Firebase Cloud Messaging service (FCM) and add them to your workspace. This authorizes Customer.io to send notifications to your app through your push provider(s).

### Firebase Cloud Messaging (FCM) setup

To send notifications through Firebase Cloud Messaging, you’ll need to upload a JSON server key that authorizes Customer.io to send notifications. If you already have your key, skip ahead to step 4 below.

The JSON server key must match the Sender ID that you use in your Firebase project.

1.  Log into the Firebase Console for your project.

2.  Click in the sidebar and go to **Project settings**.

    ![Access your project settings in firebase](https://docs.customer.io/images/project-settings.png)

3.  Go to **Service Accounts** and click **Generate New Private Key**. Confirm your choice and download the credential file.

    ![Generate a new private key in Firebase](https://docs.customer.io/images/generate-key.png)

4.  In Customer.io, go to your workspace’s **Settings** > **Workspace Settings** and click **Settings** next to *Push*.

5.  For *Android*, click **Enable**, and then click **Choose file…** to select the JSON server key you generated in previous steps. When you’re done, your workspace is setup to send notifications through Firebase to Android devices.

     ![image.png](https://docs.customer.io/images/image(317).png)

#### Send to iOS via Firebase

After you’ve set up Firebase for Android, you can enable Firebase as your iOS push-provider.

1.  In Customer.io, go to [\> *Workspace Settings* > *Push*.](https://fly.customer.io/workspaces/last/settings/actions/apps).

2.  Click **Add app** and give your app a name—or click an existing app to add a platform to it.

3.  Select the *iOS* platform, and choose *Firebase Cloud Messaging (FCM)*. An app’s iOS and Android platforms can share a single FCM credential.

 ![Push Settings - iOS_provider (FCM)](https://docs.customer.io/images/push_settings_ios_provider.png)

### Apple Push Notification service (APNs) setup

You can send push notifications to iOS devices using the [Apple Push Notification service (APNs) ↗](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification).

To authorize your Customer.io workspace to send notifications to iOS devices over Apple’s Push Notification service, you’ll need to upload your APNs `.p8` certificate and enter your Apple Developer *Key ID*, *Team ID*, and *Bundle ID*. If you already have your p8 certificate, you can skip ahead to step 5 below.

1.  Log into your Apple Developer account and go to **[Certificates, Identifiers & Profiles > Keys ↗](https://developer.apple.com/account/resources/authkeys)**. Click the blue button to create a new key.

2.  Click **Apple Push Notifications service (APNs)** and enter a name for the key.

3.  Click **Continue** and then **Register** to create the key.

4.  Download your keys and put it somewhere you’ll remember. You can only download your key once!

5.  In Customer.io, go to your workspace’s **Settings** > **Workspace Settings** and click **Settings** next to *Push*.

6.  Click **Enable** under *iOS*, and select the *Apple Push Notification service (APNs)* option.

7.  Click **Choose file…** and upload your .p8 certificate.

8.  Enter your *Key ID*, *Team ID*, and *Bundle ID*. You can find these in your [Apple Developer Account ↗](https://developer.apple.com/).

9.  (Optional) Enable the *Send all push notifications to sandbox* option.

    Your iOS certificate may have both sandbox and production environments; this option sends push notifications to both environments.

     ![image.png](https://docs.customer.io/images/image(320).png)

    Note

    We recommend [creating a separate workspace](/messaging/channels/push/qa-testing/#testing-push-notifications) for your sandbox environment.

10.  Click **Save Changes**

 ![Push Settings - iOS_provider (APNs)](https://docs.customer.io/images/push_settings_ios_provider_APNs.png)

#### Rotating your APNs credentials

You provide credentials for your developer account and app bundle. If you need to move your app to a new developer account or bundle, you’ll need to generate a new .p8 certificate and update your credentials in Customer.io.

**If you’ve already rotated your credentials and push notifications are failing**, stop and restart any automations, broadcasts, and/or transactional messages that send push notifications. Stopping and restarting establishes new connections to APNs using your updated credentials so push notifications will send properly.

1.  Stop any automations or active messages (One-time sends, Broadcasts, or Transactional messages) that send push notifications. If you don’t, push notifications will fail when you update your credentials. You can search for push notifications and trace those to relevant automations on the **[Content > Message Library](https://fly.customer.io/workspaces/last/journeys/message-library?channels=%5B%22push%22%5D)** page.
2.  Generate your new .p8 certificate in your [Apple Developer Account ↗](https://developer.apple.com/).
3.  In Customer.io, go to **[Settings > Workspace Settings > Push > iOS](https://fly.customer.io/workspaces/last/settings/actions/push/ios)**.
4.  Click **Edit authorization** and set your new credentials.
5.  Click **Save Changes**.
6.  Restart the automations, broadcasts, and/or transactional messages you. They’ll begin sending using your new credentials.

## Configure push without our SDKs

In general, we suggest that you integrate using [our SDKs](/integrations/sdk/), which provide ready-made methods to interpret messages, identify devices, and send client-side events.

However, if you want to write your own integration with Customer.io, we’ve provided some code samples below to help you get started with push notifications. You’ll need to familiarize yourself with your integration platform to understand the range of configuration options that you have available.

If your mobile app is already set up to receive push notifications, you won’t need to make many changes to work with Customer.io. But, you should be aware that we send two custom parameters in the payload of push notification: `CIO-Delivery-ID` & `CIO-Delivery-Token`. These are used for [sending Open events](#send-events) back to us.

### iOS App Setup

The following shows an example to help you register for remote notifications in iOS.

1.  Open the project editor, and go to the **Signing & Capabilities** tab.

     ![push notification capabilities tab](https://docs.customer.io/images/ios-capabilities.png)

2.  Click **Capability** and and select **Push Notifications**.

     ![Select the push notification option](https://docs.customer.io/images/ios-push-capability.png)

3.  Update the `didFinishLaunchingWithOptions` callback in the `AppDelegate.swift` to request the device token.

    ```
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Configure user interactions
        self.configureUserInteractions()

        // Register with APNs: this might change based on iOS versions you want to support
        UIApplication.shared.registerForRemoteNotifications()

        return true
    }
    ```

4.  Add the following methods to handle the behavior when the token request succeeds or fails.

    ```
    // Handle remote notification registration.
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data){
        self.enableRemoteNotificationFeatures()
        // Convert token to string
        let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
        // Forward the token to your provider, using a custom method.
        self.forwardTokenToServer(token: deviceTokenString)
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        // The token is not currently available.
        print("Remote notification support is unavailable due to error: \(error.localizedDescription)")
        self.disableRemoteNotificationFeatures()
    }
    ```

5.  Handle the notification.

    ```
    // Push notification received
    func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
        // Print notification payload data
        print("Push notification received: \(data)")

        // Customer.io push notifications include data regarding the push
        // message in the data part of the payload which can be used to send
        // feedback into our system.
        var deliveryID: String = "";
        if let value = data["CIO-Delivery-ID"] {
            deliveryID = String(describing: value)
        }
        var deliveryToken: String = "";
        if let value = data["CIO-Delivery-Token"] {
            deliveryToken = String(describing: value)
        }
    }
    ```

### Android App Setup

The following shows an example of how to register with Firebase in Android. The easiest way to integrate Firebase Cloud Messaging into your Android app is to use the `Firebase Assistant Tool` in Android Studio. It walks you through the required steps.

1.  Add the Firebase SDK as a dependency into your `build.gradle` file.

    ```
    compile 'com.google.firebase:firebase-messaging:12.0.1'
    ```

2.  Create a new service that extends the `FirebaseInstanceIdService` class. Within this class you need a `onTokenRefresh` function in which you can use `FirebaseInstanceId.getInstance().getToken()` to retrieve the device message token.

    Note that this function is only called when the device token changes, so if you need access to it at other activities you may want to save it in a variable for later use.

    ```
    public class FirebaseIdentifierService extends FirebaseInstanceIdService {
        public FirebaseIdentifierService() {
        }

        @Override
        public void onTokenRefresh() {
            // Get updated InstanceID token.
            String refreshedToken = FirebaseInstanceId.getInstance().getToken();
            Log.d("firebase", "Refreshed token: " + refreshedToken);
        }
    }
    ```

3.  Update the `AndroidManifest.xml` to add the service.

    ```
    <service
        android:name=".FirebaseIdentifierService"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
        </intent-filter>
    </service>
    ```

4.  Now that you can generate tokens, you can handle incoming messages. Create a new service, extending `FirebaseMessagingService`, to handle messages.

    ```
    public class NotifierService extends FirebaseMessagingService {
        private static final String TAG = "messaging";

        public NotifierService() {
        }

        @Override
        public void onMessageReceived(RemoteMessage remoteMessage) {
            // Check if message contains a data payload.
            // You can have data only notifications.
            if (remoteMessage.getData().size() > 0) {
                Log.d(TAG, "Message data payload: " + remoteMessage.getData());

                // Customer.io push notifications include data regarding the push
                // message in the data part of the payload which can be used to send
                // feedback into our system.
                String deliveryId = remoteMessage.getData().get("CIO-Delivery-ID");
                String deliveryToken = remoteMessage.getData().get("CIO-Delivery-Token");
            }

            // Check if message contains a notification payload.
            if (remoteMessage.getNotification() != null) {
                handleNotification(remoteMessage.getNotification());
            }
        }

        private void handleNotification(RemoteMessage.Notification notification) {
            Log.d(TAG, "Message Notification Body: " + notification.getBody());
        }
    }
    ```

5.  Update the `AndroidManifest.xml` one more time to add the new service.

    ```
    <service
        android:name=".NotifierService"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>
    ```

### Identify Device Tokens

Before you can send a push notification, you need to identify the profile—and their device—using your app. Typically, you should send this information every time someone launches your app on their client device.

We recommend that you make calls using [one of our client libraries](/integrations/data-in/connections/servers/) from your backend system rather than directly from your app. If you can’t do this, and you need to make calls from within your app, you’ll want to make sure that they run asynchronously.

To add a device to the customer profile, call the following endpoints in either our Pipelines API (recommended) or our Track API. If your account is in the EU region, make sure you use the appropriate `-eu` URLs.

Pipelines API (Recommended)Classic Track API

#### Pipelines API (Recommended)

```
Method:  POST
URL:     https://cdp.customer.io/v1/track
JSON Payload:
{
  "type": "track",
  "event": "Device Created or Updated",
  "userId": "42",
  "properties": {
    "device": {
      "token": "string",
      "type": "ios"
    }
  },
  "timestamp": "2021-07-14T19:10:25.000Z"
}
```

#### Classic Track API

```
Method:  PUT
URL:     https://track.customer.io/api/v1/customers/{customer_id}/devices
JSON Payload:
{
    "device": {
        "id": "messaging token",
        "platform": "ios/android",
        "last_used": UNIX timestamp when the device was used,
        "attributes": {
            "app_identifier": "com.example.yourapp"
        }
    }
}
```

We store up to 25 devices

If you add a 26th device, we’ll remove the device with the oldest `last_used` timestamp.

#### Send the app identifier for each device

We recommend that you send the app identifier for each device as an attribute on the device object when you register it.

If you have more than one app in your workspace, we use the `app_identifier` to send notifications to the right app. The `app_identifier` value must match the **Bundle ID / App identifier** you entered with that app’s push credentials in *\> Workspace settings > Push*.

A device without an `app_identifier` receives push notifications that you send to your [default app](/messaging/channels/push/getting-started/#the-default-app). If you have a single app, you don’t need to send the attribute.

If you use the Pipelines API, you can send the app identifier as `context.app.namespace`. By default, we map this value to the device’s `app_identifier` attribute.

### Delete a device

You can remove a device from a profile as well. A profile can have up to 25 devices, but you should prune device tokens when your push provider invalidates them.

Pipelines API (Recommended)Classic Track API

#### Pipelines API (Recommended)

```
Method:  POST
URL:     https://cdp.customer.io/v1/track
JSON Payload:
{
  "type": "track",
  "event": "Device Deleted",
  "userId": "42",
  "properties": {
    "device": {
      "token": "string",
      "type": "ios"
    }
  },
  "timestamp": "2021-07-14T19:10:25.000Z"
}
```

#### Classic Track API

```
Method:  DELETE
URL:     https://track.customer.io/api/v1/customers/{customer_id}/devices/{token}
```

### Push payloads sent from Customer.io

We have a simple user interface for sending push notifications, including images and links. However, if you want to use our UI, you should either:

*   Integrate with [our SDK(s)](/integrations/sdk/)
*   Write your own integration, expecting to handle payloads in the following format.

 ![The simple push editor provides all features supported by our SDK](https://docs.customer.io/images/push-preview.png)

If your app is already set up to receive push notifications in different formats, you can send a [custom push payload](/messaging/channels/push/custom-payloads/) instead.

APNs (iOS)FCM (iOS)FCM (Android) basic pushFCM (Android) rich push

#### APNs (iOS)

Your *Image URL* and *Deep link or web URL* go inside a `CIO.push` object. *Custom Data* resides in the payload but outside the `CIO` and `aps` objects.

```
{
    "CIO": {
        "push": {
            "link": "string",
            "image": "string"
        }
    },
    "aps": {
        "alert": {
            "title": "Title of your push goes here!",
            "body": "Body of your push goes here!"
        },
        "sound": "default"
    },
    //custom keys go here
    "customKey": "a custom key"
}
```

#### FCM (iOS)

The `CIO.push` object contains the *link* and *image* fields from notification. *Custom Data* resides in the `payload` but outside the `CIO` and `aps` objects.

```
{
  "message": {
    "apns": {
      "payload": {
        "CIO": {
          "push": {
            "link": "string",
            "image": "string"
          }
        },
        "aps": {
          "alert": {
            "title": "string",
            "body": "string"
          },
          "sound": "default"
        },
        // custom keys go in the payload but outside the CIO and aps objects
        "customKey1": "custom keys",
        "customKey2": "another custom key"
      }
    }
  }
}
```

#### FCM (Android) basic push

For a basic push, the push title and body reside in the `message.notification`. If you add an image, link, or custom data, we move the entire payload moves under the `message.data` object.

```
{
    "message": {
        "notification": {
            "title": "string", //(optional) The title of the notification
            "body": "string", //The message you want to send
        }
    }
}
```

#### FCM (Android) rich push

For a basic push, the push title and body reside in the `message.notification` object—similar to [Firebase’s standard notification payload ↗](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#notification). If you add an image or link, the entire payload moves under the `message.data` object.

```
{
    "message": {
        "data": {
            "title": "string", //(optional) The title of the notification
            "body": "string", //The message you want to send
            "image": "string", //https URL to an image you want to include in the notification
            "link": "string", //Deep link in the format remote-habits://deep?message=hello&message2=world
           // other "custom keys" are sent inside this object
        }
    }
}
```

### Send events for key customer actions

You can send events representing your audience’s activities in your app. When you send an event, you’ll set the `name` of the event: this is how you’ll find your event when creating [segments](/journeys/segmentation/data-driven-segments/) or [automations](/journeys/send/campaigns/overview/).

You can also send “screen view” events, representing the screens that your audience visits in your app. See [screen view events](#screenview) for more information.

Pipelines (Recommended)Classic Track API

#### Pipelines (Recommended)

The `userId` in the request can be either an email address or an ID, associating the event payload with that person. But you can also send anonymous events.

```
Method:  POST
URL:     https://cdp.customer.io/v1/track
JSON Payload:
{
    "event": "set favorites",
    "userId": "42",
    "properties": {
        "fav-food": "pizza"
    },
    "timestamp": "2021-07-14T19:10:25.000Z"
}
```

#### Classic Track API

The `identifier` in the request can be either an email address or an ID, associating the event payload with that person. But you can also send anonymous events.

```
Method:  POST
URL:     https://track.customer.io/api/v1/customers/{identifier}/messaging/profiles/events
JSON Payload:
{
    "name": "set favorites",
    "timestamp": 1638393518,
    "data": {
        "fav-food": "pizza"
    }
}
```

We track push metrics using a different endpoint

To report push opened, converted, and delivered metrics for a specific push notification, see [push opened events](#push-opened).

#### Screen view events

Screen events track the screens that people visit in your app. You can use screen view data not only to track the parts of your app that people find most engaging, but also to create segments or tailor automations to people who use specific parts of your app.

If you use our Pipelines API, which we recommend, you can send screen view events with a `screen` call. In our classic Track API, you can send screen view events with a `type` of `screen`.

When you send a screen view event, the `name` should be the name of the screen a person viewed. You can also send additional properties in the event—these are things you might want to reference using [liquid](/journeys/liquid/using-liquid) in your automations and messages.

Pipelines (Recommended)Classic Track API

#### Pipelines (Recommended)

The `userId` in the request can be either an email address or an ID, associating the event payload with that person. But you can also send anonymous events.

```
Method:  POST
URL:     https://cdp.customer.io/v1/screen
JSON Payload:
{
    "userId": "97980cfea0067",
    "name": "mlb-scores",
    "properties": {
        "fav-team": "giants"
    }
}
```

#### Classic Track API

The `identifier` in the request can be either an email address or an ID, associating the event payload with that person. But you can also send anonymous events.

```
Method:  POST
URL:     https://track.customer.io/api/v1/customers/{identifier}/messaging/profiles/events
JSON Payload:
{
    "name": "mlb-scores",
    "type": "screen",
    "timestamp": 1638393518,
    "data": {
        "fav-team": "giants"
    }
}
```

### Track push opened metrics

You can report three metrics from the client side to help track the performance of your push notifications: `delivered`, `opened`, and `converted`.

If you use our [iOS](/integrations/sdk/ios/push/#capture-push-metrics) or [Android](/integrations/sdk/android/push/#capture-push-metrics) SDK, we can automatically track `delivered` and `opened` metrics for you.

Otherwise, you’ll need to send events to Customer.io to report metrics from your messages. When we deliver a push notification, we include `CIO-Delivery-ID` and `CIO-Delivery-Token` properties. You must include these properties in your `delivered`, `opened`, or `converted` events to tell us which message corresponds to the metric you’re reporting.

Pipelines (Recommended)Classic Track API

#### Pipelines (Recommended)

```
Method:  POST
URL:     https://cdp.customer.io/v1/track
JSON Payload:
{
    "event": "opened",
    "userId": "42",
    "properties": {
        "delivery_id": "CIO-Delivery-ID from the notification",
        "device_id": "CIO-Delivery-Token from the notification"
    },
    "timestamp": "2021-07-14T19:10:25.000Z"
}
```

#### Classic Track API

Our classic Track API uses a different endpoint for push metrics than other types of events.

```
Method:  POST
URL:     https://track.customer.io/api/v1/push/events
JSON Payload:
{
    "delivery_id": "CIO-Delivery-ID from the notification",
    "event": "opened",
    "device_id": "CIO-Delivery-Token from the notification",
    "timestamp": UNIX timestamp when the event occurred
}
```

## Send yourself a test notification

Verify that you’ve configured everything correctly by sending yourself a test push notification. There are a couple of ways to make sure that your initial configuration is working. You can send a single test message from the settings, or (if you have an iOS app) use a separate sandbox environment for your tests.

You can send yourself a test push from the Push Notification Settings page after you’ve uploaded your certificate(s).

 ![image.png](https://docs.customer.io/images/image(319).png)

Enter your device token. and you’ll hopefully get a test push to that device with the following content: “If you’re reading this, it means your integration with Customer.io is working!” and you’re ready to start adding push notifications to your automations.

You can find your device token on the **People** page; click the person you want to send a test message to and go to the **Devices** tab.

 ![image.png](https://docs.customer.io/images/image(325).png)

©2026 Peaberry Software, Inc. [Status](https://status.customerio.com/) [Terms of Service](https://customer.io/legal/terms-of-service/) [Privacy Policy](https://customer.io/legal/privacy-policy/)

[](https://www.linkedin.com/company/customer-io)[](https://twitter.com/customerio)[](https://www.youtube.com/channel/UCkCaWdezRoa8ZyR9pEVaipA)[](https://www.instagram.com/customer.io/)
