Most FlutterFlow push notification problems fall into four categories: iOS not working at all (missing APNs authentication key), notifications not showing while the app is open (foreground handler not configured), null FCM token that looks like a code bug but is actually a denied permission, and a Firebase project mismatch between development and production builds. Each has a specific fix that requires looking outside FlutterFlow.
Why Push Notifications Fail Differently on iOS and Android
Push notifications in FlutterFlow are delivered through Firebase Cloud Messaging, which acts as a middle layer between your server and the device. Android devices communicate with FCM directly. iOS devices add a second layer: FCM must authenticate with Apple's Push Notification service (APNs) using a key you upload to Firebase. If that key is missing or expired, no iOS notification will ever arrive — the failure is silent in FlutterFlow's logs. On both platforms, a null FCM token is the other most-reported issue. Developers spend hours debugging their Firestore writes before discovering the real cause: the user tapped 'Don't Allow' on the permission prompt, and a denied permission always produces a null token.
Prerequisites
- FlutterFlow project with Firebase connected and push notifications enabled in project settings
- Apple Developer account ($99/year) for iOS push notification configuration
- Firebase project with Cloud Messaging API enabled
- FCM server key entered in FlutterFlow Settings > Push Notifications
Step-by-step guide
Upload your APNs authentication key to Firebase for iOS
Upload your APNs authentication key to Firebase for iOS
If push notifications work on Android but not on iOS, the APNs key is almost certainly missing or wrong. Go to Apple Developer Portal > Certificates, Identifiers & Profiles > Keys. Create a new key with 'Apple Push Notifications service (APNs)' checked. Download the .p8 file — it can only be downloaded once. Note the Key ID and your Team ID (shown in the upper right of the Apple Developer portal). In Firebase Console > Project Settings > Cloud Messaging > Apple app configuration, upload the .p8 file and enter the Key ID and Team ID. This single key works for both development and production APNs environments, unlike the older certificate approach.
Expected result: After uploading the key, test by sending a notification from Firebase Console > Cloud Messaging > Send test message to an iOS device. The notification should arrive within seconds.
Diagnose a null FCM token as a permissions issue
Diagnose a null FCM token as a permissions issue
If your FlutterFlow app calls the get FCM token action and gets back a null or empty value, the first reaction is usually to check the code. Stop. A null FCM token on iOS almost always means the user has not granted notification permission — either they tapped 'Don't Allow' on the permission prompt, or you never showed the prompt. On Android 13+, the same applies. In FlutterFlow check whether you have a Request Notification Permission action before you try to get the FCM token. Add a Custom Action that checks FirebaseMessaging.instance.getNotificationSettings() and reads the authorizationStatus. If it returns denied or notDetermined, show a dialog explaining why notifications are useful before calling requestPermission.
1// Custom Action: checkNotificationPermission.dart2import 'package:firebase_messaging/firebase_messaging.dart';34Future<String> checkNotificationPermission() async {5 final settings =6 await FirebaseMessaging.instance.getNotificationSettings();7 switch (settings.authorizationStatus) {8 case AuthorizationStatus.authorized:9 return 'authorized';10 case AuthorizationStatus.denied:11 return 'denied';12 case AuthorizationStatus.notDetermined:13 return 'not_determined';14 case AuthorizationStatus.provisional:15 return 'provisional';16 default:17 return 'unknown';18 }19}Expected result: The permission status string tells you exactly why the FCM token is null. 'denied' means the user rejected it; 'not_determined' means you never asked.
Configure a foreground notification handler
Configure a foreground notification handler
By default on iOS, notifications received while your app is in the foreground are silently dropped — they do not appear as banners or sounds. This is an Apple system behavior. On Android, foreground notifications are delivered but the visual presentation depends on your notification channel setup. In FlutterFlow add a Custom Action called setupForegroundHandler that calls FirebaseMessaging.instance.onMessage.listen. Inside the listener, use the flutter_local_notifications package to display a local notification when an FCM message arrives while the app is open. Register this handler in your app's initialization flow so it is active throughout the app's lifetime.
1// Custom Action: setupForegroundHandler.dart2import 'package:firebase_messaging/firebase_messaging.dart';3import 'package:flutter_local_notifications/flutter_local_notifications.dart';45final _localNotifications = FlutterLocalNotificationsPlugin();67Future setupForegroundHandler() async {8 // Initialize local notifications9 const initSettings = InitializationSettings(10 android: AndroidInitializationSettings('@mipmap/ic_launcher'),11 iOS: DarwinInitializationSettings(),12 );13 await _localNotifications.initialize(initSettings);1415 // Listen for foreground FCM messages16 FirebaseMessaging.onMessage.listen((RemoteMessage message) async {17 if (message.notification != null) {18 await _localNotifications.show(19 message.hashCode,20 message.notification!.title,21 message.notification!.body,22 const NotificationDetails(23 android: AndroidNotificationDetails(24 'default_channel', 'Default',25 importance: Importance.high,26 priority: Priority.high,27 ),28 iOS: DarwinNotificationDetails(),29 ),30 );31 }32 });33}Expected result: Notifications sent while the app is in the foreground now display as banners on both iOS and Android.
Detect and fix dev vs production Firebase project mismatches
Detect and fix dev vs production Firebase project mismatches
A common scenario: push notifications work perfectly in development but fail silently in the App Store or Google Play build. The cause is a Firebase project mismatch. FlutterFlow connects to one Firebase project, but if you downloaded your app code and built it locally, or used a different google-services.json, it may point to a different project. Check: in FlutterFlow Settings > Firebase > Firebase Project, note your project ID. On your deployed device, the FCM token is registered to the Firebase project embedded in the app's google-services.json (Android) or GoogleService-Info.plist (iOS). If you send a notification from the wrong Firebase project, the token does not exist in that project and the message fails silently. Always send test notifications from the same Firebase Console project that matches your app bundle.
Expected result: Notifications sent from the correct Firebase Console project arrive on all test devices.
Test the full notification path using Firebase's test message tool
Test the full notification path using Firebase's test message tool
Before debugging your FlutterFlow code, eliminate the delivery infrastructure as the cause. In Firebase Console > Cloud Messaging, click 'Send your first message' or 'New notification'. Write a test title and body, click 'Send test message', and paste your device's FCM token (from your app's debug output or a Custom Action that logs the token). If this test succeeds, FCM delivery works and the problem is in your FlutterFlow action that triggers the notification. If it fails, the problem is in your Firebase project configuration (APNs key, token registration). This binary test saves hours of debugging the wrong layer.
Expected result: Firebase Console's test message either delivers successfully (confirming FCM works) or fails with a specific error code that points to the configuration issue.
Complete working example
1// Complete notification setup for FlutterFlow2// Packages needed: firebase_messaging, flutter_local_notifications3import 'package:firebase_messaging/firebase_messaging.dart';4import 'package:flutter_local_notifications/flutter_local_notifications.dart';5import 'package:cloud_firestore/cloud_firestore.dart';6import 'package:firebase_auth/firebase_auth.dart';7import 'package:flutter/foundation.dart';89final _localNotifications = FlutterLocalNotificationsPlugin();1011/// Call this from your app's On App Load action12Future<void> initializeNotifications() async {13 // 1. Request permission14 final settings = await FirebaseMessaging.instance.requestPermission(15 alert: true, badge: true, sound: true,16 );17 if (settings.authorizationStatus != AuthorizationStatus.authorized) {18 debugPrint('Notification permission: ${settings.authorizationStatus}');19 return; // Token will be null — do not proceed20 }2122 // 2. Get and store FCM token23 final token = await FirebaseMessaging.instance.getToken();24 final uid = FirebaseAuth.instance.currentUser?.uid;25 if (uid != null && token != null) {26 await FirebaseFirestore.instance.collection('users').doc(uid).update({27 'fcmToken': token,28 'fcmUpdatedAt': FieldValue.serverTimestamp(),29 });30 }3132 // 3. Refresh token on rotation33 FirebaseMessaging.instance.onTokenRefresh.listen((newToken) async {34 if (uid != null) {35 await FirebaseFirestore.instance.collection('users').doc(uid)36 .update({'fcmToken': newToken});37 }38 });3940 // 4. Initialize local notifications for foreground display41 await _localNotifications.initialize(42 const InitializationSettings(43 android: AndroidInitializationSettings('@mipmap/ic_launcher'),44 iOS: DarwinInitializationSettings(),45 ),46 );4748 // 5. Show foreground notifications as local49 FirebaseMessaging.onMessage.listen((RemoteMessage msg) async {50 if (msg.notification != null) {51 await _localNotifications.show(52 msg.hashCode, msg.notification!.title, msg.notification!.body,53 const NotificationDetails(54 android: AndroidNotificationDetails('default', 'Default',55 importance: Importance.high, priority: Priority.high),56 iOS: DarwinNotificationDetails(),57 ),58 );59 }60 });61}6263/// Check permission status — use before showing permission rationale64Future<String> getPermissionStatus() async {65 final s = await FirebaseMessaging.instance.getNotificationSettings();66 return s.authorizationStatus.name;67}Common mistakes when troubleshooting Common FlutterFlow Push Notification Problems
Why it's a problem: Assuming a null FCM token is a code bug
How to avoid: Check the notification permission status first using getNotificationSettings(). If authorizationStatus is denied or notDetermined, address the permission issue before debugging the token.
Why it's a problem: Not uploading the APNs key to Firebase and wondering why iOS never receives notifications
How to avoid: Generate a .p8 APNs key in Apple Developer portal and upload it to Firebase Console > Project Settings > Cloud Messaging > Apple app configuration.
Why it's a problem: Sending notifications from the wrong Firebase project
How to avoid: Verify that your app's google-services.json (Android) and GoogleService-Info.plist (iOS) match the Firebase project you are sending from in the Console.
Best practices
- Always request notification permission after showing an in-app explanation of why you send notifications — system dialogs shown without context are denied at a much higher rate.
- Refresh the FCM token every time the user logs in, not just at app install, because tokens can be rotated by the OS.
- Handle onTokenRefresh and update the stored token in Firestore so users never miss notifications after a token refresh.
- Test notifications on real physical devices — simulators and emulators have unreliable push notification behavior.
- Log FCM token registration failures to Crashlytics so you are alerted if a platform change causes token registration to stop working.
- Use Firebase Console's test message tool as your first debugging step before changing any code.
- Include a deep link in your notification data payload so tapping the notification navigates users to the relevant screen rather than just opening the app home page.
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building a FlutterFlow app and push notifications work on Android but not on iOS. Walk me through the complete iOS push notification configuration: APNs key setup in Apple Developer portal, uploading to Firebase, and what can cause silent failures on iOS that do not show any error in my app logs.
Write a FlutterFlow Custom Action in Dart that initializes Firebase Messaging, requests notification permission, stores the FCM token to a Firestore user document, listens for token refreshes, and sets up a foreground notification handler using flutter_local_notifications to display incoming messages while the app is open.
Frequently asked questions
Why do push notifications work in debug builds but not in the App Store version?
The most common cause is using a development APNs certificate or key instead of the production one, or having the wrong Firebase project's plist in your release build. Verify that your GoogleService-Info.plist in the release build matches the Firebase project where you are sending notifications.
How do I get a user to re-enable push notifications after they denied permission?
iOS does not allow you to show the system permission prompt a second time after denial. You can only direct the user to Settings. In FlutterFlow, show an in-app dialog with a 'Go to Settings' button that opens the app settings page using a Custom Action that calls openAppSettings() from the app_settings package.
What is the difference between a notification message and a data message in FCM?
A notification message has a notification payload (title and body) and is handled by the OS — it shows automatically in the notification tray. A data message has only a data payload and is delivered silently to your app's handler. For background delivery on iOS, data-only messages require a specific capability flag. Use notification messages for standard alerts and data messages for silent background updates.
Why does my notification tap not navigate to the right screen?
When a user taps a notification that opened the app from a terminated state, the initial message is available via FirebaseMessaging.instance.getInitialMessage(). For apps already in background, use FirebaseMessaging.onMessageOpenedApp. In FlutterFlow, handle both cases in a Custom Action called from your app's On App Load action and navigate based on the message data payload.
How do I test push notifications on an iOS simulator?
iOS simulators support push notifications from Xcode 11.4 and later using simulated push files. However, you cannot test FCM token registration or real network delivery on a simulator. Always use a real physical iOS device for final push notification testing and for any issue involving APNs connectivity.
What causes 'SENDER_ID_MISMATCH' errors in FCM?
This error means the FCM token was registered with a different Sender ID (project number) than the one you are using to send. This happens when the google-services.json or GoogleService-Info.plist in the app does not match the Firebase project you are sending from. Re-download the config files from the correct Firebase project and rebuild.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation