<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Notify sphere</title>
    <description>The latest articles on DEV Community by Notify sphere (@notifysphere).</description>
    <link>https://dev.to/notifysphere</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4178987%2F92cdf39c-900d-4a3f-846c-63c459f1aeb5.png</url>
      <title>DEV Community: Notify sphere</title>
      <link>https://dev.to/notifysphere</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/notifysphere"/>
    <language>en</language>
    <item>
      <title>Firebase iOS Push Notifications: APNs Key and SDK Setup</title>
      <dc:creator>Notify sphere</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:36:08 +0000</pubDate>
      <link>https://dev.to/notifysphere/firebase-ios-push-notifications-apns-key-and-sdk-setup-2p21</link>
      <guid>https://dev.to/notifysphere/firebase-ios-push-notifications-apns-key-and-sdk-setup-2p21</guid>
      <description>&lt;p&gt;Firebase Cloud Messaging (FCM) can deliver push notifications to iPhones, but it doesn't talk to iOS devices directly — it goes through Apple Push Notification service (APNs). Most “Firebase iOS push isn't working” problems come from the Apple side of that handshake. This guide sets up both sides in order.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Firebase push works on iOS
&lt;/h2&gt;

&lt;p&gt;Your app registers with APNs and receives an APNs device token. The Firebase iOS SDK maps that token to an FCM registration token, which is the one your server uses. When you send a message, FCM authenticates with APNs using the key you uploaded, and APNs delivers it to the device. If Firebase can't authenticate with APNs, nothing arrives — even though everything looks fine in your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  A paid Apple Developer Program membership — push needs one.&lt;/li&gt;
&lt;li&gt;  A Firebase project with your iOS app added, and its &lt;code&gt;GoogleService-Info.plist&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Xcode and a physical iPhone or iPad. The Simulator isn't a reliable test for remote push.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Create an APNs authentication key
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; In the Apple Developer portal, open &lt;strong&gt;Certificates, Identifiers &amp;amp; Profiles → Keys&lt;/strong&gt; and create a new key.&lt;/li&gt;
&lt;li&gt; Enable &lt;strong&gt;Apple Push Notifications service (APNs)&lt;/strong&gt; for the key, then register it.&lt;/li&gt;
&lt;li&gt; Download the &lt;code&gt;.p8&lt;/code&gt; file and note its &lt;strong&gt;Key ID&lt;/strong&gt;. Apple lets you download it only once, so store it somewhere safe.&lt;/li&gt;
&lt;li&gt; Note your &lt;strong&gt;Team ID&lt;/strong&gt;, shown in your developer account's membership details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An authentication key doesn't expire like a push certificate, and one key works for all your apps — which is why it's the recommended option over the older &lt;code&gt;.p12&lt;/code&gt; certificates.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Upload the key to Firebase
&lt;/h2&gt;

&lt;p&gt;In the Firebase console, open &lt;strong&gt;Project settings → Cloud Messaging&lt;/strong&gt;. Under your Apple app, upload the &lt;code&gt;.p8&lt;/code&gt; key and enter the Key ID and Team ID. Firebase uses this key to authenticate with APNs on your behalf.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Add the Firebase iOS SDK
&lt;/h2&gt;

&lt;p&gt;In Xcode, choose &lt;strong&gt;File → Add Package Dependencies&lt;/strong&gt; and add &lt;code&gt;https://github.com/firebase/firebase-ios-sdk&lt;/code&gt;. Select the &lt;strong&gt;FirebaseMessaging&lt;/strong&gt; product. Then drag &lt;code&gt;GoogleService-Info.plist&lt;/code&gt; into your app target.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Enable capabilities
&lt;/h2&gt;

&lt;p&gt;Select your app target, open &lt;strong&gt;Signing &amp;amp; Capabilities&lt;/strong&gt;, and add &lt;strong&gt;Push Notifications&lt;/strong&gt;. Add &lt;strong&gt;Background Modes&lt;/strong&gt; and check &lt;strong&gt;Remote notifications&lt;/strong&gt; if you send silent or data-only pushes.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Request permission and get the FCM token
&lt;/h2&gt;

&lt;p&gt;Configure Firebase at launch, ask the user for permission, register for remote notifications, and listen for the FCM token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UIKit&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FirebaseCore&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FirebaseMessaging&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UserNotifications&lt;/span&gt;

&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;AppDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIResponder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;UIApplicationDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="kt"&gt;UNUserNotificationCenterDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;MessagingDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;didFinishLaunchingWithOptions&lt;/span&gt; &lt;span class="nv"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;LaunchOptionsKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;FirebaseApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kt"&gt;Messaging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
    &lt;span class="kt"&gt;UNUserNotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;

    &lt;span class="kt"&gt;UNUserNotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;granted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="c1"&gt;// Respect the user's choice; you can ask again later from settings&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerForRemoteNotifications&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Called with a new or refreshed FCM registration token&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Messaging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;didReceiveRegistrationToken&lt;/span&gt; &lt;span class="nv"&gt;fcmToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fcmToken&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Send this token to your push server&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FCM token: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;fcmToken&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Show notifications while the app is in the foreground&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;userNotificationCenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UNUserNotificationCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="n"&gt;willPresent&lt;/span&gt; &lt;span class="nv"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UNNotification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;UNNotificationPresentationOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the Firebase SDK uses method swizzling to pass the APNs token to FCM automatically. If you set &lt;code&gt;FirebaseAppDelegateProxyEnabled&lt;/code&gt; to &lt;code&gt;NO&lt;/code&gt; in your &lt;code&gt;Info.plist&lt;/code&gt;, you must pass the APNs token yourself by setting &lt;code&gt;Messaging.messaging().apnsToken&lt;/code&gt; in &lt;code&gt;didRegisterForRemoteNotificationsWithDeviceToken&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Send a test notification
&lt;/h2&gt;

&lt;p&gt;Run the app on a physical device, accept the permission prompt, and copy the FCM token from the console. In the Firebase console, open &lt;strong&gt;Messaging&lt;/strong&gt;, create a notification, and use &lt;strong&gt;Send test message&lt;/strong&gt; with that token. Test with the app in the foreground, in the background, and fully closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Firebase iOS push isn't working
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;No APNs key in Firebase:&lt;/strong&gt; the token is generated, but nothing is delivered. Check Project settings → Cloud Messaging.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Wrong Team ID or Key ID:&lt;/strong&gt; APNs rejects Firebase's requests. Re-enter both from your Apple developer account.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bundle ID mismatch:&lt;/strong&gt; the iOS app in Firebase must use exactly the same bundle ID as your Xcode target.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Push Notifications capability missing:&lt;/strong&gt; the app never receives an APNs token, so no FCM token works.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Swizzling disabled without passing the APNs token:&lt;/strong&gt; FCM has no APNs token to map.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Permission denied:&lt;/strong&gt; the user declined the prompt; notifications are delivered silently or not shown.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using React Native or Flutter?
&lt;/h2&gt;

&lt;p&gt;The Apple-side steps — APNs key, Firebase upload, and capabilities — are the same. The notifySphere SDKs handle the token and permission code for you: see the &lt;a href="https://notifysphere.net/blog/react-native-push-notifications" rel="noopener noreferrer"&gt;React Native guide&lt;/a&gt; and the &lt;a href="https://notifysphere.net/blog/flutter-push-notifications" rel="noopener noreferrer"&gt;Flutter guide&lt;/a&gt;. notifySphere runs on Firebase Cloud Messaging, so once your Firebase project can reach APNs, uploading its service account lets you send segmented iOS, Android, and web campaigns from one dashboard.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://notifysphere.net/blog/firebase-ios-push-notifications" rel="noopener noreferrer"&gt;notifySphere blog&lt;/a&gt;. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;free up to 1,000 users&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
      <category>notifications</category>
    </item>
    <item>
      <title>WhatsApp BSP in India: What It Is, Top Providers, Charges and How to Choose</title>
      <dc:creator>Notify sphere</dc:creator>
      <pubDate>Mon, 02 Nov 2026 06:18:33 +0000</pubDate>
      <link>https://dev.to/notifysphere/whatsapp-bsp-in-india-what-it-is-top-providers-charges-and-how-to-choose-25do</link>
      <guid>https://dev.to/notifysphere/whatsapp-bsp-in-india-what-it-is-top-providers-charges-and-how-to-choose-25do</guid>
      <description>&lt;p&gt;If you want to send WhatsApp messages from your own software, you'll quickly run into the term “BSP”. Here's what a WhatsApp Business Solution Provider actually does, how Meta's partner types differ, what they charge, and how to pick one without overpaying.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a WhatsApp BSP?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;WhatsApp Business Solution Provider (BSP)&lt;/strong&gt; is a company that helps businesses access the WhatsApp Business Platform — the API version of WhatsApp. A BSP typically handles onboarding your business and phone number, gives you a dashboard to manage message templates and send campaigns, connects WhatsApp to your other tools, and supports you when something breaks.&lt;/p&gt;

&lt;p&gt;Meta now calls these companies &lt;strong&gt;Solution Partners&lt;/strong&gt;, but “BSP” is still the term most people search for and use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you need a BSP?
&lt;/h2&gt;

&lt;p&gt;Not strictly. Meta hosts the WhatsApp Cloud API, and any developer can call it directly with a Meta Business account, a verified phone number, and an access token. Going direct means no provider fee — but you build everything else yourself: template management, a send UI, contact lists, opt-in tracking, delivery reports, a shared inbox, and retries.&lt;/p&gt;

&lt;p&gt;A provider makes sense when you want those pieces ready-made, when non-developers need to send campaigns, or when you want WhatsApp inside a wider engagement platform alongside push, email, or support.&lt;/p&gt;

&lt;h2&gt;
  
  
  WhatsApp BSP vs the WhatsApp Business app
&lt;/h2&gt;

&lt;p&gt;The free WhatsApp Business app and a BSP solve different problems. The app is for a person replying to customers by hand from a phone. The API, which you reach directly or through a BSP, is for software sending messages: OTPs, order updates, reminders, and campaigns to thousands of people.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;WhatsApp Business app&lt;/th&gt;
&lt;th&gt;WhatsApp Business API via a BSP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who sends&lt;/td&gt;
&lt;td&gt;A person, from a phone&lt;/td&gt;
&lt;td&gt;Your backend, dashboard, or automations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bulk and automated messages&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, with approved templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integrations and webhooks&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Meta's per-message rate plus the provider's fee&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A phone number registered on the API can't be used in the regular WhatsApp or WhatsApp Business app at the same time, so many businesses use a separate number for the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Partner vs Tech Provider vs Tech Partner
&lt;/h2&gt;

&lt;p&gt;Meta's partner program has three types. The difference matters mostly for how you're billed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What they do&lt;/th&gt;
&lt;th&gt;Who pays Meta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Solution Partner&lt;/strong&gt; (the classic “BSP”)&lt;/td&gt;
&lt;td&gt;Full WhatsApp services: onboarding, messaging, billing, support&lt;/td&gt;
&lt;td&gt;The partner can extend its credit line and invoice you for Meta's charges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tech Provider&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full WhatsApp services, on their own or with a Solution Partner&lt;/td&gt;
&lt;td&gt;You add your own payment method to your WhatsApp Business Account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tech Partner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Builds add-on solutions on top of the platform&lt;/td&gt;
&lt;td&gt;Depends on the joint solution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  WhatsApp BSPs in India: the main options
&lt;/h2&gt;

&lt;p&gt;There are dozens of WhatsApp providers in India. Most businesses end up choosing between these, and the right one depends on who will use it and what you send:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Best suited to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gupshup&lt;/td&gt;
&lt;td&gt;Large brands and developers who want a mature messaging API and chatbot tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interakt&lt;/td&gt;
&lt;td&gt;Small businesses and D2C stores that want a ready dashboard, catalogue and Shopify-style integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AiSensy&lt;/td&gt;
&lt;td&gt;Small teams sending broadcast campaigns and running simple chatbots without code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WATI&lt;/td&gt;
&lt;td&gt;Support teams that need a shared inbox where several agents answer WhatsApp chats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twilio&lt;/td&gt;
&lt;td&gt;Developers building WhatsApp into their own product with a global, pay-as-you-go API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exotel&lt;/td&gt;
&lt;td&gt;Businesses that already use cloud calling and want WhatsApp alongside it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;notifySphere&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mobile apps that want WhatsApp, push notifications, install attribution and in-app support in one dashboard, with Meta's rate passed through at cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All of them send through the same WhatsApp Business Platform, so message delivery and Meta's rates are the same. What differs is the dashboard, the integrations, the support, and the fee on top. Shortlist two or three by fit, then compare their fees with the table below.&lt;/p&gt;

&lt;h2&gt;
  
  
  How WhatsApp BSP pricing works
&lt;/h2&gt;

&lt;p&gt;Your WhatsApp bill always has two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Meta's per-message charge.&lt;/strong&gt; Set by Meta, by template category (marketing, utility, authentication) and recipient country. Every provider pays the same Meta rate.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The provider's fee.&lt;/strong&gt; A monthly platform fee, a markup on each message, or both. This is the only part that differs between providers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So when comparing BSPs, ignore the headline per-message price and work out the markup over Meta's rate. Meta's October 2026 India rate card lists marketing templates at ₹0.8631 and utility, authentication and service messages at ₹0.115 per message, before GST. See &lt;a href="https://notifysphere.net/blog/whatsapp-api-changes-2026" rel="noopener noreferrer"&gt;what changed in October 2026&lt;/a&gt; and &lt;a href="https://notifysphere.net/blog/whatsapp-api-pricing-india" rel="noopener noreferrer"&gt;what a monthly bill looks like in India&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What providers charge in India
&lt;/h2&gt;

&lt;p&gt;Per-message pricing published by common providers, checked in October 2026 (excluding GST):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Marketing&lt;/th&gt;
&lt;th&gt;Utility&lt;/th&gt;
&lt;th&gt;Authentication&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AiSensy&lt;/td&gt;
&lt;td&gt;₹1.09&lt;/td&gt;
&lt;td&gt;₹0.145&lt;/td&gt;
&lt;td&gt;₹0.145&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interakt&lt;/td&gt;
&lt;td&gt;₹0.949–₹0.970 (by plan)&lt;/td&gt;
&lt;td&gt;₹0.160&lt;/td&gt;
&lt;td&gt;₹0.129&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gupshup&lt;/td&gt;
&lt;td&gt;Meta rate + $0.001 per message&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twilio&lt;/td&gt;
&lt;td&gt;Meta rate + $0.005 per message, inbound and outbound&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;notifySphere&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Meta rate + ₹0.04&lt;/td&gt;
&lt;td&gt;Meta rate + ₹0.02&lt;/td&gt;
&lt;td&gt;Meta rate + ₹0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Prices change — confirm on each provider's pricing page. Platform subscription fees are charged separately by some providers and aren't included above.&lt;/p&gt;

&lt;p&gt;Markups add up quickly at volume. At 10,000 marketing and 20,000 utility messages a month, a 26% markup on Meta's rate costs about ₹2,800 more than paying Meta's rate alone, before any platform fee.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose a WhatsApp BSP
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Transparent pricing:&lt;/strong&gt; can you see Meta's rate and the provider's fee separately?&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Your own WhatsApp Business Account:&lt;/strong&gt; make sure the account and phone number belong to you, so you can switch providers later without losing them.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;API and webhooks:&lt;/strong&gt; if your backend sends OTPs or order updates, check the API docs and delivery webhooks before signing up.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Template management:&lt;/strong&gt; submitting templates and tracking approval in one place saves real time.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Opt-in and compliance:&lt;/strong&gt; look for consent tracking and easy opt-out handling.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Other channels:&lt;/strong&gt; if you also send push notifications or run support, one platform avoids a second vendor and a second customer record.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Billing model:&lt;/strong&gt; decide whether you want the provider to invoice Meta's charges, or to pay Meta directly with your own card.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Can you switch WhatsApp BSPs later?
&lt;/h2&gt;

&lt;p&gt;Yes. Meta supports moving a phone number from one WhatsApp Business Account to another, so you aren't locked in for good. Switching is easiest when the WhatsApp Business Account is in your own name from day one. Before you move, export your contacts and opt-in records, list the templates you rely on, and plan for a short window where sending is paused while the number moves across.&lt;/p&gt;

&lt;h2&gt;
  
  
  WhatsApp on notifySphere
&lt;/h2&gt;

&lt;p&gt;notifySphere connects to your own WhatsApp Business Account and adds template management, campaign sending, delivery and read receipts, consent tracking, and a support inbox — alongside push notifications and app attribution in the same dashboard. Meta's rate is passed through at cost, with a processing fee of ₹0.01–₹0.04 per message. See &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;, or read the &lt;a href="https://notifysphere.net/blog/whatsapp-business-api-guide" rel="noopener noreferrer"&gt;WhatsApp Business API developer guide&lt;/a&gt;. Sending one-time passwords? See the &lt;a href="https://notifysphere.net/blog/whatsapp-otp-api" rel="noopener noreferrer"&gt;WhatsApp OTP API guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What does BSP stand for in WhatsApp?
&lt;/h3&gt;

&lt;p&gt;BSP stands for Business Solution Provider: a company that gives businesses access to the WhatsApp Business Platform (the API), usually with a dashboard, template management, and support. Meta now calls them Solution Partners.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a BSP to use the WhatsApp Business API?
&lt;/h3&gt;

&lt;p&gt;No. Meta's Cloud API can be called directly with a Meta Business account, a verified phone number, and an access token. A provider is useful when you want a ready-made dashboard, campaigns, contact management, and support instead of building them yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does a WhatsApp BSP charge in India?
&lt;/h3&gt;

&lt;p&gt;Every provider pays Meta the same per-message rate. What differs is the provider's markup or platform fee on top. Published markups in India range from a few paise to over ₹0.20 per marketing message. notifySphere passes Meta's rate through at cost and adds a processing fee of ₹0.01 to ₹0.04 per message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who are the main WhatsApp BSPs in India?
&lt;/h3&gt;

&lt;p&gt;Commonly used WhatsApp Business API providers in India include Gupshup, Interakt, AiSensy, WATI, Twilio, Exotel and notifySphere. They all send through Meta's WhatsApp Business Platform, so they differ mainly in dashboard, integrations, support and the fee they add on top of Meta's rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is a WhatsApp BSP the same as a WhatsApp Business API provider?
&lt;/h3&gt;

&lt;p&gt;Yes, in everyday use. BSP (Business Solution Provider) is the older name; Meta now calls these companies Solution Partners or Tech Providers. Any of them gives you access to the WhatsApp Business API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which is the cheapest WhatsApp BSP in India?
&lt;/h3&gt;

&lt;p&gt;Compare the markup over Meta's rate, not the headline price, and include any monthly platform fee. Of the providers compared above, notifySphere has the lowest per-message processing fee. Prices change, so confirm on each provider's pricing page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the same number in the WhatsApp Business app and the API?
&lt;/h3&gt;

&lt;p&gt;Not at the same time. Once a number is registered on the WhatsApp Business Platform it can't be used in the regular WhatsApp or WhatsApp Business app, so many businesses use a separate number for the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I change my WhatsApp BSP later?
&lt;/h3&gt;

&lt;p&gt;Yes. Meta supports moving a phone number between WhatsApp Business Accounts. Keeping the account in your own business's name makes the move much simpler.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://notifysphere.net/blog/whatsapp-bsp" rel="noopener noreferrer"&gt;notifySphere blog&lt;/a&gt;. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;free up to 1,000 users&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>whatsapp</category>
      <category>api</category>
      <category>webdev</category>
      <category>business</category>
    </item>
    <item>
      <title>Flutter Push Notifications Not Received in Background or When App Is Killed: Fixes</title>
      <dc:creator>Notify sphere</dc:creator>
      <pubDate>Wed, 28 Oct 2026 06:37:22 +0000</pubDate>
      <link>https://dev.to/notifysphere/flutter-push-notifications-not-received-in-background-or-when-app-is-killed-fixes-j3a</link>
      <guid>https://dev.to/notifysphere/flutter-push-notifications-not-received-in-background-or-when-app-is-killed-fixes-j3a</guid>
      <description>&lt;p&gt;Your Flutter app gets push notifications while it's open, but nothing shows up once it's in the background or closed. This is one of the most common Firebase Cloud Messaging problems, and it almost always comes down to a handful of causes. Here they are, from most to least likely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  The background handler is a &lt;strong&gt;top-level function&lt;/strong&gt; with &lt;code&gt;@pragma('vm:entry-point')&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;FirebaseMessaging.onBackgroundMessage()&lt;/code&gt; is registered &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;runApp()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  The message has a &lt;strong&gt;notification&lt;/strong&gt; block, or is data-only with &lt;strong&gt;high priority&lt;/strong&gt; (Android) and &lt;code&gt;content-available&lt;/code&gt; (iOS).&lt;/li&gt;
&lt;li&gt;  Notification permission is granted (Android 13+ and iOS both ask).&lt;/li&gt;
&lt;li&gt;  On iOS: &lt;strong&gt;Push Notifications&lt;/strong&gt; and &lt;strong&gt;Background Modes → Remote notifications&lt;/strong&gt; are enabled, and the APNs key is uploaded to Firebase.&lt;/li&gt;
&lt;li&gt;  You're testing on a real device in a &lt;strong&gt;release or profile build&lt;/strong&gt;, and the app wasn't force-stopped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Set up the background handler correctly
&lt;/h2&gt;

&lt;p&gt;When your app isn't in the foreground, &lt;code&gt;firebase_messaging&lt;/code&gt; runs your handler in a separate Dart isolate. That only works if Flutter can find the function by itself, so it has to be a top-level function (not inside a class) and marked as an entry point. Otherwise tree shaking in release builds can remove it, and messages silently do nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_core/firebase_core.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_messaging/firebase_messaging.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Must be a top-level function, not a class method or closure&lt;/span&gt;
&lt;span class="nd"&gt;@pragma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'vm:entry-point'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;firebaseMessagingBackgroundHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RemoteMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Runs in its own isolate, so initialise Firebase again here&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Background message: &lt;/span&gt;&lt;span class="si"&gt;${message.messageId}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Register before runApp()&lt;/span&gt;
  &lt;span class="n"&gt;FirebaseMessaging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onBackgroundMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firebaseMessagingBackgroundHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the handler runs in its own isolate, it can't touch your widgets, providers or in-memory state. If you use other Firebase services inside it, call &lt;code&gt;Firebase.initializeApp()&lt;/code&gt; there too.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Send the right kind of message
&lt;/h2&gt;

&lt;p&gt;FCM has two kinds of messages, and they behave very differently in the background:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Notification messages&lt;/strong&gt; (with a &lt;code&gt;notification&lt;/code&gt; block) are displayed by the operating system itself when your app is in the background or closed. Your Dart code doesn't have to run for the user to see them. This is what you want for anything user-facing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Data-only messages&lt;/strong&gt; (just a &lt;code&gt;data&lt;/code&gt; block) display nothing on their own. They wake your background handler, and only if the platform agrees to deliver them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a notification the user must see, send something like this through the FCM HTTP v1 API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEVICE_FCM_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"notification"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your order is out for delivery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Arriving in about 20 minutes"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4821"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"android"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"notification"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"channel_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high_importance"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apns-priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"aps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sound"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you really need a silent data-only message, mark it high priority on Android and as a background push on iOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEVICE_FCM_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sync"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4821"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"android"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apns-push-type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apns-priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"aps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"content-available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can build and check both payloads with our free &lt;a href="https://notifysphere.net/tools/fcm-payload-builder" rel="noopener noreferrer"&gt;FCM payload builder&lt;/a&gt;, which also gives you the cURL command.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Ask for notification permission
&lt;/h2&gt;

&lt;p&gt;Since Android 13, apps need the &lt;code&gt;POST_NOTIFICATIONS&lt;/code&gt; runtime permission, and iOS has always needed one. Without it, messages are delivered to the device but never shown. Ask once, at a sensible moment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FirebaseMessaging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requestPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;alert:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;badge:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;sound:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Permission: &lt;/span&gt;&lt;span class="si"&gt;${settings.authorizationStatus}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the status comes back as &lt;code&gt;denied&lt;/code&gt;, the system won't show the dialog again, so point the user to the app's notification settings instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Android: battery savers and force stop
&lt;/h2&gt;

&lt;p&gt;If notifications arrive on a Pixel but not on some Xiaomi, Oppo, Vivo, Realme, OnePlus or Samsung phones, the phone's battery optimisation is likely stopping your app in the background. Things to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Force stop&lt;/strong&gt; from Settings blocks every FCM message until the user opens the app again. A normal swipe from recents shouldn't, but some brands treat it like a force stop.&lt;/li&gt;
&lt;li&gt;  Use &lt;strong&gt;high priority&lt;/strong&gt; for time-sensitive messages. Normal priority can be delayed while the phone is in Doze mode.&lt;/li&gt;
&lt;li&gt;  Create a &lt;strong&gt;notification channel with high importance&lt;/strong&gt; and send its &lt;code&gt;channel_id&lt;/code&gt;, or the notification may arrive silently without a heads-up banner.&lt;/li&gt;
&lt;li&gt;  For testing, set the app's battery usage to &lt;strong&gt;Unrestricted&lt;/strong&gt; and turn on Autostart where the phone has it. You can't do this for your users, but it confirms the cause.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. iOS: capabilities, APNs and how the app was closed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  In Xcode, under Signing &amp;amp; Capabilities, add &lt;strong&gt;Push Notifications&lt;/strong&gt; and &lt;strong&gt;Background Modes&lt;/strong&gt; with &lt;em&gt;Remote notifications&lt;/em&gt; ticked.&lt;/li&gt;
&lt;li&gt;  Upload your APNs authentication key in the Firebase console (Project settings → Cloud Messaging). Without it, nothing reaches iOS at all. The &lt;a href="https://notifysphere.net/blog/firebase-ios-push-notifications" rel="noopener noreferrer"&gt;Firebase iOS push guide&lt;/a&gt; walks through it.&lt;/li&gt;
&lt;li&gt;  Background data messages are throttled by iOS and aren't delivered at all if the user swiped the app away. Notification messages are still shown in that case.&lt;/li&gt;
&lt;li&gt;  If you see &lt;code&gt;apns-token-not-set&lt;/code&gt;, the device never got an APNs token. See &lt;a href="https://notifysphere.net/blog/no-apns-token-specified-before-fetching-fcm-token" rel="noopener noreferrer"&gt;how to fix the APNs token error&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Test the right way
&lt;/h2&gt;

&lt;p&gt;Debug builds behave differently from what your users run. When you stop the app from your IDE, the process is killed in a way that real users never do, and background messages may not arrive. Test background and terminated states on a real device with &lt;code&gt;flutter run --release&lt;/code&gt; (or a profile build), close the app the way a user would, then send a message.&lt;/p&gt;

&lt;p&gt;To handle taps, use &lt;code&gt;FirebaseMessaging.onMessageOpenedApp&lt;/code&gt; for a tap while the app is in the background, and &lt;code&gt;FirebaseMessaging.instance.getInitialMessage()&lt;/code&gt; for a tap that launched the app from closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want this handled for you?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://notifysphere.net/blog/flutter-push-notifications" rel="noopener noreferrer"&gt;notifySphere Flutter SDK&lt;/a&gt; handles token registration and wires your background handler in at startup, and it tracks delivery and opens for every notification, so you can see whether a message reached the phone or was dropped on the way. It's free up to 1,000 monthly active users. Compare it with other options on our &lt;a href="https://notifysphere.net/vs/onesignal-alternative" rel="noopener noreferrer"&gt;OneSignal alternatives&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why do Flutter notifications work in the foreground but not in the background?
&lt;/h3&gt;

&lt;p&gt;Usually one of four things: the background handler isn't a top-level function marked &lt;a class="mentioned-user" href="https://dev.to/pragma"&gt;@pragma&lt;/a&gt;('vm:entry-point'), it's registered after runApp(), the message is data-only without high priority, or the phone's battery saver is stopping your app. Fix them in that order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does onBackgroundMessage not get called on iOS?
&lt;/h3&gt;

&lt;p&gt;For a data-only message, iOS needs content-available: 1 in the aps payload and the Background Modes capability with Remote notifications enabled. Even then iOS throttles background messages and won't deliver them if the user swiped the app away. For anything the user must see, send a notification payload instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do push notifications arrive if the user force-stops or swipes away the app?
&lt;/h3&gt;

&lt;p&gt;On Android, force stop from Settings blocks all FCM messages until the user opens the app again; a normal swipe from recents does not, except on some phone brands with aggressive battery savers. On iOS, notification messages are still shown after a swipe, but background data messages are not delivered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I update the UI from onBackgroundMessage?
&lt;/h3&gt;

&lt;p&gt;No. The background handler runs in a separate isolate with no access to your widgets or app state. Save what you need (for example with shared_preferences) and read it when the app opens, or use onMessageOpenedApp and getInitialMessage to react to taps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are notifications not showing when the app is open?
&lt;/h3&gt;

&lt;p&gt;That's expected. In the foreground, Android doesn't display FCM notifications on its own, so you show them yourself with flutter_local_notifications. On iOS, call setForegroundNotificationPresentationOptions(alert: true, badge: true, sound: true).&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://notifysphere.net/blog/flutter-push-notifications-not-received-in-background" rel="noopener noreferrer"&gt;notifySphere blog&lt;/a&gt;. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;free up to 1,000 users&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
      <category>flutter</category>
    </item>
    <item>
      <title>React Native Push Notifications: A Step-by-Step Guide</title>
      <dc:creator>Notify sphere</dc:creator>
      <pubDate>Thu, 22 Oct 2026 05:35:22 +0000</pubDate>
      <link>https://dev.to/notifysphere/react-native-push-notifications-a-step-by-step-guide-aap</link>
      <guid>https://dev.to/notifysphere/react-native-push-notifications-a-step-by-step-guide-aap</guid>
      <description>&lt;p&gt;Push notifications in React Native come down to three pieces: Firebase Cloud Messaging (FCM) to deliver messages, native setup on Android and iOS, and JavaScript that registers the device and reacts to notifications. This guide walks through all three with the notifySphere React Native SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  How React Native push notifications work
&lt;/h2&gt;

&lt;p&gt;Each device gets a push token from FCM. Your app sends that token to a server — here, notifySphere — along with the user it belongs to. When you send a campaign, the server asks FCM to deliver it, and FCM reaches Android directly and iOS through Apple Push Notification service (APNs). One Firebase project covers both platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  React Native 0.70 or newer.&lt;/li&gt;
&lt;li&gt;  A Firebase project with Cloud Messaging enabled.&lt;/li&gt;
&lt;li&gt;  A notifySphere app with an App ID and API token, and your Firebase service account uploaded under &lt;strong&gt;Settings → Messaging&lt;/strong&gt; (see &lt;a href="https://notifysphere.net/docs/firebase-credentials" rel="noopener noreferrer"&gt;Firebase credentials&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;  A physical iPhone for iOS testing — push doesn't work on the iOS Simulator.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Install the SDK and its dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-native-notify-sphere
npm &lt;span class="nb"&gt;install&lt;/span&gt; @react-native-firebase/app @react-native-firebase/messaging
npm &lt;span class="nb"&gt;install&lt;/span&gt; @notifee/react-native
npm &lt;span class="nb"&gt;install&lt;/span&gt; @react-native-async-storage/async-storage@^1.23.1
npm &lt;span class="nb"&gt;install &lt;/span&gt;react-native-device-info react-native-install-referrer
&lt;span class="nb"&gt;cd &lt;/span&gt;ios &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pod &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pin AsyncStorage to v1 as shown. Version 2 needs a custom Maven repository that most React Native projects don't have configured.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Configure Android
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Download &lt;code&gt;google-services.json&lt;/code&gt; from the Firebase console into &lt;code&gt;android/app/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Apply the Google Services Gradle plugin.&lt;/li&gt;
&lt;li&gt;  Add the &lt;code&gt;POST_NOTIFICATIONS&lt;/code&gt; permission — Android 13 and later require it to show notifications.&lt;/li&gt;
&lt;li&gt;  Add a small notification icon. Android silently drops notifications that don't have one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Configure iOS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Add &lt;code&gt;GoogleService-Info.plist&lt;/code&gt; to your Xcode project.&lt;/li&gt;
&lt;li&gt;  Under &lt;strong&gt;Signing &amp;amp; Capabilities&lt;/strong&gt;, enable &lt;strong&gt;Push Notifications&lt;/strong&gt; and &lt;strong&gt;Background Modes → Remote notifications&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  Configure Firebase and the notification center delegate in your AppDelegate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Register the background handler
&lt;/h2&gt;

&lt;p&gt;Notifications that arrive while the app is in the background or closed are handled before your React tree mounts. Register the handler synchronously in &lt;code&gt;index.js&lt;/code&gt;, before &lt;code&gt;registerComponent()&lt;/code&gt; — if it's wrapped in a promise or timeout, those notifications are dropped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppRegistry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;appName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-notify-sphere&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;API_TOKEN&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Must run synchronously, before registerComponent()&lt;/span&gt;
&lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBackgroundHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_TOKEN&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;AppRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Register the device and handle notifications
&lt;/h2&gt;

&lt;p&gt;Call &lt;code&gt;initialize()&lt;/code&gt; when the app mounts. It's safe to call on every launch — it only re-registers when the FCM token or user details change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/App.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Platform&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-notify-sphere&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;APP_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-notifysphere-app-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-api-token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PUSH_TYPE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AndroidPush&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IOSPush&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;applicationUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// your user's ID&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PUSH_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;free&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;__DEV__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNotification&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// type: "received" | "press" | "opened" | "initial"&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;press&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// navigate to the screen this notification is about&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...render your app&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Tag users for segmentation
&lt;/h2&gt;

&lt;p&gt;Tags let you target campaigns at specific groups — users in one city, users on a plan, users who haven't ordered in 30 days. Update them without re-registering the device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateTags&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;applicationUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PUSH_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mumbai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastOrderAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Send a test notification
&lt;/h2&gt;

&lt;p&gt;Run the app on a physical device, accept the notification permission, then send a test push from the dashboard. Check three states: app open (foreground), app in the background, and app fully closed. If the closed-app case fails, the background handler almost always isn't registered early enough.&lt;/p&gt;

&lt;p&gt;dashboard.notifysphere.net&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbnuyrdwt1hs8ukp34d1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbnuyrdwt1hs8ukp34d1f.png" alt="notifySphere dashboard with active subscriptions, app subscribers, monthly active users, and push sends"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once devices register, subscriptions, monthly active users, and push sends show up on the dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Handle sign-out and account switching
&lt;/h2&gt;

&lt;p&gt;A push token belongs to the device, not the user. If someone signs out and a different person signs in on the same phone, the server can keep sending the first user's notifications to that device unless you detach it. &lt;code&gt;destroy()&lt;/code&gt; only removes local listeners, so on sign-out call &lt;code&gt;logout()&lt;/code&gt; instead: it unsubscribes the device on the server, deletes the FCM token and clears cached user data. It doesn't clear tags, so when the new user signs in, call &lt;code&gt;initialize()&lt;/code&gt; with that user's ID and their own tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// On sign-out: detach this device from the user (SDK 1.3.0+)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onSignOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// ...then clear your own session&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// On sign-in: register the device for the new user&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onSignIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;applicationUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PUSH_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test it on one device, because foreground, background and closed-app checks won't catch this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Sign in as User A and send a push to A. It should arrive.&lt;/li&gt;
&lt;li&gt; Sign out, then send to A again. Nothing should arrive on this device.&lt;/li&gt;
&lt;li&gt; Sign in as User B. A push to B should arrive; a push to A still shouldn't.&lt;/li&gt;
&lt;li&gt; Check that B's tags and segments carry nothing over from A.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thanks to Dave Kurian, who suggested this test in the comments of this guide on &lt;a href="https://dev.to/notifysphere/react-native-push-notifications-a-step-by-step-guide-aap"&gt;DEV&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common problems
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Nothing arrives on iOS:&lt;/strong&gt; you're on the Simulator, or the Push Notifications capability is missing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Nothing arrives on Android 13+:&lt;/strong&gt; the user never granted the notification permission.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Arrives in foreground only:&lt;/strong&gt; the background handler is registered too late.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Android shows nothing, no error:&lt;/strong&gt; the small notification icon is missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://notifysphere.net/docs/react-native" rel="noopener noreferrer"&gt;React Native SDK reference&lt;/a&gt; covers every method and option. Building in Flutter? See the &lt;a href="https://notifysphere.net/blog/flutter-push-notifications" rel="noopener noreferrer"&gt;Flutter push notifications guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Notifications arriving late rather than not at all? See &lt;a href="https://notifysphere.net/blog/real-time-push-notification-sdk" rel="noopener noreferrer"&gt;why push notifications arrive late and how to fix it&lt;/a&gt;. Comparing push providers? Read &lt;a href="https://notifysphere.net/vs/onesignal-alternative" rel="noopener noreferrer"&gt;notifySphere vs OneSignal and other OneSignal alternatives&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://notifysphere.net/blog/react-native-push-notifications" rel="noopener noreferrer"&gt;notifySphere blog&lt;/a&gt;. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;free up to 1,000 users&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
      <category>notifications</category>
    </item>
    <item>
      <title>Flutter Push Notifications: A Step-by-Step Guide</title>
      <dc:creator>Notify sphere</dc:creator>
      <pubDate>Wed, 14 Oct 2026 11:42:07 +0000</pubDate>
      <link>https://dev.to/notifysphere/flutter-push-notifications-a-step-by-step-guide-34f1</link>
      <guid>https://dev.to/notifysphere/flutter-push-notifications-a-step-by-step-guide-34f1</guid>
      <description>&lt;p&gt;Flutter push notifications run on Firebase Cloud Messaging (FCM) for both Android and iOS. The Dart side is short; most of the work is native setup — and on iOS, one step that many guides skip decides whether you can tell if a notification was ever delivered.&lt;/p&gt;

&lt;h2&gt;
  
  
  How push notifications work in Flutter
&lt;/h2&gt;

&lt;p&gt;Your app gets a device token from FCM and sends it to your push server along with the user it belongs to. When you send a campaign, the server asks FCM to deliver it. FCM reaches Android devices directly and iPhones through Apple Push Notification service (APNs), using the APNs key you upload to Firebase.&lt;/p&gt;

&lt;p&gt;This guide uses &lt;code&gt;flutter_notify_sphere&lt;/code&gt;, the notifySphere Flutter SDK, which handles registration and reports when each notification is delivered and tapped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Dart 3.9 or newer.&lt;/li&gt;
&lt;li&gt;  A Firebase project with Cloud Messaging enabled, and your APNs .p8 key uploaded in its Cloud Messaging settings.&lt;/li&gt;
&lt;li&gt;  A notifySphere app with an App ID and API token, with your Firebase service account uploaded (see &lt;a href="https://notifysphere.net/docs/push-setup" rel="noopener noreferrer"&gt;push setup&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;  A physical iPhone — push doesn't work on the iOS Simulator.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Add the packages
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter&lt;/span&gt;
  &lt;span class="na"&gt;flutter_notify_sphere&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.0&lt;/span&gt;
  &lt;span class="na"&gt;firebase_core&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^4.3.0&lt;/span&gt;
  &lt;span class="na"&gt;firebase_messaging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^16.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use these Firebase versions or newer within the same major version. Older &lt;code&gt;firebase_core&lt;/code&gt; and &lt;code&gt;firebase_messaging&lt;/code&gt; releases won't resolve alongside the SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Configure Android
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Put &lt;code&gt;google-services.json&lt;/code&gt; in &lt;code&gt;android/app/&lt;/code&gt; and apply the Google Services Gradle plugin.&lt;/li&gt;
&lt;li&gt;  Add the &lt;code&gt;INTERNET&lt;/code&gt;, &lt;code&gt;POST_NOTIFICATIONS&lt;/code&gt;, and &lt;code&gt;VIBRATE&lt;/code&gt; permissions. Android 13 and later need &lt;code&gt;POST_NOTIFICATIONS&lt;/code&gt; to show anything.&lt;/li&gt;
&lt;li&gt;  Set a default notification icon and the default channel ID in the manifest.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Configure iOS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Add &lt;code&gt;GoogleService-Info.plist&lt;/code&gt; to the &lt;code&gt;Runner&lt;/code&gt; target in Xcode.&lt;/li&gt;
&lt;li&gt;  Enable &lt;strong&gt;Push Notifications&lt;/strong&gt;, &lt;strong&gt;Background Modes → Remote notifications&lt;/strong&gt;, and an &lt;strong&gt;App Group&lt;/strong&gt; named &lt;code&gt;group.&amp;lt;your.bundle.id&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Add a Notification Service Extension on iOS
&lt;/h2&gt;

&lt;p&gt;This is the step most Flutter push tutorials leave out. When a notification arrives while your app is in the background or closed, iOS doesn't run any Dart code. Without native code, you can't confirm delivery or attach images in those states — which is most of the time.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Notification Service Extension&lt;/strong&gt; is a small native target that iOS runs for every incoming notification. Add one in Xcode (&lt;strong&gt;File → New → Target → Notification Service Extension&lt;/strong&gt;), give it the same App Group as your app, and add the delivery-confirmation code from the &lt;a href="https://notifysphere.net/docs/flutter" rel="noopener noreferrer"&gt;Flutter SDK docs&lt;/a&gt;. The extension reads the credentials the SDK saved in the shared App Group, confirms delivery, and downloads any image attachment.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Initialize the SDK
&lt;/h2&gt;

&lt;p&gt;Initialize Firebase, then the SDK, before &lt;code&gt;runApp&lt;/code&gt;. The background handler must be a top-level function marked with &lt;code&gt;@pragma('vm:entry-point')&lt;/code&gt; so it survives tree shaking and can run in a background isolate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_core/firebase_core.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_messaging/firebase_messaging.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_notify_sphere/flutter_notify_sphere.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@pragma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'vm:entry-point'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;backgroundMessageHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RemoteMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Runs in a background isolate — keep it short&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FlutterNotifySphere&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;showForegroundNotification:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;onNotificationClick:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RemoteMessage&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Navigate to the screen this notification is about&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nl"&gt;backgroundMessageHandler:&lt;/span&gt; &lt;span class="n"&gt;backgroundMessageHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Register the user
&lt;/h2&gt;

&lt;p&gt;Register once you know who the user is. Taps and deliveries that happen before registration — such as a tap that cold-starts the app — are queued and sent once registration completes, so you don't lose them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// After login, or on your home screen&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;FlutterNotifySphere&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;appId:&lt;/span&gt; &lt;span class="s"&gt;'YOUR_APP_ID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;apiKey:&lt;/span&gt; &lt;span class="s"&gt;'YOUR_API_TOKEN'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;userData:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'applicationUserId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Jane Doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nl"&gt;onFcmToken:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'FCM token: &lt;/span&gt;&lt;span class="si"&gt;$token&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;onRegistrationComplete:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Subscription: &lt;/span&gt;&lt;span class="si"&gt;$id&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;onError:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Registration failed: &lt;/span&gt;&lt;span class="si"&gt;$error&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Test all three app states
&lt;/h2&gt;

&lt;p&gt;Send a test from the dashboard to a real device, and check each state separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Foreground:&lt;/strong&gt; a heads-up notification appears and &lt;code&gt;onForegroundMessage&lt;/code&gt; fires.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Background:&lt;/strong&gt; the notification shows in the tray; tapping it fires &lt;code&gt;onNotificationClick&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Closed:&lt;/strong&gt; the notification still shows, and on iOS the Delivered count rises — proof the service extension works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;dashboard.notifysphere.net&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbnuyrdwt1hs8ukp34d1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbnuyrdwt1hs8ukp34d1f.png" alt="notifySphere dashboard with active subscriptions, app subscribers, monthly active users, and push sends" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Registered Flutter devices appear as app subscribers, with push sends and delivery tracked per campaign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common problems
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Version solving failed:&lt;/strong&gt; your Firebase packages are older than the SDK requires.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;iOS delivered count stays at zero when the app is closed:&lt;/strong&gt; the service extension is missing, or it isn't in the same App Group as the app.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Nothing on Android 13+:&lt;/strong&gt; the notification permission wasn't granted.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Background handler never runs:&lt;/strong&gt; it isn't a top-level function, or the &lt;code&gt;vm:entry-point&lt;/code&gt; annotation is missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://notifysphere.net/docs/flutter" rel="noopener noreferrer"&gt;Flutter SDK reference&lt;/a&gt; lists every option. Using React Native instead? See the &lt;a href="https://notifysphere.net/blog/react-native-push-notifications" rel="noopener noreferrer"&gt;React Native push notifications guide&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://notifysphere.net/blog/flutter-push-notifications" rel="noopener noreferrer"&gt;notifySphere blog&lt;/a&gt;. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;free up to 1,000 users&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
      <category>notifications</category>
    </item>
    <item>
      <title>Best SDK for Real-Time Push Notification Delivery: What Actually Matters</title>
      <dc:creator>Notify sphere</dc:creator>
      <pubDate>Mon, 12 Oct 2026 09:58:40 +0000</pubDate>
      <link>https://dev.to/notifysphere/best-sdk-for-real-time-push-notification-delivery-what-actually-matters-4g1c</link>
      <guid>https://dev.to/notifysphere/best-sdk-for-real-time-push-notification-delivery-what-actually-matters-4g1c</guid>
      <description>&lt;p&gt;An OTP that arrives after the user gave up, or a “your driver has arrived” alert that shows up five minutes late, is worse than no notification at all. If you're choosing a push SDK because delivery speed matters, here's how delivery actually works and what to compare.&lt;/p&gt;

&lt;h2&gt;
  
  
  How push delivery works
&lt;/h2&gt;

&lt;p&gt;Every push notification takes the same path, whichever SDK you use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Your server, or your push provider, sends the message with the device's token.&lt;/li&gt;
&lt;li&gt; The platform service delivers it: &lt;strong&gt;Firebase Cloud Messaging (FCM)&lt;/strong&gt; on Android and &lt;strong&gt;Apple Push Notification service (APNs)&lt;/strong&gt; on iOS.&lt;/li&gt;
&lt;li&gt; The operating system wakes your app or shows the notification directly.&lt;/li&gt;
&lt;li&gt; A good SDK then reports back that the message arrived and whether it was tapped.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That means no SDK can deliver faster than FCM or APNs. What an SDK &lt;em&gt;can&lt;/em&gt; do is make sure every message is sent in the way that gets it delivered immediately, and tell you when that didn't happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why push notifications arrive late
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Normal priority on Android.&lt;/strong&gt; FCM holds normal-priority messages while the phone is in Doze mode and delivers them in the next maintenance window. Only high-priority messages wake the device.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hidden high-priority messages.&lt;/strong&gt; Android may deprioritise an app whose high-priority messages don't result in a visible notification. Keep high priority for messages the user will see.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Battery optimisation on some Android phones.&lt;/strong&gt; Several manufacturers stop background apps aggressively, which is common on phones popular in India. Data messages handled by your app suffer most; notification messages shown by the system are more reliable.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Low priority or background pushes on iOS.&lt;/strong&gt; APNs delivers &lt;code&gt;apns-priority: 5&lt;/code&gt; and silent &lt;code&gt;content-available&lt;/code&gt; pushes when it suits the device's power state, and throttles them.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Stale device tokens.&lt;/strong&gt; Tokens change after reinstalls and restores. Sending to an old token fails silently unless your provider removes tokens that FCM or APNs reports as unregistered.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Slow fan-out on the sending side.&lt;/strong&gt; Large campaigns sent one token at a time from a single worker can take minutes to reach the last user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The settings that control delivery speed
&lt;/h2&gt;

&lt;p&gt;For a time-sensitive alert, these are the fields that matter in an FCM HTTP v1 request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEVICE_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"notification"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your order is out for delivery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Arriving in 20 minutes"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"android"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"600s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"collapse_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"order_1234"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apns-priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apns-push-type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apns-collapse-id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"order_1234"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;android.priority: high&lt;/code&gt; and &lt;code&gt;apns-priority: 10&lt;/code&gt; deliver immediately.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;apns-push-type: alert&lt;/code&gt; marks a user-facing notification on iOS.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;ttl&lt;/code&gt; drops the message if it can't be delivered in time, so a stale “driver arriving” alert never shows up an hour later.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;collapse_key&lt;/code&gt; and &lt;code&gt;apns-collapse-id&lt;/code&gt; replace an older update with the newest one instead of stacking them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to compare when choosing a push SDK
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Why it matters for real-time delivery&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Priority control per message&lt;/td&gt;
&lt;td&gt;OTPs and live updates need high priority; promotions don't&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delivery receipts from the device&lt;/td&gt;
&lt;td&gt;“Sent” isn't “delivered”. You need to see what reached the phone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic token refresh and cleanup&lt;/td&gt;
&lt;td&gt;Stale tokens are the quietest cause of lost notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background and killed-app handling&lt;/td&gt;
&lt;td&gt;Notifications must show when the app isn't running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTL and collapse support&lt;/td&gt;
&lt;td&gt;Old alerts expire instead of arriving late&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fallback channel&lt;/td&gt;
&lt;td&gt;If a push isn't delivered or opened, a WhatsApp message can still reach the user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SDKs for your stack&lt;/td&gt;
&lt;td&gt;Native setup for React Native and Flutter is where most delivery bugs start&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Comparing providers? See how this plays out in &lt;a href="https://notifysphere.net/vs/onesignal-alternative" rel="noopener noreferrer"&gt;notifySphere vs OneSignal and other OneSignal alternatives&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test delivery speed yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Install a release build on a real Android phone and a real iPhone, not an emulator.&lt;/li&gt;
&lt;li&gt; Lock both phones and leave them for 30 minutes so Android enters Doze.&lt;/li&gt;
&lt;li&gt; Send a high-priority notification and note the time it appears.&lt;/li&gt;
&lt;li&gt; Repeat with the app force-stopped, and on a phone from a manufacturer known for battery optimisation.&lt;/li&gt;
&lt;li&gt; Compare the send time with the delivery time your provider reports.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Real-time push with notifySphere
&lt;/h2&gt;

&lt;p&gt;notifySphere delivers through FCM and APNs, and its &lt;a href="https://notifysphere.net/blog/react-native-push-notifications" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; and &lt;a href="https://notifysphere.net/blog/flutter-push-notifications" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; SDKs report delivery and taps back to your dashboard, so you see what actually arrived, not just what was sent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-notify-sphere&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;applicationUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;android&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AndroidPush&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IOSPush&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Delivery and press events are reported back to your dashboard automatically&lt;/span&gt;
&lt;span class="nx"&gt;NotifySphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNotification&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;press&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// open the screen this notification is about&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a push isn't opened, a journey can follow up on WhatsApp from the same dashboard. Setting up iOS? Start with the &lt;a href="https://notifysphere.net/blog/firebase-ios-push-notifications" rel="noopener noreferrer"&gt;Firebase iOS push guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the best SDK for real-time push notification delivery?
&lt;/h3&gt;

&lt;p&gt;There's no SDK that is faster than the transport: on Android every push SDK delivers through Firebase Cloud Messaging, and on iOS through Apple Push Notification service. The best SDK is the one that sends with the right priority, keeps device tokens fresh, retries on failure, and reports delivery back to you so you can see what actually arrived.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are my push notifications delayed on Android?
&lt;/h3&gt;

&lt;p&gt;The usual causes are normal-priority messages held during Doze mode, aggressive battery optimisation on some Android phones that stops apps in the background, and stale device tokens. Send time-sensitive messages with high priority and make sure each one shows a visible notification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are push notifications delayed on iOS?
&lt;/h3&gt;

&lt;p&gt;Low-priority (apns-priority 5) and background (content-available) pushes are delivered when it suits the device's power state and are throttled. User-facing alerts sent with apns-priority 10 and apns-push-type alert are delivered immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Firebase Cloud Messaging real-time?
&lt;/h3&gt;

&lt;p&gt;High-priority FCM messages are delivered immediately when the device is online, including waking it from Doze. Normal-priority messages may wait for a maintenance window. FCM is the delivery layer most push SDKs, including notifySphere, use on Android.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I measure push notification delivery?
&lt;/h3&gt;

&lt;p&gt;A send API returning success only means FCM or APNs accepted the message. To know whether it reached the phone, the SDK on the device has to report a delivery event back. notifySphere's React Native and Flutter SDKs report delivery and taps to your dashboard.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://notifysphere.net/blog/real-time-push-notification-sdk" rel="noopener noreferrer"&gt;notifySphere blog&lt;/a&gt;. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — &lt;a href="https://notifysphere.net/pricing" rel="noopener noreferrer"&gt;free up to 1,000 users&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
      <category>notifications</category>
    </item>
  </channel>
</rss>
