When does the Expo Push Notification service return DeviceNotRegistered (besides the obvious)?

Obviously, the Expo push notification endpoint will return a DeviceNotRegistered error code if you send a push notification token that isn’t actually registered with the service. My question is, are there any scenarios were a token would previously be registered and then become unregistered? Like, does Expo clean up their tokens if one of the platform-specific services reports that that token is no longer valid?

The interface is: when you get back a DeviceNotRegistered error for a token, you should stop sending messages to that token.

The reasons for getting DeviceNotRegistered could include:

  • Not asking the user for permission to send notifications
  • Sending a malformed or bogus token
  • Apple’s sending back “Unregistered” as the error reason from APNs. There are many reasons this happens e.g. they cycle tokens, the user could turn off notifications, etc. Completely up to Apple’s discretion; Expo reports that back as “DeviceNotRegistered”.
  • Similar for Google (GCM and Amazon SNS).
  • In the future, it is likely that Expo will remove tokens from our database or mark them as unregistered if Apple or Google reports them as unregistered. This is an implementation detail and is not intended to affect anything developer-facing – it’s just a way to reduce pointless requests to Apple and Google.
  • Expo may also expose a way for (non-developer) users to disable / re-enable notifications on a per-project basis, and we might send back DeviceNotRegistered in that case too. From a developer’s perspective, this is the same as Apple or Google saying that a device token is no longer registered and won’t require code changes.

So yes it is possible and expected for a previously registered token to become unregistered at the discretion of the push services.

I’m noticing many of my user’s push tokens have started to return “DeviceNotRegistered”. Should we be somehow routinely updating a user’s push token? i.e. Should we do something where like every time they start the app, we get push token and send it to our backend?

This is what we do. We basically do the workflow described in the example here (https://docs.expo.io/versions/latest/guides/push-notifications#__next) every time the app loads (if the user is logged in). Usually the token is the same, so our backend just overwrites it, but sometimes it changes so then we’re prepared. When we send out notifications, we send out to all push tokens matching that user. And when the push comes back with DeviceNotRegistered, we remove it from our database so its not sent out the next time (then the list actually gets smaller sometimes).

2 Likes

Thank yo llamaluvr. That makes sense. I think we will implement the same.

Sorry if is not obvious for me, but, how to workarround this problem? We have expired or “DeviceNotRegistered” error, but expo (in client) not returning a new Expo Token.

@ide, @quinlanj - Can you guys clarify. @quinlanj wrote here:

" your token shouldn’t expire, but your standalone app’s push certificates may expire."

It seems like @llamaluvr is reporting that sometimes they can expire out of the blue even if the user does not reinstall the app.

So can the expo tokens change if the user does not reinstall the app? I’ve noticed ppl asking this question here and there in the forums but no definitive answers in the documentation.

It’s been a looooong time since I posted this and I can’t even remember what I was thinking. I know the APNS token can change on a backup and restore (like when migrating to a new phone). Some people say it can change for other reasons and it’s not really clearly documented by Apple. I’d assume an APNS token change would result in an Expo token change. So all I do is check the token and update my server whenever the app starts up, so I’m never caught in a situation where a token that I don’t control changes for a reason I don’t understand.

Yeah…makes sense, but are you sure you need to do that?

Because according to @ide and @quinlanj from the Expo team, there basically is no way that a device token would change that would also not require the user to have to re-login.

So if you do it on login, then you should be ok. After reading documentation and forums posts for hours this is my conclusion. The documentation is not addressing this directlytly and I still for the life of me cannot find where it says under what conditions the token will change in the documentation. It’s buried in various forum postings.

Might be a difference between the language of “expire” and “change”. It never expires, but certain events I could see triggering a change. I just can’t see a way for Expo to maintain the same push token if the user restores the app on another device. It’s possible that the app is still in use on the previous device. In this case, the correct behavior would be for both devices to receive different push notifications, therefore, the push tokens would have to be different.

Actually found a reference to Apple’s documentation on this… https://stackoverflow.com/a/41856383. The APNS token can change on app restore, OS reinstall, and other situations. They recommend assuming it could change at anytime and updating your server accordingly. I would treat an Expo push token just like an APNS token, because all it really is is a platform-agnostic proxy for an APNS (or FCM) token.

Sorry, I mean changes, not referring to expires.

What I’m saying is that based on what I’ve read, there is no way for the expo token to change that does not require the user to login:

  1. Reinstalls the app - requires login
  2. “restores the app on another device” - requires login

Yes if you want to support logging in with the same account on multiple phones, obviously will have separate tokens for each phone.

Maybe the only thing actually now that I think of it is if the user changes their phone (upgrades), all the apps remain logged in, but very likely there will be a different token and if you don’t check on app open, it will not update in your backend…so that kind of answers it for me. :slight_smile:

If you can guarantee login any time the token changes (reinstalling the OS is another scenario), that could potentially work. However, with a default configuration and a typical login system, this is not the standard behavior. Without special configuration, an app restore is going to restore local storage, so if your session token is in there, the user will remain logged on. I forget exactly when this does or doesn’t get restored- there’s potentially different config for iCloud backup vs. iTunes backup, but I’ve definitely seen it happen.

It might work, can’t say it won’t. There’s a lot of variables in there, not all of which the developer controls, and it’ll be pretty difficult to troubleshoot if there is a problem, which I think is why the typical practice is to send the token to the server on app start and overwrite it if it changes. It’s an easy, cheap API call, and protects pretty thoroughly against something unexpected that may happen today based on current documentation or tomorrow based on a change in the framework or OS. In my experience, the one time (besides total server outage) when our users really come out with the pitchforks is when push notifications get messed up :stuck_out_tongue: .

1 Like

Yeah…I’m with you, already implemented it that way, essentially anytime the app is opened it will get a new token.

@aryk to clarify - the push tokens that you get from the users (ie) ExponentToken[XXXXX], dont expire.

The APNs key that is required to send these tokens to your users (.p8 file that you either uploaded to us, or that we generated for you) doesnt expire. However, before people used APNs keys, Apple used to require people have push certificates (.p12 file, that expires within a year). This shouldnt be relevant to you anymore since Apple stopped accepting these legacy push certificates at the beginning of this month https://developer.apple.com/news/?id=11042019a