Skip to main content
The Sendrealm React Native SDK works in Expo when your app can include custom native code. That means Expo prebuild, expo run, or EAS development builds. Expo Go is not supported because Expo Go cannot load custom native modules that are not already built into the Expo Go app. Use this guide for Expo projects. If your React Native app already owns native android and ios projects without Expo prebuild, use React Native Bare SDK.

What The Expo Plugin Does

The Sendrealm Expo plugin updates native project configuration during prebuild. It can:
  • Copy google-services.json into the Android app during prebuild.
  • Set default Android notification icon and color metadata.
  • Configure iOS APNs environment.
  • Add iOS background remote notification mode.
  • Add an iOS Notification Service Extension for rich image notifications.
  • Point the iOS project at a local native Sendrealm pod during SDK development.
The plugin runs when Expo generates or updates native projects. If you change plugin options, run prebuild again.

Setup Order

Follow this order:
  1. Upload Firebase and APNs credentials in Sendrealm.
  2. Install @sendrealm/react-native.
  3. Add the Expo plugin to app.json or app.config.js.
  4. Add Android google-services.json and configure iOS push capabilities.
  5. Run Expo prebuild or create an EAS development build.
  6. Initialize Sendrealm from JavaScript.
  7. Request notification permission after your app explains the value.
  8. Link the device with login after user sign-in.
  9. Send test pushes on Android and iOS.

Requirements

  • Expo project using development builds or prebuild
  • Android device or emulator with Google Play services
  • Physical iOS device for APNs testing
  • A Sendrealm app ID from the dashboard
  • Firebase credentials uploaded for Android delivery
  • APNs credentials uploaded for iOS delivery
  • Push Notifications enabled for the iOS Bundle ID in Apple Developer

Install

npx expo install @sendrealm/react-native
This installs the JavaScript package and native module. The app still needs a native rebuild because push notifications require native Android and iOS code.

Configure The Plugin

Add the Sendrealm plugin to app.json or app.config.js:
{
  "expo": {
    "plugins": [
      [
        "@sendrealm/react-native",
        {
          "android": {
            "googleServicesFile": "./google-services.json",
            "notificationIcon": "ic_stat_sendrealm",
            "notificationColor": "#111827"
          },
          "ios": {
            "apnsEnvironment": "sandbox",
            "enableBackgroundRemoteNotifications": true,
            "notificationServiceExtension": true
          }
        }
      ]
    ],
    "extra": {
      "sendrealmAppId": "YOUR_SENDREALM_APP_ID"
    }
  }
}
The extra values are available to your JavaScript app through Expo config. Do not put Sendrealm API keys or provider private keys in extra. The Sendrealm app ID is safe client configuration; Firebase service account JSON and APNs .p8 keys are server/provider credentials and belong in the Sendrealm dashboard.

Generate google-services.json For Expo Android

Expo Android builds still need Firebase Android app configuration. Generate google-services.json from Firebase:
  1. Open the Firebase console.
  2. Select the Firebase project for your Android app.
  3. If you only have a Google Cloud project, add Firebase to that existing Google Cloud project from the Firebase console first.
  4. From the Firebase project overview, click the Android icon or Add app.
  5. Enter the Android package name from your Expo config. This is usually expo.android.package, for example com.example.app.
  6. Click Register app.
  7. Click Download google-services.json.
  8. Save it in your Expo project, commonly at:
google-services.json
Then point the Sendrealm plugin at that file:
{
  "expo": {
    "plugins": [
      [
        "@sendrealm/react-native",
        {
          "android": {
            "googleServicesFile": "./google-services.json"
          }
        }
      ]
    ]
  }
}
During prebuild, the plugin copies it to:
android/app/google-services.json
Make sure the Firebase Android package name matches the package Expo builds. If you use different package names for development, staging, and production, register each package name in Firebase and use the matching google-services.json for that build profile.

Plugin Options Explained

OptionWhat it does
android.googleServicesFilePath to your Firebase google-services.json; copied to android/app/google-services.json during prebuild.
android.notificationIconSets the default Android drawable resource name for notifications.
android.notificationColorSets the default Android notification accent color.
ios.apnsEnvironmentSelects sandbox for development builds or production for production-signed builds.
ios.enableBackgroundRemoteNotificationsAdds iOS remote-notification background mode for silent/background pushes.
ios.notificationServiceExtensionCreates a Sendrealm Notification Service Extension for rich image notifications.
ios.sendrealmIOSPodPathPoints iOS at a local native Sendrealm pod for SDK repository development.

iOS Capabilities With Expo

Expo does not remove the Apple push requirements. Your Expo app still builds into a native iOS app with a Bundle ID, App ID, entitlements, and provisioning profile. In Apple Developer:
  1. Open Certificates, Identifiers & Profiles.
  2. Open Identifiers.
  3. Select the App ID for the Bundle ID in your Expo config, usually expo.ios.bundleIdentifier.
  4. Enable Push Notifications.
  5. Save the App ID changes.
Apple requires an Account Holder or Admin role to manage App ID capabilities. If you use EAS credentials or automatic signing, make sure the provisioning profile is refreshed after enabling Push Notifications. In Expo config:
  • Set ios.apnsEnvironment to sandbox for development builds or production for TestFlight and App Store builds.
  • Set ios.enableBackgroundRemoteNotifications to true only if you send silent/background pushes.
  • Set ios.notificationServiceExtension to true if you send rich image notifications.
Then rerun prebuild or create a new EAS build. Capability and entitlement changes only matter after the native app is regenerated and rebuilt.
npx expo prebuild --platform ios
If you commit the generated native ios project, open ios/*.xcworkspace in Xcode and verify the main app target has Push Notifications under Signing & Capabilities. If you use silent pushes, also verify Background Modes includes Remote notifications. If you use rich images, verify the Notification Service Extension target exists.

iOS APNs Key For Sendrealm

Sendrealm sends iOS pushes through APNs, so the Sendrealm dashboard needs an APNs private key even when your app is built with Expo. Create the key in Apple Developer:
  1. Open Certificates, Identifiers & Profiles.
  2. Open Keys.
  3. Create a new key with a clear name, for example Sendrealm Push.
  4. Select Apple Push Notification service.
  5. Configure the APNs key scope if Apple asks for one.
  6. Confirm and download the .p8 file immediately.
The Apple Developer user creating the key must be an Account Holder or Admin. The key must have Apple Push Notification service selected. If you choose a Topic Specific key, include the exact Bundle ID from expo.ios.bundleIdentifier. A key for another Apple service cannot send push notifications. Upload the .p8 file, Key ID, Team ID, Bundle ID, and APNs environment in Sendrealm. Expo/EAS signing credentials and Sendrealm APNs provider credentials are related to the same app, but they are not the same thing: EAS signs the app, while Sendrealm uses the APNs key to send notifications. See Mobile Push Credentials for the full APNs key walkthrough.

Prebuild And Run Locally

Generate native projects and run locally:
npx expo prebuild --platform android
npx expo run:android

npx expo prebuild --platform ios
npx expo run:ios --device
Use --device for iOS push testing because APNs testing should happen on a physical device.

Build With EAS

Build development clients with EAS:
npx eas build --profile development --platform android
npx eas build --profile development --platform ios
Use an EAS development build when your team wants Expo-style development while still including custom native modules.

Initialize

Read values from Expo config and initialize once:
import Constants from "expo-constants";
import { useEffect } from "react";
import Sendrealm from "@sendrealm/react-native";

export default function App() {
  useEffect(() => {
    const extra = Constants.expoConfig?.extra ?? {};

    void Sendrealm.initialize({
      appId: extra.sendrealmAppId,
      autoRequestPermission: false,
      apnsEnvironment: "sandbox",
    });
  }, []);

  return null;
}
Set apnsEnvironment to production for TestFlight and App Store builds. A common pattern is to read this from build-time config so development builds use sandbox and production builds use production.

Ask For Permission

Request notification permission after your app explains the value:
await Sendrealm.requestPermission();
Check status:
const status = await Sendrealm.getPermissionStatus();
const allowed = await Sendrealm.hasNotificationPermission();
On Android 13 and newer, this shows the Android notification permission prompt. On iOS, this shows the APNs alert, badge, and sound authorization prompt.

Identity, Tags, And Events

Link the device after login:
await Sendrealm.login("user-123", "user@example.com");
Add app-observed tags:
await Sendrealm.addTags({
  plan: "pro",
  onboardingComplete: true,
});
Track custom events:
await Sendrealm.trackEvent("app_opened");
await Sendrealm.trackEvent("checkout_started", {
  product_id: "sku_123",
  price: 29,
});
Call login before setting user tags. Use events for behavior that should drive segmentation, analytics, or automations.

Rich iOS Media

Rich image notifications require a Notification Service Extension. Enable it in the plugin:
{
  "ios": {
    "apnsEnvironment": "sandbox",
    "enableBackgroundRemoteNotifications": true,
    "notificationServiceExtension": true
  }
}
Then run:
npx expo prebuild --platform ios
The plugin creates a Sendrealm notification service extension target that can download and attach remote media before iOS displays the notification.

Android Notification Icons

Android status bar icons should be simple drawable resources, usually monochrome. If you set:
{
  "android": {
    "notificationIcon": "ic_stat_sendrealm"
  }
}
Then the native Android project must contain a matching drawable resource such as res/drawable/ic_stat_sendrealm.xml. If the icon is missing, Android may fall back to the app icon or a default icon.

Delivery Timing And OS Behavior

Expo development builds use the same native delivery rules as any other Android or iOS app. Sendrealm can register the device and send the notification, but the device OS decides when and how the notification is delivered or displayed. Notifications may not be instant when:
  • Android is in Doze or App Standby.
  • The Android message is normal priority.
  • Android battery optimization or OEM background rules restrict the app.
  • iOS treats the payload as a background update.
  • APNs or iOS throttles low-priority/background delivery.
  • The device is offline or has poor network connectivity.
  • The user disabled notifications or a notification channel.
  • Focus mode or notification summary defers iOS alerts.
Use high priority only for urgent, user-visible Android notifications. Do not rely on silent/background pushes as the only path for critical app behavior. When the user opens the app, fetch current state from your backend so the app recovers gracefully if a push was delayed or skipped.

Diagnostics

Use support diagnostics when testing development builds:
const diagnostics = await Sendrealm.getSupportDiagnostics();
console.log(JSON.stringify(diagnostics, null, 2));
Confirm the output shows:
  • Expected API URL
  • Device ID
  • Token presence
  • Permission status
  • Subscribed state
  • SDK version
  • Empty or shrinking queue counts
  • No unexpected last SDK error

Testing Checklist

Before releasing:
  • The app is a development build or production build, not Expo Go.
  • Android test device has Google Play services.
  • iOS test device is physical.
  • Plugin options are committed and prebuild has been rerun.
  • Firebase package name matches the Android app.
  • iOS App ID has Push Notifications enabled in Apple Developer.
  • iOS native target has Push Notifications enabled after prebuild.
  • APNs Bundle ID, Team ID, Key ID, .p8, and environment match the iOS build.
  • initialize resolves successfully.
  • requestPermission returns the expected permission state.
  • A foreground push arrives.
  • A background push arrives.
  • Non-urgent pushes still make sense if delivery is delayed.
  • Time-sensitive pushes use visible notification payloads.
  • Notification tap opens the expected screen or URL.
  • Rich media works if notificationServiceExtension is enabled.

Troubleshooting

SymptomWhat to check
Expo Go does not workBuild a development client because custom native code is required.
Android token is missingUse a Google Play device or emulator and verify the Firebase Android package name.
iOS push does not arriveUse a physical device and verify APNs environment, Bundle ID, Team ID, Key ID, and .p8 key in Sendrealm.
iOS entitlement is missingEnable Push Notifications on the Apple Developer App ID, rerun prebuild, and rebuild the app.
Silent pushes do not wake the app reliablySet ios.enableBackgroundRemoteNotifications to true, rebuild, and treat silent delivery as best effort.
Notifications are delayedCheck Android power management, FCM priority, iOS APNs priority, Focus settings, and notification permissions.
Some pushes are missingCheck stale tokens, disabled channels, background-only payloads, excessive pending messages, and provider diagnostics.
Rich images do not attachConfirm notificationServiceExtension is enabled and prebuild has been rerun.
Plugin changes do not appearRerun expo prebuild. If generated native files are stale, regenerate them intentionally.
Tags return ContactNotLinkedCall login(userId, email) before tags.