GitHub project

Packages and configuration options

How options take effect

The Expo plugin reads two different kinds of options out of your app.json (or app.config.js) file, and they take effect at different times.

Where you set itWhen Customer.io reads itWhat it changes
Plugin options—android, ios, location, geofence, liveNotificationsWhen you run expo prebuildThe native iOS and Android files the plugin generates
config, inside the plugin optionsWhen you run expo prebuildThe native initialization code, which applies these settings when your app launches
CioConfig, passed to CustomerIO.initialize() in your app codeWhen your app launchesSDK behavior at runtime

Because the plugin compiles your plugin options and config into native code, you need to run expo prebuild again and rebuild your app after you change them. An over-the-air update can’t change them, because it only replaces your JavaScript. Changes to CioConfig apply the next time your app calls CustomerIO.initialize().

You pick one of the two runtime paths:

Auto-initialization (Expo 53+): you add a config object to your plugin options. The plugin generates native initialization code, so the SDK starts on its own and you don’t have to call CustomerIO.initialize().

JavaScript initialization: you leave config out and call CustomerIO.initialize() with a CioConfig object in your app code. Code samples label this path Manual initialization.

Build-time options apply on both paths. Runtime options don’t: the plugin only generates native initialization code when config is present; when you initialize from JavaScript, nothing reads a config object. See Initializing from JavaScript for what changes on that path.

Build-time options

To use the Expo plugin, add a customerio-expo-plugin entry to your app.json or app.config.js file. The plugin reads this entry when you run expo prebuild and uses it to generate your native projects. Before you set up your app:

  • If you’re in our EU region, set the region to eu.
  • To support Customer.io’s latest features, set your iOS deployment target to 15.1 or higher.

If you send notifications to iOS users through Firebase Cloud Messaging, you’ll need to:

  • Set expo-build-properties.ios.useFrameworks to static.
  • Set customerio-expo-plugin.ios.pushNotification.provider to fcm.
  • Set customerio-expo-plugin.ios.pushNotification.googleServicesFile to the location of your GoogleService-Info.plist file. If you use @react-native-firebase with the Customer.io SDK, you should not set this value. Learn more
JSON
{
  "plugins": [
    [
      "expo-build-properties",
      {
        "ios": {
          "deploymentTarget": "15.1", // set your iOS deployment target to support Customer.io
          "useFrameworks": "static" // set if you use FCM to send push notifications to iOS devices
        }
      }
    ],
    [
      "customerio-expo-plugin",
      {
        "config": {
          "cdpApiKey": "<cdpApiKey>",
          "siteId": "<siteId>",
          "region": "us"
        },
        "android": {
          "googleServicesFile": "./files/google-services.json"
        },
        "ios": {
          "useFrameworks": "static", // must match value in expo-build-properties if set
          "appleTeamId": "YOUR_TEAM_ID", // optional: for Notification Service Extension code signing
          "pushNotification": {
            "provider": "fcm", // use "apn" for Apple Push Notification service
            "googleServicesFile": "<Path to GoogleService-Info.plist file>", // required if provider is "fcm" and you don't use the @react-native-firebase SDK
            "useRichPush": true,
            "appGroupId": "group.com.example.myapp.cio"
          }
        }
      }
    ]
  ]
}
JSON
{
  "plugins": [
    [
      "expo-build-properties",
      {
        "ios": {
          "deploymentTarget": "15.1", // set your iOS deployment target to support Customer.io
          "useFrameworks": "static" // set if you use FCM to send push notifications to iOS devices
        }
      }
    ],
    [
      "customerio-expo-plugin",
      {
        "android": {
          "googleServicesFile": "./files/google-services.json"
        },
        "ios": {
          "useFrameworks": "static", // must match value in expo-build-properties if set
          "appleTeamId": "YOUR_TEAM_ID", // optional: for Notification Service Extension code signing
          "pushNotification": {
            "provider": "fcm", // use "apn" for Apple Push Notification service
            "googleServicesFile": "<Path to GoogleService-Info.plist file>", // required if provider is "fcm" and you don't use the @react-native-firebase SDK
            "useRichPush": true,
            "appGroupId": "group.com.example.myapp.cio",
            "env": {
              "cdpApiKey": "<cdpApiKey>",
              "region": "us"
            }
          }
        }
      }
    ]
  ]
}

Android options

These options control the Android project the plugin generates.

OptionTypeDefaultDescription
androidobjectRequired if you want to setup Android even if it is empty. Eg (“android”: {}).
android.googleServicesFilestringSet the path to your google-services.json file.
android.setHighPriorityPushHandlerbooleanThis is optional, if you choose to use a 3rd party plugin to handle notification permissions, but want our SDK to handle the notifications.
android.pushNotification.channel.idstring[your package name](Optional) Android messaging notification channel ID
android.pushNotification.channel.namestring[your app name] Notifications(Optional) Android messaging notification channel name
android.pushNotification.channel.importanceinteger3(Optional) The importance of the channel. Acceptable values are 0 (min), 1 (low), 2 (medium), 3 (default/high), and 4 (urgent). See the Android developer documentation for more about the behavior of each importance level
android.pushNotification.iconstring(Optional, requires 3.8.0 or later) The small icon shown in the status bar for push notifications. Without it, Android falls back to your app icon rendered as a grey square. Set either a path to a local image relative to your project root (./assets/notification-icon.png) or a reference to a drawable your app already defines (@drawable/ic_stat_notification). See setting the notification icon for details.
android.pushNotification.colorstring(Optional, requires 3.8.0 or later) The accent color applied to the notification icon. Set a #RRGGBB or #AARRGGBB hex color, or a reference to a color your app already defines (@color/notification_accent).

iOS options

These options control the Xcode project the plugin generates.

OptionTypeDefaultDescription
iosobjectRequired: The parent object for iOS settings, including your initialization keys.
ios.useFrameworksstring(Optional) Allows the plugin to work with static libraries. Options are static and dynamic
ios.appleTeamIdstring(Optional) Your Apple Developer Team ID. Used to set the development team for code signing the Notification Service Extension when useRichPush is true. Find your Team ID in your Apple Developer account under Membership Details.
ios.pushNotificationobjectRequired Configurations for push notifications for iOS. See iOS push notification options.

iOS push notification options

Everything under ios.pushNotification shapes the push handling the plugin writes into your Xcode project, including the Notification Service Extension that renders rich push notifications.

OptionTypeDefaultDescription
ios.pushNotification.envobjectRequired when you initialize from JavaScript Contains your API key (pushNotification.env.cdpApiKey) and region (pushNotification.env.region with one of eu or us) information. The Notification Service Extension needs these values at build time. You can omit this object when you use auto-initialization, because the plugin fills it in from config. If you set both, the values must match, or the prebuild fails.
ios.pushNotification.env.cdpApiKeystringRequired: the key to use for authentication
ios.pushNotification.env.regionus or euusThe region your Customer.io account is in. If you use the wrong region, your mobile traffic won’t make it into Customer.io.
ios.pushNotification.providerstringapnUse apn for Apple Push Notification service or fcm for Firebase Cloud Messaging.
ios.pushNotification.googleServicesFilestringRequired if ios.pushNotification.provider is fcm. Set the path to your GoogleService-Info.plist file. Do not set this value if you use the @react-native-firebase SDK. Learn more
ios.pushNotification.useRichPushbooleanfalseEnables rich push features for iOS (images and links). When enabled, the plugin creates a Notification Service Extension in your Xcode project. If automatic code signing doesn’t resolve your development team, set ios.appleTeamId to your Apple Developer Team ID.
ios.pushNotification.autoFetchDeviceTokenbooleantrueWhen true, the SDK automatically gets the device token. If you get tokens through another provider and register them with the SDK using the CustomerIO.registerDeviceToken method, you should set this to false. Learn more
ios.pushNotification.autoTrackPushEventsbooleantrueWhen true, the SDK automatically tracks push delivery and open metrics. Set it to false to report those metrics yourself.
ios.pushNotification.showPushAppInForegroundbooleantrueSet to true if you want push notifications sent by Customer.io to be shown when your app is in the foreground.
ios.pushNotification.disableNotificationRegistrationbooleanfalse(Optional) Removes the registerPushNotification handler and allows you to control notification permission requests. We recommend that you set this to true if you have customerio-reactnative version >= 2.2.0 installed.
ios.pushNotification.handleDeeplinkInKilledStatebooleanfalseLegacy AppDelegate workaround for Expo SDK 53–57. Set to true to let the Customer.io SDK handle deep links when your app is in a killed/closed state. On Expo SDK 58+ (scene lifecycle), this option is not applied because scene routing replaces it. Expo SDK 58 is currently pre-release. Follow the scene path’s deep-link readiness steps instead.
ios.pushNotification.appGroupIdstring(Optional) Your App Group identifier for reliable push delivery tracking. Must start with group.. When set, the plugin automatically configures App Group entitlements and passes the identifier to the SDK. Requires useRichPush: true.

Native module options

Location, geofencing, and Live Notifications each need native dependencies that the plugin adds during prebuild. These options sit at the top level of your plugin config rather than inside config, because they describe what the plugin builds. That’s what makes them work whether you auto-initialize or initialize from JavaScript.

OptionTypeDefaultDescription
locationobjectContainer for location tracking plugin settings.
location.enabledbooleanfalseWhen true, the plugin adds the native location dependencies (iOS Podfile subspec and Android Gradle properties) during prebuild. Your app must add its own location permissions and privacy usage descriptions.
geofenceobjectContainer for geofencing plugin settings. Enables the Location module automatically.
geofence.enabledbooleanfalseWhen true, the plugin adds the native geofence dependencies on iOS and Android during prebuild.
liveNotificationsobjectContainer for the Live Notifications build-time setup: the enabled switch, the branding compiled into the iOS widget, and the source files for a custom template. See Set up Live Notifications for the full option list.

Runtime configuration

Runtime options set SDK behavior—logging, automatic tracking, in-app messaging—when your app launches. Where you set them depends on how the SDK initializes.

Auto-initialization options

Add a config object to your plugin options and the plugin generates native initialization code for both platforms, so the SDK starts without a CustomerIO.initialize() call in your app. The plugin only writes that code when config is present, so these options do nothing in an app that initializes from JavaScript.

JSON
[
  "customerio-expo-plugin",
  {
    "config": {
      "cdpApiKey": "<cdpApiKey>",
      "siteId": "<siteId>",
      "region": "us",
      "logLevel": "error",
      "screenViewUse": "all",
      "location": {
        "trackingMode": "ON_APP_START"
      }
    },
    "android": {},
    "ios": {
      "pushNotification": {
        "provider": "apn"
      }
    },
    "location": {
      "enabled": true
    }
  }
]
OptionTypeDefaultDescription
configobjectContainer for auto-initialization settings. If present, enables auto-initialization.
config.cdpApiKeystringRequired: Your CDP API key
config.siteIdstringOptional: Your site ID for in-app messaging. Required to enable in-app messaging.
config.regionstringUSWorkspace region: “US” or “EU”
config.logLevelstringdebugLog level: “none”, “error”, “info”, or “debug”
config.autoTrackDeviceAttributesbooleantrueAutomatically track device attributes
config.trackApplicationLifecycleEventsbooleantrueTrack app lifecycle events
config.screenViewUsestringallScreen view tracking: “all” (server + in-app) or “inapp” (in-app only)
config.migrationSiteIdstringPreviously used site id, required if migrating from earlier versions (1.X)
config.locationobjectEnable location tracking. Takes a trackingMode option: MANUAL (default), ON_APP_START, or OFF. The plugin applies it when you set location.enabled or geofence.enabled to true.
config.geofenceobjectOptional runtime settings for geofencing. Takes a locationMode option: AUTOMATIC (default) or MANUAL. The plugin applies it only when geofence.enabled is true.
config.liveNotificationsobjectRuntime settings for Live Notifications. Its presence enables the feature, so you don’t also need liveNotifications.enabled.

Initializing from JavaScript

If you call CustomerIO.initialize() yourself, leave config out of your plugin options and set your runtime values in a CioConfig object instead. The manual initialization example shows the plugin options for this path. Three things work differently on this path:

  • Build-time options still apply. The plugin reads android, ios, location, geofence, and liveNotifications at prebuild either way.
  • ios.pushNotification.env becomes required for rich push. The Notification Service Extension needs your API key and region compiled in, and with no config object there’s nothing for the plugin to copy them from.
  • Set Live Notification branding in both places. Put liveNotifications.branding in your plugin options and pass branding to CustomerIO.initialize(). The plugin compiles the value from your plugin options into the iOS widget, and the value you pass at runtime is what Android applies. The plugin generates no native initialization code on this path, so it can’t forward the value for you. You also need to set liveNotifications.enabled to true explicitly, because there’s no config.liveNotifications object to turn the feature on.

SDK packages

The SDK consists of a few packages. You must use the CioConfig and CustomerIO packages to configure and initialize the SDK in your React Native app.

Package ProductRequired?Description
CustomerIOYesThe main SDK package. Used to initialize the SDK and call the SDK’s methods.
CioConfigYesConfigure the SDK including in-app messaging support.
CioRegionNoUsed inside the CioConfig.region option to declare your region—EU or US.
CioLogLevelNoUsed inside the CioConfig.logLevel option to set the level of logs you can view from the SDK.
CioLocationTrackingModeNoUsed inside CioConfig.location to set the tracking mode. See location tracking for details.

CioConfig options

You determine global behaviors for the SDK using the CioConfig package. You must provide configuration options before you initialize the SDK; you cannot declare configuration changes after you initialize the SDK.

Import CioConfig and then set configuration options to configure things like your logging level and whether or not you want to automatically track device attributes. The logLevel option requires the CioLogLevel package and the region option requires the CioRegion package.

JAVASCRIPT
import {
  CioLogLevel,
  CioRegion,
  CustomerIO,
  CioConfig,
  PushClickBehaviorAndroid,
} from 'customerio-reactnative';

const App = () => {

useEffect(() => {
   const config: CioConfig = {
      cdpApiKey: 'CDP API Key', // Mandatory
      migrationSiteId: 'siteId', // Required if migrating from an earlier version
      region: CioRegion.US,
      logLevel: CioLogLevel.Debug,
      trackApplicationLifecycleEvents: true,
      inApp: {
         siteId: 'site_id',
      },
      push: {
         android: {
            pushClickBehavior: PushClickBehaviorAndroid.ActivityPreventRestart
         }
      }
   };
   CustomerIO.initialize(config)
   }, [])
}
OptionTypeDefaultDescription
cdpApiKeystringRequired: the key you’ll use to initialize the SDK and send data to Customer.io
regionCioRegion.EU or CioRegion.USCioRegion.USRequires the CioRegion package. You must set the region your account is in the EU (CioRegion.EU).
apiHoststringThe domain you’ll proxy requests through. You’ll only need to set this (and cdnHost) if you’re proxying requests.
autoTrackDeviceAttributesbooleantrueAutomatically gathers information about devices, like operating system, device locale, model, app version, etc
cdnHoststringThe domain you’ll fetch configuration settings from. You’ll only need to set this (and apiHost) if you’re proxying requests.
logLevelstringerrorRequires the CioLogLevel package. Sets the level of logs you can view from the SDK. Set to debug or info to see more logging output.
migrationSiteIdstringRequired if you’re updating from 3.x: the credential for previous versions of the SDK. This key lets the SDK send remaining tasks to Customer.io when your audience updates your app.
screenViewUseAll or InAppAllScreenView.All (Default): Screen events are sent to Customer.io. You can use these events to build segments, trigger automations, and target in-app messages.

ScreenView.InApp: Screen view events not sent to Customer.io. You’ll only use them to target in-app messages based on page rules.
trackApplicationLifecycleEventsbooleantrueSet to false if you don’t want the app to send lifecycle events
inAppobjectRequired for in-app support. This object takes a siteId property, determining the workspace your in-app messages come from.
pushobjectTakes a single option called PushClickBehaviorAndroid. This object and option controls how your app behaves when your Android audience taps push notifications.
locationobjectEnable location tracking. Takes a trackingMode option from the CioLocationTrackingMode package.

Proxying requests

By default, requests go through our domain at cdp.customer.io. You can proxy requests through your own domain to provide a better privacy and security story, especially when submitting your app to app stores.

To proxy requests, you’ll need to set the apiHost and cdnHost properties in your SDKConfigBuilder. While these are separate settings, you should set them to the same URL.

While you need to initialize the SDK with a cdpApiKey, you can set this to any value you want. You only need to pass your actual key when you send requests from your server backend to Customer.io. If you want to secure requests to your proxy server, you can set the cdpApiKey to a value representing basic authentication credentials that you handle on your own. See proxying requests for more information.

JAVASCRIPT
import { CioConfig, CustomerIO, CioRegion } from "customerio-reactnative";

useEffect(() => {
  const config: CioConfig = {
    cdpApiKey: process.env.EXPO_PUBLIC_CDP_API_KEY,
    region: CioRegion.US,
    apiHost: "proxy.example.com",
    cdnHost: "proxy.example.com", 
    inApp: {
      siteId: process.env.EXPO_PUBLIC_SITE_ID,
    }
  };
  CustomerIO.initialize(config);
}, []);
Updated September 30, 2026