<?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>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>
