How-To Send Mobile & Web Push Notifications using Python

Send mobile, web, and multichannel push with Python and Courier. Sync device tokens via the mobile SDKs and send to a user with one API call.

Updated Jul 6, 2026

Push notifications let you reach users with timely, relevant messages even when they are not in your app. This guide shows how push works and how to send mobile, web, and multichannel push notifications from a Python backend using Courier.

Rather than integrating each push provider by hand and managing device tokens yourself, you'll send to a user through one API and let Courier render the content, route to the right provider, and record delivery.

What Are Push Notifications

A push notification is a message sent from a remote server to an app or browser on a phone, computer, or other device. The user does not need the app open to receive it: on mobile it appears on the lock screen or in the notification center, and in a browser it appears as a banner through a service worker.

Users must opt in before you can send push, so permission handling is part of every implementation. Once a user opts in, push works well for transactional alerts (an order shipped, a new-device login), event-driven reminders (a reservation is coming up), and product updates. The strongest strategies are multichannel: the same event can reach a user by push, email, SMS, or in-app inbox, and their preferences decide which.

Sending Mobile Push Notifications with Python

Mobile push is delivered to the device operating system by a push provider: Firebase Cloud Messaging (FCM) for Android (and iOS via APNs), and the Apple Push Notification service (APNs) for iOS.

The flow: your app registers with the OS and receives a device token, that token is stored against a user, and your Python backend sends a notification to that user. Courier renders the content and hands it to the provider, which delivers to the device.

Token lifecycle (rotation, reinstalls, stale tokens) is the part teams underestimate. Courier's mobile SDKs handle it by syncing each device token to the signed-in user, which is what lets your Python backend send to a user_id instead of tracking raw tokens.

Sending Web Push Notifications with Python

For browser (web) push, Courier delivers through OneSignal, which is purpose-built for web push and covers Chrome, Firefox, Edge, and Safari. Courier orchestrates it the same way as mobile: you send to a user, and Courier routes the web channel to OneSignal.

Set up the OneSignal integration in Courier (App ID + REST API Key). On your site, use the OneSignal Web SDK to subscribe the browser and set OneSignal's External ID to your app's user_id. Store that on the Courier user profile as oneSignalExternalUserId (or the Player ID as oneSignalPlayerID) so Courier can target it. Your backend then sends to the user and routes the onesignal channel:

client.send.message(
message={
"to": {"user_id": "user_123"},
"content": {"title": "New reply", "body": "You have a new message."},
"routing": {"method": "all", "channels": ["onesignal"]},
}
)

If instead you want an in-app notification feed inside your web app (rather than browser push), Courier's Inbox renders one from the same send.

Sending Multichannel Push Notifications with Python and Courier

Now let's send push to a user across their devices with a single Python call, using FCM and APNs through Courier.

Prerequisites:

  1. A Courier account.
  2. Python 3.9 or newer.
  3. At least one push provider configured in Courier: Firebase FCM and/or Apple Push Notification (APNs). Courier also supports Expo.

Step 1: Add a Push Integration

Open the Courier Integrations page and configure a push provider: Firebase FCM for Android and web, Apple Push Notification (APNs) for iOS. Courier routes to whichever providers you enable.

Step 2: Design a Notification Template

Create a template in Design Studio: add a Push channel, write your content (use variables like {{name}} for personalization), and publish. Note the template ID. You can also send inline content without a template, shown below.

Step 3: Sync Device Tokens from Your App

Courier needs each user's device tokens to deliver push. Your client app collects them with a Courier mobile SDK, which syncs the token to the signed-in user_id automatically. Use the React Native, iOS, or Android SDK. Each signs the user in with a JWT your backend mints and keeps FCM and APNs tokens current for that user. See Users and Profiles for how tokens attach to a user.

Step 4: Install the Courier SDK

pip install trycourier

The package installs as trycourier, and you import it as courier.

Step 5: Send the Notification

Create a file (for example send_push.py) and add the code below. It creates a client with your Courier API key and sends a push to a user across their FCM and APNs devices:

import os
from courier import Courier
client = Courier(api_key=os.environ["COURIER_API_KEY"])
response = client.send.message(
message={
"to": {"user_id": "user_123"},
"content": {
"title": "Your order shipped",
"body": "Track it anytime in the app.",
},
"routing": {"method": "all", "channels": ["firebase-fcm", "apn"]},
"providers": {
"firebase-fcm": {
"override": {"body": {"data": {"click_action": "https://example.com/orders"}}}
},
"apn": {
"override": {"body": {"aps": {"sound": "default", "badge": 1}}}
},
},
}
)
print(f"Sent with request ID: {response.request_id}")

A few things to note:

  • You send to "to": {"user_id": "user_123"}, and Courier delivers to every device token synced for that user.
  • routing.channels lists provider keys (firebase-fcm, apn, and expo if you use it), not a generic "push". method: "all" sends every listed channel; "single" tries them in order for failover.
  • To send a template instead of inline content, replace content with "template": "YOUR_TEMPLATE_ID" and add a data object for your variables. Provider override fields like sounds and badges are not compatible with a template on the same send.

Step 6: Send and Check the Logs

Run it with your API key (available under Settings in the Courier dashboard):

COURIER_API_KEY=<your-api-key> python send_push.py

You'll get back a request_id. Open Message Logs to see the per-recipient delivery timeline, which providers were attempted, and the rendered content.

Frequently Asked Questions

What package do I install for Courier in Python? Run pip install trycourier. The distribution is named trycourier, and you import it as from courier import Courier.

How do device tokens get to Courier? Your client app collects them with a Courier mobile SDK (React Native, iOS, or Android), which syncs each token to the signed-in user_id. Your Python backend then sends to that user and never handles raw tokens.

Can one send reach a user on both iOS and Android? Yes. Send to a user_id with routing.channels: ["firebase-fcm", "apn"] and method: "all", and Courier delivers to every synced device.

Do I need Firebase for iOS push? No. iOS push is delivered through APNs, so you can send with APNs alone. FCM is optional on iOS and still delivers via APNs. Many teams add FCM for cross-platform reach.

How do I personalize a push notification? Send a template built in Design Studio and pass a data object (for example {"name": "Nomen Nescio"}), or include inline content with variables. Courier renders it per recipient.

Conclusion

Push notifications keep users engaged with timely, relevant messages. With Courier and its Python SDK, you send to a user across FCM, APNs, and Expo with one API call, let mobile SDKs handle token sync, and see exactly what happened in Message Logs. To go further, explore channel routing and failover and the full Send API.

One API, every channel

Ship notifications without the boilerplate

Courier gives you one API for email, SMS, push, and chat, with templates, routing, retries, and delivery logs built in.

Last updated Jul 6, 2026. Code samples are illustrative; provider APIs and pricing change over time, so check each provider’s docs before relying on them.