Prerequisites
- and an
- Provider credentials: a Firebase service account JSON for Android, an APNs
.p8key for iOS, or both - A physical device, since simulators and emulators do not reliably receive push
Set up your app
Pick your platform. Each tab is the complete path, from an empty project to a device that receives push.- iOS
- Android
- Flutter
- React Native
1
Connect APNs in Courier
Open , switch to the environment you send from, and choose Apple Push Notification Service. Providers are per environment, so one connected in test does not exist in production.Fill in four fields, then click Install Provider:
- Key Id, the identifier of your APNs key
- Key, the contents of the downloaded
.p8file - Team Id, your Apple Developer team identifier
- Topic (App Bundle Id), the bundle ID of the app you send to
2
Install the SDK
In Xcode, go to File > Add Packages, paste the repository URL, pick a version, and add it to your target.With CocoaPods instead, add the pod and run
pod install from your ios/ directory. The SDK needs iOS 15.0 or later.3
Enable push in Xcode
Select your target, open Signing & Capabilities, and add Push Notifications.For silent push, add Background Modes as well and check Remote notifications.Optionally add a to track delivery while the app is closed. It is three steps in Xcode, and the iOS SDK reference walks them.
4
Sync the device token
Extend
CourierDelegate in your AppDelegate. The SDK registers the APNs token, refreshes it, and forwards delivery and click events.5
Sign in the user
Courier ties every token to a signed-in user, so no push reaches the device until you call Call it once, right after your own login resolves. Credentials persist on the device, so app launches do not need it. Call
signIn. Pass the user_id you send to, plus a JWT your backend mints (see ).The
Use whatever your app already calls this user, such as a database id or your auth provider’s
user_id is yours, not Courier’s.Use whatever your app already calls this user, such as a database id or your auth provider’s
sub. Nothing has to exist in Courier first, since signing in registers the user and their device tokens. With no auth yet, any stable string works, as long as you reuse it on every launch and send to that same id.signOut on logout to delete that device’s tokens from Courier.6
Request notification permission
iOS shows the system dialog once. If the user denies it, they re-enable it in device Settings.Reading the status, and getting the user back after they deny: .
user_id you signed in.The SDK holds a token it receives before anyone signs in and uploads it at sign-in, so you never race the callback. Signing in a different user signs the previous one out first.
Send a test push
First with a Push channel and publish it. Then send it to theuser_id you signed in, routing to the push channel. Courier resolves the user’s tokens and delivers through each connected provider.
Verify
The notification appears on the device you registered. For a silent payload, confirm your app handled it in the background instead. Open the message in . A delivered push shows the provider it went through and the token it targeted. If it did not deliver, the log names the reason: no token, expired token, or provider not configured.channels: ["push"] picks a single push provider in failover order and stops at the first success. To reach both iOS and Android on one send, set the push channel’s routing_method to all and put both providers on that channel. See .Delivery and click tracking
Courier tracks push delivery and clicks for you. Every push carries atrackingUrl, and the SDK posts back to it as the notification arrives and again when the user taps it. Both events land in with no code of your own.
The wiring from Set up your app is what reports them:
Two provider defaults keep that accurate, and a new workspace has both on. Attach Mutable Content on is what lets the extension run at all. Apply Recommended Courier Mobile SDK Formatting on ships the push as
data, so Android wakes for it. shows both payloads.
If you handle notifications outside the Courier hooks, post delivery and click events yourself with
client.tracking.postTrackingUrl. Each SDK page carries the call: , , , and .