Push notifications

Notify mobile customers of agent replies when your app is closed. APNs setup for iOS, Firebase Cloud Messaging for Android, forwarding pushes when your app has its own handlers, and React Native specifics.

When an agent replies while your app is in the background, Kustomer sends a push through Apple Push Notification service (APNs) on iOS, or Firebase Cloud Messaging (FCM) on Android. Tapping the notification opens the conversation in the SDK's UI.

AgentKustomerAPNs / FCMYour app (chat SDK)AgentKustomerAPNs / FCMYour app (chat SDK)Request a device token1token2Register token for this customer3Reply in conversation4Push to the customer's devices5Notification6Tap opens the conversation7
Diagram source
sequenceDiagram
  autonumber
  participant App as Your app (chat SDK)
  participant OS as APNs / FCM
  participant K as Kustomer
  participant Agent
  App->>OS: Request a device token
  OS-->>App: token
  App->>K: Register token for this customer
  Agent->>K: Reply in conversation
  K->>OS: Push to the customer's devices
  OS-->>App: Notification
  App->>App: Tap opens the conversation

Push goes to the customer the device is registered to. Log the customer in with a JWT to reach them on every device, and log out when they sign out so the next user doesn't get their notifications.

iOS

  1. Create an APNs key

    In the Apple Developer portal, under Certificates, Identifiers & Profiles › Keys, create a key with Apple Push Notifications service (APNs) enabled and download the .p8 file. Note the Key ID and your Team ID. Make sure your app ID has the Push Notifications capability.

  2. Upload it to Kustomer

    In Kustomer, go to Apps › Chat, open the SDK tab, and in the iOS push settings enter the .p8 key, Team ID, Key ID, and every bundle ID that should receive pushes.

  3. Enable the capability

    In Xcode, add the Push Notifications capability to your app target.

  4. Forward the device token

    Kustomer.setup registers for remote notifications. Pass the result to the SDK:

    AppDelegate.swift
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      Kustomer.didRegisterForRemoteNotifications(deviceToken: deviceToken)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
      Kustomer.didFailToRegisterForRemoteNotifications(error: error)
    }
  5. Ask for permission

    Ask when it makes sense to the customer, for example after their first chat message:

    Swift
    Kustomer.requestAuthorizationForPush()

    This requests alert, sound and badge permission. If your app already asks for notification permission, you don't need it.

Your own notification delegate

If nothing else in your app sets UNUserNotificationCenter.current().delegate, setup installs the SDK's delegate and you're done. If your app has its own delegate, set it before Kustomer.setup and forward Kustomer's notifications:

AppDelegate.swift
extension AppDelegate: UNUserNotificationCenterDelegate {
  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              willPresent notification: UNNotification,
                              withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    if notification.isFromKustomer() {
      Kustomer.pushProvider.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler)
    } else {
      completionHandler([.banner, .sound])
    }
  }

  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              didReceive response: UNNotificationResponse,
                              withCompletionHandler completionHandler: @escaping () -> Void) {
    if response.notification.isFromKustomer() {
      Kustomer.pushProvider.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)
    } else {
      completionHandler()
    }
  }
}

The SDK opens the conversation when a notification is tapped, and hides Kustomer notifications while your app is in the foreground (in-app banners cover that case). A notification that launched the app is handled by setup. Don't also use the deprecated Kustomer.unUserNotificationCenterDelegate; combining them can recurse.

Test with development builds

Debug builds get sandbox device tokens. Set options.pushEnvironment = .development, and turn on Test push notifications in the brand's chat install settings. Production pushes for that brand are paused while it's on, so turn it off when you're done.

Android

  1. Add Firebase to your app

    Register the app in the Firebase console, add google-services.json, and apply the com.google.gms.google-services Gradle plugin. The SDK already depends on firebase-messaging.

  2. Upload the service account key

    In the Firebase console, under Project settings › Service accounts, generate a new private key. Upload the JSON file in Kustomer under Apps › Chat › Install Chat, in the Android section. (Legacy FCM server keys no longer work.)

  3. Register the device

    After Kustomer.init succeeds:

    Kotlin
    Kustomer.init(application = this, apiKey = key, options = options) { result ->
      if (result is KusResult.Success) Kustomer.getInstance().registerDevice()
    }
  4. Request notification permission

    The SDK doesn't declare POST_NOTIFICATIONS. On Android 13 and later, declare it and request it at a sensible moment:

    AndroidManifest.xml
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    Kotlin
    if (Build.VERSION.SDK_INT >= 33) {
      requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
    }

That's all when Kustomer is your only push sender: the SDK registers its own FirebaseMessagingService, re-registers when the token changes, and posts notifications.

Your own FirebaseMessagingService

Android delivers FCM messages to one service. If your app has its own, forward Kustomer's messages and tokens to the SDK:

MyMessagingService.kt
import com.kustomer.ui.utils.helpers.KusNotificationService

class MyMessagingService : FirebaseMessagingService() {
  override fun onMessageReceived(remoteMessage: RemoteMessage) {
    if (KusNotificationService.onMessageReceived(remoteMessage, applicationContext)) return
    // your own notifications
  }

  override fun onNewToken(token: String) {
    CoroutineScope(Dispatchers.IO).launch {
      Kustomer.getInstance().registerDeviceToken(token)
    }
    // your own token handling
  }
}

onMessageReceived returns true when the message was Kustomer's and it handled it. Pass a TaskStackBuilder as the third argument to control the back stack when the customer taps the notification.

Customize notifications

To changeDo this
Small iconAdd a drawable named ic_kus_chat_notification
Channel ID, name and descriptionOverride the strings kus_channel_id, kus_channel_name and kus_channel_description
Foreground bannersKustomerOptions.Builder().showInAppNotifications(false) turns them off

The SDK creates its channel with high importance, the default sound, lights and vibration.

React Native

React Native uses the platform mechanisms above.

Android is automatic when @react-native-firebase/messaging is installed: KustomerChat.configure registers the FCM token and handles messages. You still need the Firebase setup, the uploaded service account key, and the POST_NOTIFICATIONS permission. If your app already handles FCM, set skipFCMPushRegistration: true and forward:

TypeScript
import messaging from '@react-native-firebase/messaging'
import KustomerChat from '@kustomer/chat-react-native'

messaging().getToken().then(KustomerChat.setPushToken)
messaging().onTokenRefresh(KustomerChat.setPushToken)
messaging().onMessage((message) => {
  if (KustomerChat.isKustomerNotification(message)) KustomerChat.onRemoteMessage(message)
})

iOS needs the .p8 upload and the native AppDelegate token forwarding from the iOS steps. Set pushEnvironment: PushEnvironment.development in configure options while testing debug builds. The package's automatic token registration works only on Android, so turn it off on iOS:

TypeScript
import { Platform } from 'react-native'

await KustomerChat.configure(KUSTOMER_CHAT_KEY, {
  skipFCMPushRegistration: Platform.OS === 'ios',
})

KustomerChat.unsetPushToken() deregisters the device on both platforms.

Sign-out and opt-out

iOSAndroidReact Native
Stop pushes for this deviceKustomer.deregisterCurrentDeviceForPushNotifications { result in }deregisterDeviceForPushNotifications() (suspend)KustomerChat.logOut()
Logging out deregistersYesNo, deregister firstYes
Never registeroptions.disablePush = trueDon't call registerDevice()disablePush: true

On iOS, disablePush only stops registration; a device that registered earlier keeps receiving pushes until it's deregistered.

Troubleshooting

SymptomCheck
No pushes on iOS debug buildspushEnvironment is .development, and Test push notifications is on.
No pushes on iOS release buildsThe bundle ID is listed in Kustomer, and Test push notifications is off.
Pushes stopped after adding another push SDK (iOS)It replaced the notification delegate. Forward Kustomer notifications as shown above.
No pushes on Android 13+POST_NOTIFICATIONS is declared and granted.
No pushes on Android, permission grantedYour own FirebaseMessagingService isn't forwarding to KusNotificationService, or the service account JSON is from a different Firebase project.
The previous user's notifications arriveDeregister on sign-out. On Android, logOut() alone doesn't deregister.