Summary
Calling OneSignal.login(externalId) on every app launch does not retire or deduplicate stale push subscriptions on the same physical device. Over time, multiple enabled push subscriptions accumulate under the same external_id for a single device, causing every notification sent via include_aliases: { external_id: [...] } to be delivered N times (once per enabled subscription).
Environment
react-native-onesignal: 5.4.5 (also reproduced behavior on data created by earlier SDK versions)
- React Native: 0.81.4
- Expo: 54
- Platforms: iOS 26.x (iPhone 16) and Android 16 (Pixel)
Reproduction
- Install app, call
OneSignal.initialize() then OneSignal.login(userId) on launch
- Use app normally — subscription created correctly
- Update iOS (e.g. 26.4 → 26.5), or reinstall/clear data on Android
- Launch app again —
login(userId) is called with the same external ID
- Check subscriptions via
GET /apps/{app_id}/users/by/external_id/{userId}
Expected: One enabled push subscription per device per platform type.
Actual: Multiple enabled push subscriptions accumulate for the same device_model and platform type. Examples observed:
- iOS user: 2 enabled
iOSPush subscriptions on the same iPhone model (SDK 050501, different OS versions 26.4.2 and 26.5.1), both with valid APNs tokens
- Android user: 7
AndroidPush subscriptions on the same Pixel device (6 disabled with the same stale FCM token, 1 enabled with current token), plus 2 additional enabled subscriptions on old devices that were never cleaned up
Impact — Duplicate Notification Delivery
When sending a push notification targeted at a single external_id:
{
"include_aliases": { "external_id": ["<userId>"] },
"headings": { "en": "Title" },
"contents": { "en": "Body" },
"target_channel": "push"
}
The OneSignal delivery stats show successful: 2 for the iOS user (single device, single API call). The user physically receives the notification twice on the same phone.
Root Cause Analysis
login() transfers the current device's subscription to the identified user, but does not:
- Check if the user already has an enabled push subscription for the same
device_model + platform type
- Retire/disable the previous subscription on the same device
- Deduplicate before delivery
There is also no server-side guard — no API parameter like "deliver once per device" exists. collapse_id only collapses the notification tray; both deliveries still happen and both count as successful.
Related Issues
This is a long-standing class of bugs across SDKs:
- Android SDK #2110 — App kill + reopen creates duplicate subscription (fixed in PR #2099)
- Android SDK #2143 — 20-subscription cap deadlocks login forever (still open, 5+ reporters, acknowledged as bug by @jkasten2)
- Android SDK #2514 — Restricted external ID corrupts device, 12-15 orphan subs (still open)
- Android SDK PR #2618 — login/logout race fixed May 2026
- iOS SDK PR #1669 — iOS prewarm creates duplicate subscriptions (fixed SDK 5.5.2)
- React Native #1829 — logout/login doesn't clear old external ID (still open)
In #2143, a OneSignal engineer stated: "We are looking into removing older push subscriptions automatically so this extra integration step won't be needed in the future." — has there been progress on this?
Feature Request
-
login() should deduplicate subscriptions per device — when a user logs in and a new push subscription is created, any existing enabled push subscription for the same device_model + platform type under the same external_id should be automatically disabled or deleted.
-
Server-side dedup option — an API parameter (e.g., deduplicate_per_device: true) on the Create Notification endpoint that ensures at most one delivery per physical device per external_id, regardless of how many subscription records exist.
-
Automatic stale subscription cleanup — subscriptions with enabled: false that share an FCM/APNs token with a newer enabled subscription on the same user should be garbage-collected automatically.
Current Workaround
We are building a server-side cleanup job that periodically:
- Fetches each user's subscriptions via the View User API
- Identifies duplicates (multiple enabled subscriptions of the same type on the same device_model)
- Deletes stale ones via
DELETE /apps/{app_id}/subscriptions/{subscription_id}
This works but should not be necessary — the SDK and platform should handle this automatically.
Summary
Calling
OneSignal.login(externalId)on every app launch does not retire or deduplicate stale push subscriptions on the same physical device. Over time, multiple enabled push subscriptions accumulate under the sameexternal_idfor a single device, causing every notification sent viainclude_aliases: { external_id: [...] }to be delivered N times (once per enabled subscription).Environment
react-native-onesignal: 5.4.5 (also reproduced behavior on data created by earlier SDK versions)Reproduction
OneSignal.initialize()thenOneSignal.login(userId)on launchlogin(userId)is called with the same external IDGET /apps/{app_id}/users/by/external_id/{userId}Expected: One enabled push subscription per device per platform type.
Actual: Multiple enabled push subscriptions accumulate for the same device_model and platform type. Examples observed:
iOSPushsubscriptions on the same iPhone model (SDK 050501, different OS versions 26.4.2 and 26.5.1), both with valid APNs tokensAndroidPushsubscriptions on the same Pixel device (6 disabled with the same stale FCM token, 1 enabled with current token), plus 2 additional enabled subscriptions on old devices that were never cleaned upImpact — Duplicate Notification Delivery
When sending a push notification targeted at a single
external_id:{ "include_aliases": { "external_id": ["<userId>"] }, "headings": { "en": "Title" }, "contents": { "en": "Body" }, "target_channel": "push" }The OneSignal delivery stats show
successful: 2for the iOS user (single device, single API call). The user physically receives the notification twice on the same phone.Root Cause Analysis
login()transfers the current device's subscription to the identified user, but does not:device_model+ platform typeThere is also no server-side guard — no API parameter like "deliver once per device" exists.
collapse_idonly collapses the notification tray; both deliveries still happen and both count assuccessful.Related Issues
This is a long-standing class of bugs across SDKs:
In #2143, a OneSignal engineer stated: "We are looking into removing older push subscriptions automatically so this extra integration step won't be needed in the future." — has there been progress on this?
Feature Request
login()should deduplicate subscriptions per device — when a user logs in and a new push subscription is created, any existing enabled push subscription for the samedevice_model+ platform type under the sameexternal_idshould be automatically disabled or deleted.Server-side dedup option — an API parameter (e.g.,
deduplicate_per_device: true) on the Create Notification endpoint that ensures at most one delivery per physical device perexternal_id, regardless of how many subscription records exist.Automatic stale subscription cleanup — subscriptions with
enabled: falsethat share an FCM/APNs token with a newer enabled subscription on the same user should be garbage-collected automatically.Current Workaround
We are building a server-side cleanup job that periodically:
DELETE /apps/{app_id}/subscriptions/{subscription_id}This works but should not be necessary — the SDK and platform should handle this automatically.