This article is part of the weekly learning pathways we’re releasing leading up to Firebase Summit. See the full pathway and register for the summit here.
When you send a push notification to your users, things can go wrong in many places: the network might be down, the device might have performance issues or the send request might be invalid. And each platform has its own complexity so the challenges can keep adding up. All of this makes it difficult to know whether your notifications actually got delivered to users.
To get a better understanding of whether your notifications were delivered and where things might have gone wrong, you need one central place to collect all information and then run an analysis. This is where BigQuery can help. BigQuery, Google's solution for building data warehouses, gives you the ability to run queries and build custom dashboards that provide deep insights and actionable information.
With the Firebase Cloud Messaging Android SDK, you can log notification delivery data and export it to BigQuery. We recently expanded the same support for iOS and the web. In this article, we will walk you through the process of setting this up so you can better understand your delivery rate and identify ways to troubleshoot or improve it.
First, you need to enable BigQuery for your Firebase project. You can do this by navigating to the Firebase console > Project Settings > Integrations, and then click Link on the BigQuery card. It's worth noting that, by default, this integration uses the BigQuery sandbox. This lets you explore BigQuery capabilities at no cost, so you can evaluate if it fits your use case. After you link your Firebase project to BigQuery, Firebase will export your data to BigQuery. The initial propagation of data might take up to 48 hours to complete.
Once the data is successfully exported, you should be able to see a data table created under your project’s firebase_messaging tab in the BigQuery console.
data
firebase_messaging
To collect Notification Delivery data, you need to enable logging on the client side. In the next step, we're going to set up the iOS client and start logging some data to BigQuery.
With the Firebase Messaging iOS SDK 8.6.0 or higher, you can now enable notification delivery logging in your app that exports to BigQuery by calling a new API we recently added. You will need to log alert and background notifications separately (this is only required for Apple's platforms).
Alert notifications and Notification Service Extension
To log alert notifications delivery, you first need to add a Notification Service Extension to your project in Xcode. The Notification Service Extension lets you customize the content of notifications before they become visible to users. Apple’s developer documentation has more details about how to add a service extension to your project.
After adding the Notification Service Extension to your project, find the NotificationService didReceiveNotificationRequest:withContentHandler: method inside the service extension target. This is where you will add code to enable logging.
NotificationService didReceiveNotificationRequest:withContentHandler:
In Firebase 8.6.0, We have introduced a new method to the Firebase Messaging API: the delivery data export API FIRMessagingExtensionHelper exportDeliveryMetricsToBigQueryWithMessageInfo:. Logging is disabled by default, so you will need to explicitly enable it by calling this API inside the Notification Service Extension.
FIRMessagingExtensionHelper exportDeliveryMetricsToBigQueryWithMessageInfo:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { // Modify the notification content here... bestAttemptContent.title = "\(bestAttemptContent.title) 👩🏻💻" // Log Delivery signals and export to BigQuery. Messaging.serviceExtension() .exportDeliveryMetricsToBigQuery(withMessageInfo: request.content.userInfo) // Add image, call this last to finish with the content handler. Messaging.serviceExtension() .populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler) } }
Note that, if you use the Firebase Cloud Messaging SDK to add an image to your notification, you need to make sure to call the deliver data export API before calling Messaging.serviceExtension().populateNotificationContent(_:withContentHandler), as shown in the code snippet above.
Messaging.serviceExtension().populateNotificationContent(_:withContentHandler)
The Apple system only passes the notification to the service extension if the notification payload contains the key "mutable-content" :1, so make sure you specify this key if you use the HTTP v1 API. If you use the Firebase console to send notifications, "mutable-content" :1 will be set automatically.
"mutable-content" :1
Background notifications
Background notifications are hidden messages that allow your app to wake up and update data in the background. To enable delivery data export for these kinds of notifications, you will need to implement the application:didReceiveRemoteNotification:fetchCompletionHandler: method and call exportDeliveryMetricsToBigQueryWithMessageInfo: method as shown below:
application:didReceiveRemoteNotification:fetchCompletionHandler:
exportDeliveryMetricsToBigQueryWithMessageInfo:
// For background notifications, call the API inside the UIApplicationDelegate method: func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { Messaging.extensionHelper().exportDeliveryMetricsToBigQuery(withMessageInfo:userInfo) }
Make sure to include "content-available":1 to specify it’s a background notification when you use the HTTP v1 API to send the notification.
"content-available":1
Notification Delivery Logging is newly available on the web for Firebase JS SDK versions 9.0.0 and newer. To enable delivery data export, all you need to do is to enable the flag on a service worker as shown below. This is handled similarly to Android.
// userConsent holds the decision of the user to give big query export consent. const userConsent = ...; const messaging = getMessagingInSw(app); experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, userConsent)
Notification Delivery Logging has been supported on Android since Firebase SDKs version 20.1.0 or higher. On Android, you can call the delivery data logging API to enable data export for both display and data messages like this:
FirebaseMessaging.getInstance().setDeliveryMetricsExportToBigQuery(true)
By default, Notification Delivery Logging is disabled on all three platforms, and will only be activated once you call the API to enable it for the particular platform your app is running on. You can also deactivate the BigQuery export any time by unlinking your project in the Firebase console.
Results on BigQuery
Once you have successfully logged some data you will see this data in the BigQuery console. Keep in mind that the data is regularly pushed from Firebase to BigQuery and the daily propagation might take some time (up to a couple of hours, depending on the amount of data) to complete.
BigQuery data also includes customized analytics labels that help you to create custom queries. Here’s a preview what type of data you can get from the iOS platform:
With the delivery data on BigQuery, you can now run custom queries or build a customized dashboard based on your needs. It provides detailed information about your campaign, including message identifier, message type, SDK platform and timestamp so you can get a lot of useful information helping you identify if the message was sent as expected. You can also segment the data based on your custom analytics labels. And if you are interested in getting additional aggregate information about message delivery on Android, check out this Medium post to find out how to use FCM Aggregation API for advanced data analysis.
View the full learning pathway on FCM message delivery for additional codelabs, videos and articles. And don’t forget to register for Firebase Summit and join us on November 10th to learn how Firebase can help you accelerate your app development, release with confidence and scale with ease!
Notifications are one of the most powerful ways of bringing latent users back to your app. Properly timed and targeted notifications can be vital in increasing engagement. That's why we've redesigned the Firebase notifications dashboard to support much more sophisticated and powerful notification campaigns.
The old notifications dashboard let you set up notification campaigns as one-time alerts that could go out immediately, or be scheduled for a later date. For example, with a few clicks, you could set up a notification campaign that would remind new users who failed to complete onboarding to do so on Monday. However, it was not possible to automate this reminder to go out every Monday - unless you did it manually.
In the new Firebase notifications dashboard, we have added the ability to create recurring campaigns. Recurring campaigns are notification campaigns that run automatically, whenever a user meets the targeting conditions. Now, it's easy to set-up that weekly reminder to encourage new users to complete onboarding. Or, perhaps you want to offer bi-weekly discounts on in-app purchases to spenders to nudge them towards a purchase - that's also possible!
The new notifications dashboard allows you to set user-level message frequency caps, so you can limit the number of times a user gets a message to prevent spamming them. You can limit messages to only be sent once per user, or allow one message over a specified number of days.
Perhaps you want to send a welcome message once to each new user. Use a single message to target every new user once. Or, perhaps you want to encourage users to check out a tutorial on how to use the app. You can send a notification once every few days to guide them towards the action until it's been completed. And since targeted segments are dynamic, users who meet the criteria will automatically start receiving notifications, and users who no longer meet the criteria will stop receiving the targeted notifications. This means your notification will only be delivered to users who find it relevant.
Users can receive a notification just once
Users can receive notifications at a custom interval
Untargeted batch and blast notifications are annoying and can cause churn. It's vital to carefully segment the right users so your notification appears welcome and relevant to their recent interaction with your app - not out of place and random. The new notifications dashboard includes a more sophisticated segment builder that gives you the ability to target prevalent user characteristics, like last app engagement and the number of days since they first opened the app. This targeting is built into the dashboard, so you don't have to add any code to get these new parameters.
Finally, we also improved the results section of the notifications dashboard so you can better monitor the performance of your campaigns and make adjustments as needed. In the new notifications dashboard, you can now track the effectiveness of recurring campaigns day-by-day. Here, you can see daily data points for notification sends, opens, and conversions. You'll also notice that the graphs have been updated from a bar chart to a time-series graph, which are more intuitive and easier to interpret.
The redesigned Firebase notifications dashboard offers new, powerful campaign options, sophisticated targeting, and rich analytics to track the progress of your notifications campaigns. If you're new to Firebase notifications, get started with the Firebase Cloud Messaging guides.
Check out the Firebase console to set up your notification campaigns today!
In the "Notifying your users with FCM" blog post, we shared guidance on using FCM in modern Android with regard to all the power management features. Following on that, let's look at the common workflow of FCM messages -- notification messages and data messages, and how to handle these messages in your code.
When sending push notifications to your users, notification messages are the preferred method if you want to take advantage of the Firebase Console and let the Android system handle notification posting. Notification messages are high priority by default, and high priority FCM messages will still be delivered to users immediately even when the device is idle.
When using an FCM notification message, the system handles showing the notification on behalf of your app when it's in the background. When your app is in the foreground, the FCM notification message is delivered to the onMessageReceived()handler and you can handle it by posting a notification if needed or update the app content with the FCM payload data (Max 4KB) or fetch content from app server.
onMessageReceived()
An App server sends a notification message (or a notification message with a data payload) to a user:
getIntent()
Note: if the user dismisses the notification, data will not be delivered when app opens.
class SimpleFirebaseMessagingService : FirebaseMessagingService() { private val TAG = "spFirebaseMsgService" override fun onMessageReceived(remoteMessage: RemoteMessage) { // when App is in foreground, notification message: if (remoteMessage.notification != null) { // post notification if needed updateContent(remoteMessage.notification) } // process data payload } private fun updateContent(notification: RemoteMessage.Notification) {} }
SimpleFirebaseMessagingService.kt
You should use data messages if you need to handle the notification in the client app, whether to customize the notification or to decrypt the received payload data.
A data message is normal priority by default, which means it will be batched to the next maintenance window when the device is in Doze, by default.
When sending data messages, you need to handle the messages in the onMessageReceived() callback in the client app. The suggested approach in the handler is as following:
An App server sends data messages to notify users with end-to-end encrypted FCM message:
Note: Keep in mind that the FCM handler only has approximately 20 seconds once the message is received, as it's designed to complete short tasks like posting a notification. If you need to process longer than this window, we recommend scheduling a job or use the WorkManager API.
class SimpleFirebaseMessagingService : FirebaseMessagingService() { private val TAG = "spFirebaseMsgService" override fun onMessageReceived(remoteMessage: RemoteMessage) { // Use data payload to create a notification if (remoteMessage.data.isNotEmpty()) { // step 2.1: decrypt payload val notificationMessage = decryptPayload(remoteMessage.data) // step 2.1: display notification immediately sendNotification(notificationMessage) // step 2.2: update app content with payload data updateContent(remoteMessage.data) // Optional step 2.3: if needed, fetch data from app server /* if additional data is needed or payload is bigger than 4KB, App server can send a flag to notify client*/ if (remoteMessage.data["url"] != null) { scheduleJob() // use WorkManager when it's stable } } // process notification payload when app in foreground... } private fun decryptPayload(dataPayload: Map<String, String>): String { return "decrypted message" } private fun sendNotification(notificationMessage: String) {} private fun updateContent(dataPayload: Map<String, String>) {} private fun scheduleWork() { // it's recommended to use WorkManager when it's stable, use JobScheduler // on background work complete, update the notification if still active } }
Android has introduced many power improvement features in recent versions, so make sure you review and test your FCM use cases against these features. You can learn more about Android Power features and how it works with FCM from this blog post.
If you are not using FCM yet, it's time to upgrade. The C2DM library was officially deprecated in 2012 and shut down completely in 2015, making it no longer compatible with modern Android. We also announced in April 2018 that Google Cloud Messaging (GCM) server and client APIs have been deprecated and will be removed as soon as April 11th, 2019. You can find out more about the announcement and migration guides in this blog post.
To take advantage of all the new features and functionality that FCM and Android provide, we recommend using FCM today. To get started, visit the Firebase Cloud Messaging documentation.
If you're like most app developers, you know that small changes can often make a big difference in the long term success of your app. Whether it's the wording that goes into your "Purchase" button, the order in which dialogs appear in your sign-up flow, or how difficult you've made a particular level of a game, that attention to detail can often make the difference between an app that hits the top charts, or one that languishes.
But how do you know you've made the right changes? You can certainly make some educated guesses, ask friends, or run focus groups. But often, the best way to find out how your users will react to changes within your app is to simply try out those changes and see for yourself. And that's the idea behind A/B testing; it lets you release two (or more!) versions of your app simultaneously among randomly selected users to find out which version truly is more successful at getting the results you want.
And while Firebase Remote Config did allow you to perform some simple A/B testing through its "random percentile" condition, we've gone ahead and added an entirely new experiment layer in Firebase that works with Remote Config and notifications to make it quick and easy to set up and measure sophisticated A/B tests. Let's take a quick tour of how it works!
With the new A/B testing feature, you can create an A/B test that will allow you to play with any combination of values that you can control through Remote Config. Setting up an A/B test allows you to define how the experiment will behave in a number of different ways, including determining how many of your users are involved with the experiment at first…
…how many variants you want to run, and how your app might behave differently for each variant…
...and what the goal of the experiment is.
Different experiments might have different desired goals, and A/B testing supports a number of common outcomes, like increasing overall revenue or retention in your app, reducing the number of crashes, or increasing the occurrence of any event you're measuring in Google Analytics for Firebase, such as finishing your in-app tutorial.
Once you've defined your A/B test, Firebase takes over by delivering these different variations of your app to randomly-selected members of your audience. Firebase will then measure your users' behavior over time, and let you know when an experiment appears to be performing better, based on those goals you've defined earlier. Firebase A/B testing measures these results for you with the same Bayesian statistical models that power Google Optimize, Google's free testing and personalization product for websites.
Fabulous, a motivational app for building better habits, recently made improvements to their app's onboarding flow by using Firebase A/B testing. When the user first starts an app, Fabulous shows them how to complete a habit, presents them with a letter about forming better habits, and then asks them to commit to a simple routine. The team suspected that if they removed a few steps from this onboarding process, more people might complete it.
Some of the screens a typical user encounters when first using Fabulous
So they ran an A/B test where some users didn't see the letter, others didn't see the request to commit to a simple routine, and others skipped both of those steps. The Fabulous team found that by removing both of these steps from the onboarding process, there was a 7% improvement in the rate of users completing the onboarding flow. More importantly, they confirmed that this shorter onboarding experience didn't have any negative impact on their app's retention.
You also have the ability to A/B test your app notification messages through the Firebase Notifications console. You can try out different versions of your notification message and see which ones lead to more users opening up your app from that notification, or which messages lead to users performing some intended goal within your app, like making a purchase.
A/B testing is available in beta to all Firebase developers starting today. If you're excited to get started, you should make sure that your app is wired up to use Remote Config and/or Firebase Cloud Messaging, and that you've updated these libraries to the latest and greatest versions. You can always find out more about A/B testing in our documentation, or check out the A/B Test Like a Pro video series we've been building.
Then, head on over to the Firebase Console and start making your app better — one experiment at a time!