Understanding FCM Message Delivery on Android

If you are using Firebase Cloud Messaging to send important push notifications to your Android app users, you may be concerned about undelivered or delayed notifications. You may have already generated FCM delivery reports using the FCM aggregated API to check FCM delivery data or implemented your own analysis tools. If you see undelivered messages due to inactive devices, consider managing your tokens. If you see many messages dropped due to TTL Expired, ensure expirations are working as intended.

Understanding the reasons behind FCM delivery rates can ease your concerns about messages that are not delivered, so this blog post will discuss the 7 different statuses that a FCM message can have and what you can do about each one. With a better understanding of these message statuses, you can follow the guidelines and best practices in this article to help investigate your app’s FCM performance and improve your FCM delivery rate.

Delivered Messages

What Happened to My Message?

The message has been delivered to the user’s device. The onMessageReceived method will be called if you have extended FirebaseMessagingService, as recommended in our message handling guidance.

What Can I Do About it?

Just because a message has been delivered does not mean that your app has successfully displayed the push notification banner. Therefore, you should not count “Delivered” as the number of notification banners displayed when calculating push notification performance metrics such as click rate.

Furthermore, there is a separate section of the API report that focuses on the delivery performance for messages that were successfully delivered, and you can check the data for any unexpected delays of such messages:

  • Device offline: Expected delay. The target device was not connected at the time of sending. These messages will be delivered when the device reconnects.
  • Device in Doze mode: Expected delay. Normal-priority messages were delayed because the device was in doze mode.
  • User stopped: Expected delay. The intended recipient was not active at the time of sending.
  • Message throttled: Unexpected delay. Messages are delayed due to throttling, such as collapsible message throttling or maximum message rate throttling.

Pending Messages

What Happened to My Message?

These messages are not yet delivered because the device is offline. The messages are queued in the FCM backend waiting for delivery. For example, sending a message to a device that’s in airplane mode, off, or at the bottom of a river could result in a pending message.

If the day ends and messages are still in this state, they are reported as pending, and Firebase will continue to resend the message until the message’s time-to-live expires for 28 days. If the device were to turn back on before the end of the day, the messages would be delivered (delivered messages category gets incremented) and “delayed device offline” would also get incremented.

What Can I Do About it?

Pending messages will fall into another status sooner or later.

Collapsed Messages

What Happened to My Message?

Messages were collapsed by a newer message with the same collapse key.

What Can I Do About it?

This is considered an expected drop, as it’s a FCM feature to allow developers to replace an outdated message with a newer message.

Based on your business requirements, you may only want to send the newest messages to your user’s devices. An example would be a sports app that updates users with the latest score; only the most recent message is relevant.

Too many pending messages

What Happened to My Message?

Messages were dropped due to too many undelivered non-collapsible messages. Specifically, each app instance can only have 100 pending messages stored on Firebase servers for a disconnected device. When that device reconnects within 28 days, those messages will be delivered. However, if the limit is reached, all stored messages are discarded and the Firebase SDK will invoke the onDeletedMessages method.

What Can I Do About it?

Messages are dropped by FCM by design, but you might consider this an unexpected drop.

First, consider sending collapsible messages to avoid this.

Second, your app should handle onDeletedMessages(). If the user opens your app and Firebase detects that there are messages that were deleted due to too many pending messages, your app’s onDeletedMessages method will be invoked. At that time, your onDeletedMessages method might need to perform a full sync with your app server to make sure your app didn’t miss any important messages.

App is force-stopped

What Happened to My Message?

Messages were dropped due to the application being force-stopped on the device at the time of delivery, and retries were unsuccessful.

What Can I Do About it?

Because the user’s device is restricting the app, FCM can’t deliver the message. Unfortunately, you likely can’t do much about this.

Inactive device

What Happened to My Message?

Messages were dropped due to the target device being inactive. FCM will drop messages if the target device is deemed inactive by FCM. If a device does reconnect, the Firebase SDK will invoke onDeletedMessages() instead of re-delivering the messages.

What Can I Do About it?

Messages are dropped by FCM by design, but you might consider this an unexpected drop.

Based on our experience, apps that fail to manage FCM registration tokens are likely to have 15% of messages dropped due to inactive devices. Unlike other dropped message types, it’s hard to reduce this drop rate to 0% even if you follow our best practices because there will be some users who are inactive for more than 28 days.

What can you do to minimize message drops in this category:

  • Server side: consider updating registration tokens on your server, removing stale tokens, and unsubscribing them from topics. See Manage FCM registration tokens for best practices in this area.
  • Client side: handle onDeletedMessages(). You might need to perform a full sync with your app server to make sure your app didn’t miss any important messages. If you haven’t sent a message to the app on that device within the last 4 weeks, FCM won’t call onDeletedMessages().

Time to Live expired

What Happened to My Message?

Messages were dropped due to time-to-live expiration.

What Can I Do About it?

This is considered an expected drop, as it’s a FCM feature to let you to set a “time to live” deadline for the message.

Based on your business requirements, you may want to avoid sending outdated messages. For example in a 24-hour promotion, the message would be dropped after 24 hours so that only valid messages are presented to users.

Further Debugging

Undelivered messages with “Pending” statuses do not mean messages were dropped, and messages with “Collapsed”, “TTL expired”, “Too many pending messages dropped”, and “Device inactive drop” statuses are dropped by design.

If there are particular messages that you want to investigate, you can specify an analytics_label in those messages to FCM. Then, you’ll receive one aggregate data report per analytics label, and you can examine the delivery rates of those specific messages.

If the suggested remedies do not work, check if the issue is observed on a specific OEM device, model, or Android version. If you see any abnormality for a specific device, upgrade the device with the latest Android version and the latest OTA update that the device manufacturer provides. If the same issue is still reproduced on the updated device, report the issue.

Troubleshooting Message Delivery

If you have checked your FCM delivery rates using the statuses above and are still experiencing messages not getting delivered or messages being delayed, you can use the Firebase troubleshooter to debug problems related to sending messages in general. This is a step-by-step guide that can help you determine what is happening with a particular message. Additionally, there is a troubleshooter specifically for debugging Android message delivery.

To use the troubleshooter, read the description, follow the steps on each page, then choose the outcome that you experienced. This will either take you to another page with more descriptions and/or next steps, or it will open a page where you can submit a bug report.

Getting Aggregated Delivery Data

If you would like to get data on delivery rates for your app, you can learn more in FCM Aggregated Delivery Data, which walks you through exporting data from your Firebase project. Note that the percentages of all the message statuses might not add up to 100%, because not all message statuses are included in the API. There are a few additional limitations to these metrics, and they are most useful as trends over time.

Proxied Notifications

High priority notification messages (not data messages) that meet certain criteria are proxied by Google Play Services instead of being deprioritized, meaning that the notifications are displayed by Google Play services on behalf of the app without needing to start the app. This provides a better overall user experience on Android devices, and this feature is currently in Beta, subject to change. You can read more about proxied notifications on the Firebase documentation.

You may notice delays or drops in the number of messages received versus the number prior to the introduction of proxied notifications, because analytics for proxied notifications are only reported once your app starts and might not be reported at all if the notification doesn’t result in the app opening. ProxyNotificationInsightPercents` data from the FCM Aggregate Delivery Data API reports the percentage of successfully proxied notifications as well as details for messages that could not be successfully proxied.

Conclusion

By fully understanding these FCM statuses for your messages, you can follow the guidelines above to investigate your app’s FCM performance and follow the best practices, which could hopefully improve your FCM delivery rate!