How to Use Firebase Cloud Messaging
How to Use Firebase Cloud Messaging Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably deliver messages at no cost. Developed by Google as part of the Firebase platform, FCM enables developers to send notifications and data messages to Android, iOS, and web applications. Whether you're looking to increase user engagement, deliver real-time updates, or trig
How to Use Firebase Cloud Messaging
Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably deliver messages at no cost. Developed by Google as part of the Firebase platform, FCM enables developers to send notifications and data messages to Android, iOS, and web applications. Whether you're looking to increase user engagement, deliver real-time updates, or trigger background actions, FCM provides a scalable, secure, and easy-to-integrate infrastructure for push notifications.
With over 5 billion active Android devices and millions of iOS and web users, the ability to communicate directly with users through timely, personalized messages is no longer optional—it’s essential. FCM simplifies this process by abstracting complex protocols like APNs (Apple Push Notification service) and GCM (Google Cloud Messaging), offering a unified API that works seamlessly across platforms. Unlike third-party notification services, FCM integrates natively with Firebase Analytics, Crashlytics, and other Firebase tools, giving you deeper insights into user behavior and message performance.
This guide will walk you through every aspect of using Firebase Cloud Messaging—from initial setup and configuration to advanced implementation techniques and real-world use cases. By the end, you’ll have a comprehensive understanding of how to leverage FCM to enhance your app’s functionality and user retention.
Step-by-Step Guide
1. Set Up a Firebase Project
To begin using Firebase Cloud Messaging, you must first create a Firebase project. Navigate to the Firebase Console and click “Add project.” Follow the prompts to name your project, accept the terms, and optionally enable Google Analytics. Once the project is created, you’ll be taken to the project overview dashboard.
From the dashboard, click “Add app” and select the platform you’re developing for—Android, iOS, or Web. For Android, you’ll need to provide your package name (e.g., com.yourcompany.yourapp), which must match exactly what’s defined in your AndroidManifest.xml. For iOS, you’ll need your Bundle ID. For web, you’ll provide a nickname and enable the service worker.
After registering your app, Firebase will generate a configuration file: google-services.json for Android, GoogleService-Info.plist for iOS, and a snippet of JavaScript code for web. Download and save these files securely—they are required for authentication and communication between your app and Firebase servers.
2. Integrate Firebase SDK into Your App
Next, integrate the Firebase SDK into your application. The method varies depending on your platform.
For Android: Add the Google Services plugin to your project-level build.gradle file:
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.3.15'
}
}
Then, in your app-level build.gradle, apply the plugin and add the FCM dependency:
apply plugin: 'com.google.gms.google-services'
dependencies {
implementation 'com.google.firebase:firebase-messaging:23.4.0'
}
Sync your project in Android Studio to download the required libraries.
For iOS: If you’re using CocoaPods, add the following to your Podfile:
pod 'Firebase/Messaging'
Run pod install and open the .xcworkspace file. In your AppDelegate.swift (or AppDelegate.m), import Firebase and initialize it:
import Firebase
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
}
For Web: Add the Firebase SDK via npm or a script tag. Using npm:
npm install firebase
Then initialize Firebase in your JavaScript file:
import { initializeApp } from "firebase/app";
import { getMessaging } from "firebase/messaging";
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_PROJECT.firebaseapp.com",
projectId: "YOUR_PROJECT",
storageBucket: "YOUR_PROJECT.appspot.com",
messagingSenderId: "YOUR_SENDER_ID",
appId: "YOUR_APP_ID"
};
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
3. Request Notification Permissions
Before your app can receive push notifications, users must grant permission. This step is mandatory on iOS and recommended on Android and web.
iOS: In your AppDelegate, request authorization after Firebase is configured:
import UserNotifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
print("Notification permission granted")
} else {
print("Notification permission denied")
}
}
application.registerForRemoteNotifications()
return true
}
Web: Use the messaging API to request permission:
import { getMessaging, getToken } from "firebase/messaging";
const messaging = getMessaging();
getToken(messaging, { vapidKey: 'YOUR_VAPID_KEY' }).then((currentToken) => {
if (currentToken) {
console.log('Token:', currentToken);
} else {
console.log('No registration token available. Request permission to generate one.');
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
For Android, permission is handled automatically by the system, but you should still handle cases where users disable notifications in device settings.
4. Handle Token Refresh
FCM registration tokens are not permanent. They can change due to app reinstallations, device resets, or security updates. Your app must listen for token refresh events and update your backend accordingly.
Android: Create a service that extends FirebaseMessagingService:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onNewToken(String token) {
Log.d("FCM", "Refreshed token: " + token);
sendTokenToServer(token);
}
private void sendTokenToServer(String token) {
// Send token to your backend via HTTP POST
}
}
Register the service in AndroidManifest.xml:
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
iOS: Implement the didRegisterForRemoteNotificationsWithDeviceToken delegate method:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
sendTokenToServer(token)
}
Web: Listen for token changes using onTokenRefresh:
messaging.onTokenRefresh(() => {
getToken(messaging, { vapidKey: 'YOUR_VAPID_KEY' }).then((refreshedToken) => {
console.log('Token refreshed:', refreshedToken);
sendTokenToServer(refreshedToken);
}).catch((err) => {
console.log('Unable to retrieve refreshed token ', err);
});
});
5. Receive and Display Messages
Once the token is registered and your backend is configured, you can start receiving messages. FCM supports two types: notification messages and data messages.
Notification Messages: These are handled automatically by the system when the app is in the background. When the app is in the foreground, you must handle them manually.
Data Messages: These contain custom key-value pairs and are always delivered to your app, regardless of state.
Android: Override onMessageReceived in your FirebaseMessagingService:
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Check if message contains a notification payload
if (remoteMessage.getNotification() != null) {
String title = remoteMessage.getNotification().getTitle();
String body = remoteMessage.getNotification().getBody();
showNotification(title, body);
}
// Check if message contains a data payload
if (remoteMessage.getData().size() > 0) {
String data = remoteMessage.getData().get("custom_key");
handleDataMessage(data);
}
}
iOS: Implement the userNotificationCenter delegate method:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
print("Received notification: \(userInfo)")
// Show notification while app is in foreground
completionHandler([.alert, .sound, .badge])
}
Web: Use onMessage to handle foreground messages:
messaging.onMessage((payload) => {
console.log('Message received: ', payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: payload.notification.icon
};
new Notification(notificationTitle, notificationOptions);
});
6. Send Messages from Firebase Console
Once your app is configured, you can send test messages directly from the Firebase Console. Go to the “Cloud Messaging” section under “Engage” in the left-hand menu.
Click “Create message.” Enter a title and body. Select your app from the “Target” dropdown. You can send to specific devices using their registration tokens, to topics, or to user segments based on Firebase Analytics data.
Click “Test on a device” to send a message to a single device using its FCM token. This is ideal for testing. For production, use the Firebase Admin SDK or REST API to send messages programmatically.
7. Send Messages Programmatically Using Admin SDK
For automated or bulk messaging, use the Firebase Admin SDK. Install it in your server environment:
npm install firebase-admin
Initialize the SDK with your service account key (download from Firebase Console > Project Settings > Service Accounts):
const admin = require('firebase-admin');
const serviceAccount = require('./path/to/serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
Send a message to a single device:
const message = {
token: 'DEVICE_REGISTRATION_TOKEN',
notification: {
title: 'Hello from Firebase!',
body: 'This is a test notification.'
},
data: {
click_action: 'OPEN_ACTIVITY',
custom_data: 'some_value'
}
};
admin.messaging().send(message)
.then((response) => {
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
Send to a topic:
const message = {
topic: 'news',
notification: {
title: 'Breaking News',
body: 'New update available!'
}
};
admin.messaging().send(message)
.then((response) => {
console.log('Topic message sent:', response);
});
Best Practices
Optimize Message Delivery Timing
Timing is critical for user engagement. Avoid sending notifications during late-night hours unless your app’s audience is global and active at all times. Use Firebase Analytics to identify peak usage hours for your user segments and schedule messages accordingly. For example, an e-commerce app might send cart abandonment alerts two hours after a user leaves their cart, while a fitness app might send motivational messages in the morning.
Use Topics for Scalable Segmentation
Instead of managing individual device tokens for every user segment, use FCM topics. Topics allow you to subscribe users to categories like “sports_news,” “promotions,” or “low_battery_alert.” Subscribers receive messages sent to that topic, and unsubscribing is as simple as calling unsubscribeFromTopic(). This reduces server-side complexity and improves scalability.
Implement Message Prioritization
FCM supports high and normal priority levels. Use high priority only for time-sensitive messages like chat alerts or emergency notifications. Normal priority is sufficient for newsletters or updates. High-priority messages may wake the device from sleep, consuming battery. Misusing high priority can lead to throttling by the OS or user complaints.
Handle Permission Denials Gracefully
Some users will decline notification permissions. Don’t block functionality or annoy users with repeated prompts. Instead, provide an in-app setting to re-enable notifications. Explain the benefits—e.g., “Get alerts when your order ships”—and link to device settings for manual enabling.
Encrypt Sensitive Data in Payloads
While FCM messages are encrypted in transit, the payload is readable on the device. Never send passwords, tokens, or personally identifiable information in notification payloads. Use data messages to trigger your app to fetch sensitive content from your secure backend after the notification is tapped.
Test Across Platforms and OS Versions
Notification behavior varies between Android versions, iOS releases, and browser implementations. Test on multiple devices and OS versions. On Android, test with Doze mode enabled. On iOS, test in background and killed states. On web, test across Chrome, Firefox, and Safari. Use Firebase Test Lab and BrowserStack for automated testing.
Monitor Delivery and Engagement Metrics
Enable Firebase Analytics and link it to FCM. Track metrics like message delivery rate, open rate, and conversion rate after notification taps. Use UTM parameters in deep links to measure traffic sources. Set up alerts for sudden drops in delivery rates, which may indicate token invalidation or API issues.
Respect User Privacy and Compliance
Ensure compliance with GDPR, CCPA, and other regional privacy laws. Provide clear opt-in/opt-out mechanisms. Allow users to manage notification preferences in-app. Never collect tokens without consent. Document your data usage policies and make them accessible.
Tools and Resources
Firebase Console
The Firebase Console is your central hub for managing FCM. Use it to send test messages, view delivery statistics, create audience segments, and monitor message performance. The dashboard provides real-time graphs showing delivery rates, open rates, and device types.
Firebase Admin SDK
Available for Node.js, Java, Python, Go, and C
, the Admin SDK allows server-side message sending. It supports advanced features like multicast messaging (sending to up to 500 devices at once), conditional targeting based on app version or locale, and message scheduling.
Postman or cURL for REST API Testing
For debugging or custom integrations, use the FCM HTTP v1 API via Postman or cURL. This gives you full control over message headers, authentication tokens, and payload structure. Documentation is available at Firebase HTTP v1 API Reference.
FCM Token Debugger
Use the Firebase DebugView in Firebase Analytics to see real-time token registration events. This helps verify that your app is correctly generating and sending tokens to Firebase servers.
Third-Party Libraries
For React Native, use react-native-firebase. For Flutter, use firebase_messaging. For Xamarin, use Xamarin.Firebase.Messaging. These libraries abstract platform-specific code and simplify integration.
Documentation and Community
Always refer to the official Firebase documentation at firebase.google.com/docs/cloud-messaging. The Firebase community on Stack Overflow and GitHub is active and helpful. Search for common issues like “FCM not working on iOS 15” or “Android 12 notification icon not showing.”
Notification Design Tools
Use tools like Figma or Adobe Express to design notification templates with consistent branding, fonts, and icons. For Android, use the Notification Asset Generator to create adaptive icons in multiple resolutions.
Real Examples
Example 1: E-Commerce Flash Sale Alert
An online retailer uses FCM to notify users of limited-time sales. When inventory drops below 10 units for a popular item, their backend triggers a message to users who have previously viewed that product. The message includes a deep link to the product page and a countdown timer in the notification body: “Only 3 left! 2 hours left to save 50%.”
Results: Click-through rate increased by 42% compared to email campaigns. Cart abandonment decreased by 18% within 24 hours of the campaign.
Example 2: Ride-Sharing Driver Availability
A ride-sharing app sends data messages to drivers when demand spikes in their area. The message contains coordinates and estimated fare. When tapped, the app opens the map view with the pickup location preloaded. Drivers can accept or decline with one tap.
Implementation: The backend uses Firebase Functions to trigger messages based on real-time demand data from Firestore. Tokens are stored in a database indexed by location and availability status.
Example 3: News App Breaking News Topic
A news organization creates topics for categories like “politics,” “sports,” and “weather.” Users subscribe during onboarding. When a breaking news story is published, a single message is sent to the “breaking” topic. All subscribed users receive the alert instantly.
Optimization: The app uses a data payload to include an article ID. When the notification is tapped, the app fetches the full article from a CDN instead of embedding content in the message, reducing payload size and improving load speed.
Example 4: Fitness App Workout Reminder
A fitness app sends personalized reminders based on user goals and historical activity. If a user hasn’t logged a workout in three days, the app triggers a notification: “You’re on a 3-day streak! Keep going—just 15 minutes today.”
Logic: The backend runs a daily cron job using Firebase Functions to query Firestore for inactive users. Messages are sent using the Admin SDK with custom data fields for tracking engagement.
Example 5: Travel App Flight Delay Alert
A travel app integrates with airline APIs to detect flight delays. When a delay is detected, FCM sends a notification to the user’s device with updated departure time and gate information. The message includes a deep link to rebook or contact support.
Integration: The app uses FCM data messages to update the UI in real time, even if the app is closed. The notification is displayed using a custom notification channel on Android and a rich notification on iOS with action buttons.
FAQs
What is the difference between FCM and APNs?
FCM is Google’s unified messaging platform that supports Android, iOS, and web. APNs (Apple Push Notification service) is Apple’s proprietary system for iOS and macOS. FCM acts as a bridge—it automatically routes messages to APNs for iOS devices, so developers don’t need to manage both systems separately.
Can I send FCM messages without an internet connection?
No. FCM requires an active internet connection on the device to receive messages. If the device is offline, messages are stored temporarily by FCM servers and delivered when connectivity is restored, up to a 4-week window for non-collapsible messages.
Why are my notifications not appearing on iOS?
Common causes include: missing Push Notification capability in Xcode, incorrect certificate configuration, invalid bundle ID, or user denying permission. Check the device logs in Xcode for errors like “APNs token not registered.”
How many devices can I target with one FCM message?
You can send a single message to up to 1,000 devices using the legacy HTTP API. With the HTTP v1 API, you can send to up to 500 devices in a single multicast request. For larger audiences, use topics or send messages in batches.
Do FCM messages cost money?
No. FCM is free to use at any scale. Google does not charge for message delivery, token registration, or API usage. However, if you use Firebase Analytics or other paid Firebase services alongside FCM, those may incur costs based on usage.
Can I send FCM messages from my own server?
Yes. Use the Firebase Admin SDK or the HTTP v1 REST API to send messages from your backend. You’ll need a service account key from the Firebase Console to authenticate.
What happens if a user uninstalls my app?
FCM tokens become invalid when the app is uninstalled. Your server should handle “NotRegistered” errors when sending messages and remove the token from your database. FCM will not retry messages to invalid tokens.
How do I track if a user clicked my notification?
Include a unique identifier in the notification’s data payload. When the user taps the notification, your app can send an event to Firebase Analytics or your backend with the identifier. This allows you to measure click-through rates and conversion funnels.
Is FCM secure?
Yes. FCM uses TLS encryption for all message transmissions. Tokens are randomly generated and cannot be reverse-engineered. Never store tokens in insecure locations like local storage or cookies. Use secure backend storage with access controls.
Can I send messages to users who haven’t opened the app yet?
Yes. As long as the app was installed and registered a token with FCM, messages will be delivered—even if the app has never been opened. However, on iOS, the user must grant notification permission before tokens are generated.
Conclusion
Firebase Cloud Messaging is a powerful, free, and scalable solution for delivering real-time notifications across Android, iOS, and web platforms. Its seamless integration with the broader Firebase ecosystem, combined with straightforward APIs and robust documentation, makes it the preferred choice for developers seeking to enhance user engagement without the complexity of managing multiple push notification services.
By following the steps outlined in this guide—from project setup and SDK integration to message handling and best practices—you’ve equipped yourself with the knowledge to implement FCM effectively in any application. Whether you’re building a social app, an e-commerce platform, or a productivity tool, timely, personalized notifications can significantly boost retention, satisfaction, and conversion.
Remember: success with FCM isn’t just about sending messages—it’s about sending the right message, to the right user, at the right time. Use analytics to refine your strategy, respect user privacy, and continuously test across devices. With thoughtful implementation, FCM becomes more than a feature—it becomes a core component of your user experience.
Start small, measure everything, and scale intelligently. The future of app communication is real-time, personalized, and intelligent—and FCM is your gateway to it.