Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

The Courier React Native SDK provides prebuilt components and APIs for building notification experiences in React Native. It handles authentication, token management, and real-time message delivery across iOS and Android from a single codebase.
  • Inbox — prebuilt notification center with theming and custom rendering
  • Push Notifications — automatic token syncing and delivery tracking for APNS and FCM
  • Preferences — prebuilt UI for users to manage their notification settings
Available on GitHub and npm.
RequirementValue
Min iOS version15.0
Min Android SDK23
Gradle8.4+

Installation

npm install @trycourier/courier-react-native

iOS Setup

1

Set iOS deployment target to 15.0+

Update your Podfile:
platform :ios, '15.0'
2

Install CocoaPods

cd ios && pod install

Android Setup

1

Add the Jitpack repository

In your android/build.gradle:
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://www.jitpack.io' }
    }
}
2

Set minimum SDK version

In your android/build.gradle:
ext {
    minSdkVersion = 23
    compileSdkVersion = 33
    targetSdkVersion = 33
}
3

Extend CourierReactNativeActivity

Update your MainActivity to extend CourierReactNativeActivity. This allows the SDK to manage user state across app sessions.
import com.courierreactnative.CourierReactNativeActivity

class MainActivity : CourierReactNativeActivity() {
    // ...
}

Authentication

All SDK features (Inbox, Push, Preferences) require a signed-in user. Authentication is JWT-based; your backend generates a token and the SDK manages credentials across app sessions.
For a full walkthrough of JWT generation, see the Inbox Authentication guide.
1

Generate a JWT on your backend

Call the Issue Token endpoint from your server:
curl -X POST https://api.courier.com/auth/issue-token \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "user_id:YOUR_USER_ID write:user-tokens inbox:read:messages inbox:write:events read:preferences write:preferences read:brands",
    "expires_in": "2 days"
  }'
2

Sign in the user

Pass the JWT to the SDK where you manage user state. Credentials persist across app sessions. If the token expires, generate a new one from your backend and call signIn again; the SDK does not handle token refresh automatically.
import Courier from "@trycourier/courier-react-native";

await Courier.shared.signIn({
    userId: "your_user_id",
    accessToken: jwt,
});
3

Sign out when done

await Courier.shared.signOut();

EU-hosted workspaces

For EU-hosted Courier workspaces, pass the built-in EU preset through apiUrls:
import Courier, { getCourierApiUrlsForRegion } from "@trycourier/courier-react-native";

await Courier.shared.signIn({
    userId: "your_user_id",
    accessToken: jwt,
    apiUrls: getCourierApiUrlsForRegion("eu")
});

Authentication state

const userId = await Courier.shared.getUserId();
const tenantId = await Courier.shared.getTenantId();
const isSignedIn = await Courier.shared.isUserSignedIn();

const listener = await Courier.shared.addAuthenticationListener({
    onUserChanged: (userId) => {
        console.log("User changed:", userId);
    },
});

await listener.remove();

Inbox

Courier Inbox provides a prebuilt notification center component. It supports theming and real-time updates on both iOS and Android.
Inbox requires the Courier Inbox provider to be enabled in your workspace. If using JWT authentication, enable JWT support in the provider settings.JWT toggle in Courier provider settings
On Android, your app theme must extend Theme.MaterialComponents for the prebuilt UI to render correctly. Set this in your res/values/styles.xml.
For an overview of how Courier Inbox works and how to send messages to it from your backend, see Get Started with Inbox and Send an Inbox Message.

Prebuilt Component

Default Inbox on iOSDefault Inbox on Android
import { CourierInboxView } from "@trycourier/courier-react-native";

<CourierInboxView
  onClickInboxMessageAtIndex={(message, index) => {
    message.read
      ? Courier.shared.unreadMessage({ messageId: message.messageId })
      : Courier.shared.readMessage({ messageId: message.messageId });
  }}
  onClickInboxActionForMessageAtIndex={(action, message, index) => {
    console.log(action);
  }}
  style={{ flex: 1 }}
/>

Theming

Pass a theme object to customize the inbox appearance. The theme supports separate iOS and Android style properties, custom fonts, colors, and button styles.
<CourierInboxView
  lightTheme={{
    iOS: {
      unreadIndicatorStyle: { indicator: "dot", color: "#9747FF" },
      titleStyle: { unread: { font: { family: "Avenir", size: 18 } } },
      // ... additional iOS styles
    },
    android: {
      unreadIndicatorStyle: { indicator: "dot", color: "#9747FF" },
      titleStyle: { unread: { font: { family: "fonts/poppins.otf", size: 18 } } },
      // ... additional Android styles
    },
  }}
/>
Styled Inbox on iOSStyled Inbox on Android
You can also apply branding from Courier Studio. The SDK supports primary color and footer visibility from your brand settings.

Custom Inbox UI

For full control over rendering, use addInboxListener to receive raw message data and build your own UI:
await Courier.shared.setInboxPaginationLimit(100);

const listener = await Courier.shared.addInboxListener({
    onLoading(isRefresh) {
        // Show loading state
    },
    onError(error) {
        // Handle error
    },
    onUnreadCountChanged(unreadCount) {
        // Update badge indicators
    },
    onTotalCountChanged(totalCount, feed) {
        // Track total messages per feed
    },
    onMessagesChanged(messages, canPaginate, feed) {
        // Update your custom UI with messages
    },
    onPageAdded(messages, canPaginate, isFirstPage, feed) {
        // Efficiently append new pages during pagination
    },
    onMessageEvent(message, index, feed, eventName) {
        // React to individual events: added, read, unread, opened, archived, clicked
    }
});

// Clean up
await listener.remove();

Message Actions

Track every event a Courier message can receive:
await Courier.shared.openMessage({ messageId: "..." });
await Courier.shared.clickMessage({ messageId: "..." });
await Courier.shared.readMessage({ messageId: "..." });
await Courier.shared.unreadMessage({ messageId: "..." });
await Courier.shared.archiveMessage({ messageId: "..." });
await Courier.shared.readAllInboxMessages();

Reading the feed

// Adjust how many messages are loaded per page (default: 32)
await Courier.shared.setInboxPaginationLimit(100);

// Drive pagination manually
const newMessages = await Courier.shared.fetchNextPageOfMessages({ inboxMessageFeed: "feed" });

// Pull-to-refresh
await Courier.shared.refreshInbox();

Push Notifications

The SDK simplifies push notification setup with automatic token syncing and delivery tracking for both APNS (iOS) and FCM (Android).
Push notifications require a physical device. Simulators and emulators do not reliably support push token registration or notification delivery.
FeatureiOSAndroid
Automatic token managementYesYes
Notification trackingYesYes
Permission requestsYesYes

Provider Setup

Configure your push provider in the Courier dashboard:
  • iOS: APNS (recommended) or FCM
  • Android: FCM (recommended)
For step-by-step provider credential setup, see the APNS integration guide or FCM integration guide.

iOS Push Setup

1

Enable the Push Notifications capability

In Xcode: select your target > Signing & Capabilities > add Push Notifications.
2

Forward APNS callbacks to Courier

Update your AppDelegate.h so it inherits from CourierReactNativeDelegate. The SDK registers for remote notifications, syncs the APNS token to Courier, and forwards delivery / click events to your JavaScript listeners.
#import <courier-react-native/CourierReactNativeDelegate.h>

@interface AppDelegate : CourierReactNativeDelegate
@end
If you are using Expo, see the Expo section below for the Swift / Objective-C bridge that wires Courier into ExpoAppDelegate.
3

Add a Notification Service Extension (recommended)

Required for tracking delivery when the app is not running. See the iOS SDK push setup for the full steps; the same template applies to React Native.

Android Push Setup

Firebase is now a separate dependency. Starting with Courier React Native 6.x (Android 6.x), the SDK no longer bundles Firebase Messaging as a transitive dependency. Your app must add its own Firebase BoM and firebase-messaging artifact so you can subclass FirebaseMessagingService.
1

Set up Firebase

Register your app in Firebase, download google-services.json, and place it in android/app/. Follow the Firebase Android setup guide for the rest.In android/build.gradle:
buildscript {
    dependencies {
        classpath("com.google.gms:google-services:4.3.14")
    }
}
In android/app/build.gradle:
apply plugin: "com.android.application"
apply plugin: "com.google.gms.google-services"

dependencies {
    implementation platform('com.google.firebase:firebase-bom:33.1.2')
    implementation "com.google.firebase:firebase-messaging"
}
2

Extend CourierReactNativeActivity

Update your MainActivity so the SDK can receive push delivery and click events while the app is in foreground.
import com.courierreactnative.CourierReactNativeActivity

class MainActivity : CourierReactNativeActivity() {
    // ...
}
3

Create a FirebaseMessagingService

Subclass Firebase’s FirebaseMessagingService directly and forward both callbacks to Courier. The SDK caches the FCM token, uploads it to Courier when a user is signed in, and broadcasts delivery events through its event bus.
package your.app.package;

import androidx.annotation.NonNull;
import com.courier.android.Courier;
import com.courier.android.notifications.CourierPushNotificationIntent;
import com.courier.android.notifications.RemoteMessageExtensionsKt;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class YourNotificationService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(@NonNull RemoteMessage message) {
        super.onMessageReceived(message);

        // Tell the Courier SDK that a push was delivered
        Courier.Companion.onMessageReceived(message.getData());

        // Build the PendingIntent that opens MainActivity and carries the original payload
        CourierPushNotificationIntent notificationIntent = new CourierPushNotificationIntent(
            this,
            0,
            MainActivity.class,
            message
        );

        String title = message.getData().get("title");
        if (title == null && message.getNotification() != null) {
            title = message.getNotification().getTitle();
        }

        String body = message.getData().get("body");
        if (body == null && message.getNotification() != null) {
            body = message.getNotification().getBody();
        }

        RemoteMessageExtensionsKt.presentNotification(
            notificationIntent,
            title,
            body,
            android.R.drawable.ic_dialog_info,
            "Notification Service"
        );
    }

    @Override
    public void onNewToken(@NonNull String token) {
        super.onNewToken(token);

        // Register/refresh the FCM token with Courier
        Courier.Companion.onNewToken(token);
    }
}
4

Register the service in AndroidManifest.xml

<service
    android:name=".YourNotificationService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Manual Token Syncing

Use this for any provider Courier doesn’t sync automatically (Expo, OneSignal, Pusher Beams, etc.) or to push tokens you obtain elsewhere:
import { CourierPushProvider } from "@trycourier/courier-react-native";

// By string key
await Courier.shared.setToken({
    key: "your-provider-key",
    token: "your_messaging_token"
});

// By known provider enum
await Courier.shared.setTokenForProvider({
    provider: CourierPushProvider.EXPO,
    token: "your_expo_token"
});

// Read tokens stored locally by the SDK
const tokenForKey = await Courier.shared.getToken({ key: "your-provider-key" });
const tokenForProvider = await Courier.shared.getTokenForProvider({
    provider: CourierPushProvider.EXPO
});
const allTokens = await Courier.shared.getAllTokens();

Handling Push Events

Register a listener to respond when notifications are delivered or tapped. This is useful for deep linking, analytics, or showing in-app alerts.
const pushListener = Courier.shared.addPushNotificationListener({
    onPushNotificationDelivered: (push) => {
        console.log("Delivered:", push);
    },
    onPushNotificationClicked: (push) => {
        console.log("Clicked:", push);
    }
});

pushListener.remove();

Requesting Permission

Prompt the user to allow notifications (iOS shows a system dialog; Android 13+ requires runtime permission). You can also check the current permission status without prompting.
// Set how iOS handles foreground delivery
Courier.setIOSForegroundPresentationOptions({
    options: ["sound", "badge", "list", "banner"]
});

const status = await Courier.requestNotificationPermission();
const current = await Courier.getNotificationPermissionStatus();

Send a Test Notification

Once you’ve completed the setup above, send a test push using the Send API with push as the routing channel. See the APNS sending guide or FCM sending guide for complete examples.

Preferences

Courier Preferences provides a prebuilt component for users to manage which notification topics and channels they subscribe to.
Topics and sections are configured in the Preferences Editor. See Preferences Overview for how preference enforcement works at send time.
Default Preferences on iOSDefault Preferences on Android
import { CourierPreferencesView } from "@trycourier/courier-react-native";

<CourierPreferencesView
  mode={{ type: "topic" }}
  style={{ flex: 1 }}
/>

Preference Modes

  • Topic mode ({ type: "topic" }): shows subscription topics the user can toggle on or off
  • Channels mode ({ type: "channels", channels: ["push", "sms", "email"] }): shows per-channel controls for each topic

Theming

Pass a theme object with platform-specific style properties to customize fonts, colors, and toggle styles.
Styled Preferences on iOSStyled Preferences on Android

Expo

If you are using Expo, additional setup is required for push notification token syncing. You’ll need to update your AppDelegate (iOS) and MainActivity (Android) with Courier-specific code since Expo manages these files differently. See the full Expo setup guide on GitHub for step-by-step instructions for both platforms.

CourierClient

For advanced use cases, CourierClient is a low-level wrapper around the Courier API. Each client holds its own credentials, so you can spin up as many as you need.

Initialization

import { CourierClient, getCourierApiUrlsForRegion } from "@trycourier/courier-react-native";

const client = new CourierClient({
    jwt:          "...",          // Optional. Required for most authenticated calls
    clientKey:    "...",          // Optional. Used only for Inbox client-key auth
    userId:       "your_user_id",
    connectionId: "...",          // Optional. Used for the inbox websocket
    tenantId:     "...",          // Optional. Scopes the client to a tenant
    apiUrls:      getCourierApiUrlsForRegion("eu"), // Optional. Use for EU-hosted workspaces
    showLogs:     true            // Optional. Defaults to your build configuration
});

const options = client.options;

// Tear the client down when you no longer need it
client.remove();

Token Management

const device = {
    appId:        "APP_ID",
    adId:         "AD_ID",
    deviceId:     "DEVICE_ID",
    platform:     "ios",
    manufacturer: "Apple",
    model:        "iPhone 15"
};

await client.tokens.putUserToken({
    token: "...",
    provider: "firebase-fcm",
    device // Optional
});

await client.tokens.deleteUserToken({ token: "..." });

Inbox

const messages = await client.inbox.getMessages({
    paginationLimit: 25,
    startCursor: undefined
});

const archived = await client.inbox.getArchivedMessages({
    paginationLimit: 25,
    startCursor: undefined
});

const unreadCount = await client.inbox.getUnreadMessageCount();

await client.inbox.open({ messageId: "..." });
await client.inbox.read({ messageId: "..." });
await client.inbox.unread({ messageId: "..." });
await client.inbox.archive({ messageId: "..." });
await client.inbox.readAll();

Preferences

const prefs = await client.preferences.getUserPreferences({
    paginationCursor: undefined
});

const topic = await client.preferences.getUserPreferenceTopic({
    topicId: "..."
});

await client.preferences.putUserPreferenceTopic({
    topicId: "...",
    status: CourierUserPreferencesStatus.OptedIn,
    hasCustomRouting: true,
    customRouting: [CourierUserPreferencesChannel.Push]
});

Branding

const brand = await client.brands.getBrand({ brandId: "..." });

URL Tracking

Pass any tracking URL found inside a push notification payload or inbox message:
// Available events: Clicked, Delivered, Opened, Read, Unread
await client.tracking.postTrackingUrl({
    url: "courier_tracking_url",
    event: CourierTrackingEvent.Delivered
});
See the full Courier API reference at courier.com/docs/reference.

Inbox Overview

Learn about Courier Inbox and how to set it up

Push Integrations

Configure APNS, FCM, and other push providers

Preferences

Set up notification preference topics and channels

GitHub

Source code, examples, and changelog