How to keep sending push to your OneSignal subscribers through your own Firebase

By Factodus · updated

Since 1 October 2026 the free OneSignal plan pauses mobile push once an organization goes over 1,000 monthly active users. If your Android app already uses the OneSignal SDK, you don’t have to ship an update to keep reaching the people who installed it: the push tokens it registered belong to your Firebase project, and Firebase Cloud Messaging (FCM) will deliver to them no matter who sends the request.

Short version. Export your subscribers with the OneSignal REST API (allowed on the free plan): the identifier column is the FCM token. Get an OAuth token from your Firebase service account and POST each message to fcm.googleapis.com/v1/projects/<project-id>/messages:send. We tested this end to end on an Android 16 phone with OneSignal Android SDK 5.1.

Check that the tokens are yours

This only works if OneSignal registered the devices under your Firebase project, which is the normal setup: you uploaded your Firebase service account JSON to OneSignal (Settings → Push & In-App → Google Android (FCM)).

To confirm, compare two numbers:

  • your Firebase project number: Firebase console → Project settings → General;
  • the android_sender_id OneSignal hands to the SDK: https://api.onesignal.com/apps/<your-app-id>/android_params.js, or look for it in adb logcat with OneSignal’s log level set to verbose.

If they match, every token in your list is an FCM token of your project.

1. Export the subscribers

Create a REST API key in OneSignal (Settings → Keys & IDs → Add key) and request a CSV export:

curl -s -X POST "https://api.onesignal.com/players/csv_export?app_id=$APP_ID" \
  -H "Authorization: Key $ONESIGNAL_REST_KEY" \
  -H "Content-Type: application/json" -d '{}'

The answer contains csv_file_url. The file is built in the background, so poll that URL until it returns 200. It is a gzipped CSV; the columns that matter here:

Column Meaning
identifier the push token; for Android, the FCM registration token
device_type 1 is Android, 0 is iOS
tags your OneSignal tags, as JSON, handy for segments
last_active when the user last opened the app
invalid_identifier t if OneSignal already knows the token is dead, otherwise f

Keep the Android rows with a non-empty identifier and invalid_identifier = f.

2. Get an access token for FCM

Use the same service account JSON you gave OneSignal. In Python with google-auth:

from google.auth.transport.requests import Request
from google.oauth2 import service_account

creds = service_account.Credentials.from_service_account_file(
    "service-account.json", scopes=["https://www.googleapis.com/auth/firebase.messaging"])
creds.refresh(Request())
print(creds.token)  # valid for about an hour

3. Send

FCM v1 takes one token per request:

curl -s -X POST "https://fcm.googleapis.com/v1/projects/$PROJECT_ID/messages:send" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": {"token": "'"$FCM_TOKEN"'",
       "notification": {"title": "Hello", "body": "Sent straight through FCM"}}}'

A 200 with a message name means FCM accepted it. Loop over your list with modest concurrency.

Things to know

  • Use notification messages. When the app is in the background, Android shows them by itself, without any app code. That is the case we tested. While the app is open, the message goes to the OneSignal SDK in the app, which may not display a payload it didn’t send.
  • Clean up dead tokens. A 404 with UNREGISTERED means the app was uninstalled or the token rotated; drop it.
  • New installs keep coming. The SDK in your app still registers new devices with OneSignal, so repeat the export now and then and merge the new tokens.
  • The Firebase console can’t do this for you. Its campaigns only reach devices registered by the Firebase SDK of an app you added to the project, not tokens the OneSignal SDK created. We sent a campaign to our test app and it never arrived.
  • iOS tokens in the export are APNs device tokens. They need your APNs .p8 key and Apple’s HTTP/2 API instead of FCM. We haven’t tested that path yet.
  • Web push and email stay free on OneSignal, so you can keep using it for those.