Best practices for FCM registration token management
Stay organized with collectionsSave and categorize content based on your preferences.
If you useFCMAPIs to build send requests programmatically, you may
find that, over time, you are wasting resources by sending messages to inactive
devices with stale registration tokens. This situation can affect the message
delivery data reported in the Firebase console or data exported to BigQuery,
showing up as a dramatic (but not actually valid) drop in delivery rates. This
guide discusses some measures you can take to help ensure efficient message
targeting and valid delivery reporting.
Stale and expired registration tokens
Stale registration tokens are tokens associated with inactive devices that have
not connected toFCMfor over a month. As time passes, it becomes less
and less likely for the device to ever connect toFCMagain. Message
sends and topic fanouts for these stale tokens are unlikely to ever be
delivered.
There are several reasons why a token can become stale. For example, the device
the token is associated with may be lost, destroyed, or put into storage and
forgotten.
When stale tokens reach 270 days of inactivity,FCMwill consider themexpired tokens. Once a token expires,FCMmarks it as invalid and
rejects sends to it. However,FCMissues a new token for the app
instance in the rare case that the device connects again and the app is opened.
Basic best practices
There are some fundamental practices you should follow in any app that usesFCMAPIs to build send requests programmatically. The main best
practices are:
Retrieve registration tokens fromFCMand store them on your
server.An important role for the server is to keep track of each client's
token and keep an updated list of active tokens. We strongly recommend
implementing a token timestamp in your code and your servers, and updating
this timestamp at regular intervals.
Maintain token freshness and remove stale tokens.In addition to
removing tokens thatFCMno longer considers valid, you may want
to monitor other signs that tokens have become stale and remove them
proactively. This guide discusses some of your options for achieving this.
Retrieve and store registration tokens
On initial startup of your app, theFCMSDK generates a registration
token for the client app instance. This is the token that you must include in
targeted send requests from the API, or add to topic subscriptions for targeting
topics.
We strongly recommend your app retrieve this token at initial startup and save
it to your app server alongside a timestamp. This timestamp must be
implemented by your code and your servers, as it is not provided for you byFCMSDKs.
Also, it's important to save the token to the server and update the timestamp
whenever it changes, such as when:
The app is restored on a new device
The user uninstalls or re-installs the app
The user clears app data
The app becomes active again afterFCMhas expired its existing
token
Example: store tokens and timestamps inCloud Firestore
For example, you could useCloud Firestoreto store tokens in a collection
calledfcmTokens. Each document ID in the collection corresponds to
a user ID, and the document stores the current registration token and its
last-updated timestamp. Use thesetfunction as shown in this Kotlin example:
Determining whether a token is fresh or stale is not always straightforward. To
cover all cases, you should adopt a threshold for when you consider tokens
stale. By default,FCMconsiders a token to be stale if its app
instance hasn't connected for a month. Any token older than one month is likely
to be an inactive device; an active device would have otherwise refreshed its
token.
Depending on your use case, one month may be too short or too long, so it is up
to you to determine the criteria that works for you.
Detect invalid token responses from theFCMbackend
Make sure to detect invalid token responses fromFCMand respond by
deleting from your system any registration tokens that are known to be invalid
or have expired. With the HTTP v1 API, these error messages may indicate that
your send request targeted invalid or expired tokens:
UNREGISTERED(HTTP 404)
INVALID_ARGUMENT(HTTP 400)
If you are certain that the message payload is valid and you receive either of
these responses for a targeted token, it is safe to delete your record of this
token, since it will never again be valid. For example, to delete invalid tokens
fromCloud Firestore, you could deploy and run a function like the following:
//RegistrationtokencomesfromtheclientFCMSDKsconstregistrationToken='YOUR_REGISTRATION_TOKEN';constmessage={data:{//Informationyouwanttosendinsideofnotification},token:registrationToken};//SendmessagetodevicewithprovidedregistrationtokengetMessaging().send(message).then((response)=>{//ResponseisamessageIDstring.}).catch((error)=>{//DeletetokenforuseriferrorcodeisUNREGISTEREDorINVALID_ARGUMENT.if(error.errorCode=="messaging/registration-token-not-registered"){//Ifyou're running your own server, call API to delete thetokenfortheuser//ExampleshownbelowwithFirestore//GetuserIDfromFirebaseAuthoryourownserverFirebase.firestore.collection("fcmTokens").document(user.uid).delete()}});
FCMwill only return an invalid token response if a token expired
after 270 days or if a client explicitly unregistered. If you need to more
accurately track staleness according to your own definitions, you can
proactivelyremove stale registration tokens.
Update tokens on a regular basis
We recommend that you periodically retrieve and update all registration tokens
on your server. This requires you to:
Add app logic in your client app to retrieve the current token using the
appropriate API call (such astoken(completion):for Apple platforms orgetToken()for Android) and then send the current token to your app server for storage
(with a timestamp). This could be a monthly job configured to cover all
clients or tokens.
Add server logic to update the token's timestamp at regular intervals,
regardless of whether or not the token has changed.
Whatever timing pattern you follow, make sure to update tokens periodically. An
update frequency of once per month strikes a good balance between battery impact
and detecting inactive registration tokens. By doing this refresh, you also
ensure that any device which goes inactive will refresh its registration when it
becomes active again. There is no benefit to doing the refresh more frequently
than weekly.
Remove stale registration tokens
Before sending messages to a device, ensure that the timestamp of the device's
registration token is within your staleness window period. For example, you
could implementCloud Functions for Firebaseto run a daily check to ensure that the
timestamp is within a defined staleness window period such asconst
EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30;and then remove stale tokens:
If you use topics, you may also want to unregister stale tokens from the topics
to which they are subscribed. This involves two steps:
Your app should resubscribe to topics once per month and whenever the
registration token changes. This forms a self-healing solution, where the
subscriptions reappear automatically when an app becomes active again.
If an app instance is idle for one month (or your own staleness window) you
should unsubscribe it from topics using theFirebase Admin SDKto
delete the token to topic mapping from theFCMbackend.
The benefit of these two steps is that your fanouts will occur faster since
there are fewer stale tokens to fan out to, and your stale app instances will
automatically resubscribe once they are active again.
Measure delivery success
To get the most accurate picture of message delivery, it is best to only send
messages to actively used app instances. This is especially important if you
regularly send messages to topics with large numbers of subscribers; if a
portion of those subscribers are actually inactive, the impact on your delivery
statistics can be significant over time.
Before targeting messages to a token, consider:
Do Google Analytics, data captured in BigQuery, or other tracking signals
indicate the token is active?
Have previous delivery attempts failed consistently over a period of time?
Has the registration token been updated on your servers in the past month?
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-09-04 UTC."],[],[],null,[]]