Carillon docs

React Native SDK

Set up Expo or a bare React Native app for registration and notification taps.

@exostack/carillon-react-native requires the React Native New Architecture. It supports Expo through a config plugin and bare apps through native callback forwarding.

Samples on this page show placeholders. Sign in to the dashboard in this browser and they fill in with your own organization, app and mobile key.

Install

yarn add @exostack/carillon-react-native

Configure

import Carillon from '@exostack/carillon-react-native'Carillon.configure({ key: 'carillon_mk_live_your_mobile_key', debug: __DEV__ })// Call when your app should request notification permission.// 'allowed' | 'denied' | 'provisional' | 'undetermined'const permission = await Carillon.requestPermission()Carillon.identify('user-42')          // null forgets the identifierCarillon.setTags({ plan: 'pro', seats: 12 })   // replaced whole, never mergedCarillon.optOut()Carillon.optIn()const off = Carillon.onOpened((notification) => {const orderId = notification.payload.order_idif (typeof orderId === 'string') {  // Open this order in your app.}})await Carillon.debugInfo()            // registration diagnostics

requestPermission() takes nothing on either platform. Android's native call needs the activity its dialogue belongs to, and the module supplies the current one. With no activity in the foreground the promise rejects, since there is no screen to show a prompt on.

Expo

The config plugin ships inside this package.

{
  "expo": {
    "plugins": ["@exostack/carillon-react-native"],
    "android": { "googleServicesFile": "./google-services.json" }
  }
}

Run expo prebuild, then rebuild the native app. The plugin configures iOS push entitlements and callbacks, the Android messaging service, and Google services when the JSON file is present. For Kotlin MainActivity, it also forwards cold-start and warm notification taps from onCreate and onNewIntent. Existing callbacks are preserved. Java activities require conversion to Kotlin for automatic configuration; bare apps can use the manual forwarding below. The SDK detects the APNs environment from the signed build.

Bare workflow

Add the push capability, then forward the three callbacks. Import CarillonReactNative, not Carillon: your app links this package, and the Swift SDK is resolved for this package's pod alone.

import CarillonReactNative

func application(
  _ application: UIApplication,
  didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
  CarillonBridge.didRegister(token: deviceToken)
}

func application(
  _ application: UIApplication,
  didFailToRegisterForRemoteNotificationsWithError error: Error
) {
  CarillonBridge.didFailToRegister(error)
}

func userNotificationCenter(
  _ center: UNUserNotificationCenter,
  didReceive response: UNNotificationResponse,
  withCompletionHandler completionHandler: @escaping () -> Void
) {
  CarillonBridge.didOpen(response)
  completionHandler()
}

Set UNUserNotificationCenter.current().delegate before anything else in didFinishLaunching.

Opened payloads

onOpened exposes the reserved payload.carillon field as an object on both platforms. The bridge parses the Android JSON stamp without changing customer payload fields. deliveryId is also available directly on the notification.

Whole JavaScript numbers in setTags are sent as integers rather than as 12.0. Values that are not strings, numbers or booleans are refused by TypeScript and dropped at the bridge.

Track opens · SDK overview · Troubleshooting

Foreground notifications

const unsubscribe = Carillon.onReceived(async (notification) => {
  // Read notification.data; return 'suppress' for your own in-app UI.
  return 'show'
})

Carillon.clearNotifications()

A new onReceived call replaces the previous handler. Unsubscribe when the handler is no longer needed. The native SDK shows the notification if JavaScript does not answer within three seconds. A thrown or rejected handler also falls back to showing it. The listener attaches before native observation starts.

The Expo plugin forwards iOS willPresent. In a bare app, forward it explicitly:

func userNotificationCenter(_ center: UNUserNotificationCenter,
  willPresent notification: UNNotification,
  withCompletionHandler completion: @escaping (UNNotificationPresentationOptions) -> Void) {
  CarillonBridge.willPresent(notification, completionHandler: completion)
}

Use override when your AppDelegate superclass implements this method. Keep the notification center delegate installed at launch. Android's foreground renderer uses the native notification permission and channels.

Images on iOS

The Expo plugin creates a CarillonNotificationExtension target and declares it under extra.eas.build.experimental.ios.appExtensions, with bundle identifier <ios.bundleIdentifier>.CarillonNotificationExtension. Set ios.bundleIdentifier in your Expo configuration. EAS needs a provisioning profile for this target; no App Group is required. Run prebuild again, then rebuild the native app. Expo Go cannot load this native extension.

For a bare app, follow the Swift extension setup. When migrating from OneSignal, replace its notification service extension instead of keeping two service extensions.

Device ID

const deviceId = await Carillon.getDeviceId() // null before registration
const stopObserving = Carillon.onDeviceIdChanged((id) => {
  // Update a stored equipment-to-device mapping if needed.
})

The ID survives token rotation when the native installation proof is available. It is a routing identifier, not a login credential. See device identity.

On this page