A push token is not a permanent identifier. Mobile operating systems and browser push services can issue a different token after an app reinstall, a device restore, an operating system change, a browser profile change, or a provider-side decision. The timing is not always predictable, and an application may not receive a useful explanation for the change.

The practical consequence is straightforward: your server must treat a token as replaceable registration data, not as a durable identity. When a token changes, update the existing device record, preserve the user relationship, and avoid creating duplicate subscriptions or sending repeatedly to a value that is no longer valid.

Understand what has changed

A push token identifies an app installation, browser subscription, or provider registration in a particular delivery environment. It is usually not the same thing as your user ID, account ID, device ID, or application identity. Treating it as a user identifier makes token rotation difficult to handle safely.

A token change can happen for several reasons:

  • The app was reinstalled or its local data was cleared.
  • The device was restored from a backup or moved to another device.
  • The operating system refreshed the registration.
  • A browser push subscription changed.
  • The application switched between development and production environments.
  • The user changed notification permission or browser settings.
  • A provider rejected an old token and issued a new registration.

The correct response depends on what your client reports and what your delivery service returns. A new token reported during registration is a direct signal to update your records. A send failure is weaker evidence: it may indicate an expired token, an invalid environment, a permission problem, a temporary provider issue, or another configuration error.

Keep identity separate from registration

Model the relationship explicitly. A useful device or subscription record normally has separate fields for your internal record ID, user identity, provider token, platform, application environment, notification permission state, and timestamps for registration and last successful update.

Do not use the raw push token as the primary key for a user. Do not assume one user has only one token, either. A user can have several phones, tablets, browsers, or app installations, and each may need its own registration.

When a signed-in client receives or reports a new token, associate that registration with the authenticated user. When the user signs out, decide whether your product should detach the registration, retain it as an anonymous device, or require a new association at the next sign-in. The right choice depends on whether notifications are personal, device-specific, or both.

A server-side registration operation should be safe to repeat. Matching on a stable internal device record, or on a carefully defined combination of user, application, platform, and provider registration, helps prevent duplicate rows when the client retries.

Handle token updates on every client

The client should register for push notifications during normal lifecycle events, not only during first launch. A typical flow is:

  • Request permission where the platform requires it, using timing that makes sense for the product.
  • Register with the platform or browser push service.
  • Send the current token and relevant application environment to your server.
  • Compare the returned token with the locally stored value.
  • Send an update whenever the token differs.
  • Repeat registration after reinstall, sign-in, sign-out, app update, and permission changes where appropriate.
  • Record the time of the latest successful server update.

Client SDKs can help with device registration, identity, token lifecycle, payload handling, and lifecycle events across iOS, Android, and Web Push. Even with an SDK, the server remains responsible for storing the current association and handling retries. Check the SDK's current documentation for the exact callback and lifecycle behaviour of each platform rather than assuming that all platforms report changes in the same way.

Avoid relying only on a local flag such as tokenUploaded. Local state can be lost, become stale, or belong to a different user. The client should be able to send its current token again, and the server should accept that operation without creating a second logical device every time.

Update the server record safely

Make token registration an idempotent operation. If the same token arrives several times, the result should be one current registration, not a growing collection of duplicates. If a token replaces an older value, retain enough history for diagnosis but use only the current valid registration for delivery.

Validate the application and environment attached to the registration. A development token must not silently replace a production registration, and a token from one application should not be assigned to another. Provider tokens can look like opaque strings, so format-based guesses are not a reliable substitute for explicit metadata.

When the user is known, update the user-to-device relationship in the same logical workflow as the token update. Consider concurrency as well: two app sessions may report different tokens close together, and an older request may arrive after a newer one. Include a registration timestamp, version, or server-side ordering rule so that a stale update cannot overwrite a more recent registration without review.

If your delivery service accepts targets by device or user, choose the target according to the product requirement. Device targeting is useful for testing or device-specific actions. User targeting is usually safer for personal alerts because it can reach the user's currently registered devices. Tag and segment targeting can support broader audiences, while all-enabled-device targeting should be reserved for deliberately global messages.

Send reliably after a change

When sending through HoneyNotify, server-side requests use POST /v1/notifications with a Bearer API key and an Idempotency-Key. A notification requires a title, body, and target. Use an idempotency key that represents the logical notification attempt, not a newly generated value for every retry. Otherwise, a network timeout can cause the same notification to be accepted more than once.

A token change should not make your application resend every historical notification. Decide which messages are still relevant, then create a new delivery attempt only where business rules require it. For time-sensitive events, store the event separately from the delivery attempt so you can determine whether a replacement device should receive a current alert.

Keep send outcomes and registration changes observable. Useful fields include your internal notification ID, target type, user or device record, platform, environment, attempt number, provider response category, and timestamps. Avoid logging raw tokens in ordinary application logs; they are operational identifiers and should be handled as sensitive registration data.

Diagnose a sudden drop in delivery

Start with the narrowest question: did the client report a new token, or did the server merely observe failed delivery? Then inspect the following sequence:

  • Confirm that the client has notification permission and that the application is using the intended environment.
  • Check whether the latest token reached the server successfully.
  • Verify that the registration belongs to the expected user and application.
  • Check for duplicate device records or an older record still marked active.
  • Inspect provider responses and separate permanent registration failures from temporary delivery errors.
  • Send a controlled test to the affected device or user rather than broadcasting a production message.
  • Confirm that the payload is valid for the platform and that the client handles the notification type.

A registration that looks correct can still fail at payload handling. The client SDK may receive the message, but application code might discard it because a required field is missing, the notification is handled only in one lifecycle state, or a deep link is no longer valid. Troubleshooting must cover both transport and application behaviour.

Migration and imported registrations

If you have migrated from another push provider, do not assume that an imported subscription identifier will continue to identify the same device indefinitely. Imported OneSignal subscription IDs can remain as device IDs when matching provider tokens later register, but token rotation or another provider environment can prevent matching.

Plan for an explicit reconciliation path. Let the current client registration become authoritative when it checks in, preserve the old identifier only for migration diagnostics, and avoid blocking delivery on a historical ID match. Verify the current provider's migration behaviour and token requirements before designing an automated merge rule.

Common mistakes

  • Treating a token as a permanent device or user ID.
  • Registering only on first install instead of on normal client lifecycle events.
  • Creating a new database row for every token update without retiring the old record.
  • Assuming a failed send always means the token changed.
  • Mixing development and production registrations.
  • Retrying a timed-out send with a new idempotency key.
  • Logging complete tokens in application logs or support tickets.
  • Deleting a user association immediately after one transient delivery error.
  • Sending old, no-longer-relevant notifications after a replacement registration appears.
  • Assuming imported identifiers will match future provider tokens in every environment.

Conclusion

Token rotation is an expected property of push delivery, not an exceptional event to patch around. Keep identity separate from registration, make client updates repeatable, validate environment and ownership, and use delivery feedback as a diagnostic signal rather than as your only source of truth. With idempotent registration, controlled retries, and useful observability, a changed token becomes a routine lifecycle update instead of a silent loss of notifications.