Most push notification guides focus on the messages users see. Silent push notifications are the ones they never see — and they’re doing a different job entirely.
A silent push wakes your app in the background, runs a task, and puts it back to sleep. No alert, no sound, no badge. The user opens the app and finds fresh content already loaded. They don’t know a push happened. That’s the point.
This guide covers how silent push notifications work on iOS and Android, what the implementation looks like in code, and how to use them strategically as part of customer journey automation. Along the way, you’ll see how Pushwoosh handles cross-platform silent push delivery and integrates it into automated workflows.
Related reading: Mobile push notifications: how they work | What are push notifications?
What are silent push notifications?
Silent push notifications are server-initiated messages that wake an app in the background without displaying anything to the user. No alert, no sound, no badge. The OS receives the push, briefly activates the app, the app runs its background task, then goes back to sleep.
The contrast with a standard push is simple: a visible push is a message to the user; a silent push is an instruction to the app.
What can an app do in those background seconds?
- Fetch new content. Pull the latest articles, updated product catalog, or refreshed social feed so it’s ready when the user opens the app.
- Sync data. Update local state with changes that happened on the server or through other channels — a purchase made on the website, a status change in a backend system.
- Evaluate location. Check whether the user has entered or left a geofence without requiring a visible notification as the trigger.
- Update user tags or segment data. Push the latest behavioral signals back to the CDP so targeting stays accurate.
- Pre-load content for an upcoming visible notification. Set up an in-app message or rich push payload so it renders instantly when triggered.
The practical value: users open an app that’s already up to date. No loading spinner, no stale data. That perception of speed and freshness has a measurable effect on retention, even when users can’t articulate why the app feels good to use.
How silent push notifications work
The delivery chain is the same as a regular push notification: your server sends a payload to APNs (iOS) or FCM (Android), the service delivers it to the device, the OS acts on it. What’s different is the payload structure and what the OS does when it arrives.
The delivery flow
- Server sends payload. Your backend or Pushwoosh sends a specially crafted message to APNs or FCM.
- Service delivers to device. APNs or FCM routes the payload to the correct device using the stored device token.
- OS wakes the app. Recognizing the silent push flags in the payload, the OS briefly activates the app in the background.
- App runs the background task. Your code executes: fetch data, sync state, check location, update a tag.
- App signals completion. On iOS, the app calls a completion handler. On Android,
onMessageReceived()returns. The OS puts the app back to sleep.
The background window is limited. iOS gives approximately 30 seconds. Android varies by device and power state. Background tasks need to be quick or designed to work within those constraints.
Payload differences: iOS vs. Android
| Parameter | iOS (APNs) | Android (FCM) |
|---|---|---|
| How to mark as silent | content-available: 1 in aps dict; no alert/sound/badge keys | Data-only message: data payload present, no notification object |
| APNs/FCM headers | apns-push-type: background; apns-priority: 5 | priority: normal (default) or high for time-sensitive tasks |
| Background time limit | ~30 seconds; must call completionHandler | onMessageReceived runs on main thread; offload heavy work |
| OS throttling | Throttled if sent more than ~3/hour or too close together | Doze mode and App Standby restrict background delivery |
| Key handler | application(_:didReceiveRemoteNotification:fetchCompletionHandler:) | onMessageReceived() in FirebaseMessagingService |
| User visibility | None — no alert, sound, or badge | None — no notification displayed |
The most common mistake on iOS is forgetting to set apns-priority: 5 alongside apns-push-type: background. If priority is set to 10 (the default for visible pushes), Apple may reject the message or display it visually even without an alert body. The low priority is what signals to APNs that this is a background task, not an urgent notification.
On Android, the critical rule is simpler: no notification object in the FCM payload. If a notification object is present, Android handles it as a regular push notification and displays it. Silent push = data only.
iOS implementation
Xcode configuration
Enable Background Modes in Xcode before writing any code:
- Open your project and select your app target.
- Go to ‘Signing & Capabilities’ and click ’+ Capability’.
- Add ‘Background Modes’ and check ‘Remote Notifications’.
Your App ID on the Apple Developer Portal must have Push Notifications enabled. Regenerate your provisioning profiles after making this change.
Registering for remote notifications
Silent pushes still require device registration with APNs. Handle this in AppDelegate:
import UIKitimport UserNotifications
@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self UNUserNotificationCenter.current().requestAuthorization( options: [.badge, .sound, .alert] ) { granted, _ in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } return true }
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() // Pushwoosh iOS SDK handles token submission automatically }}Handling the silent push
This is the method iOS calls when a silent push arrives:
extension AppDelegate {
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
guard let aps = userInfo["aps"] as? [String: AnyObject], aps["content-available"] as? Int == 1 else { completionHandler(.noData) return }
// Run your background task here fetchLatestContent { success in completionHandler(success ? .newData : .noData) } }}Always call completionHandler before the 30-second window closes. If you don’t, iOS can terminate the app and throttle future silent pushes. Pass .newData if you fetched something, .noData if nothing changed, .failed if the task errored.
APNs payload for silent push
{ "aps": { "content-available": 1 }, "update_type": "content_refresh", "content_id": "latest_feed"}Required APNs headers alongside this payload:
- apns-push-type: background
- apns-priority: 5
Android implementation
FCM setup and manifest
Add the FirebaseMessagingService to your AndroidManifest.xml:
<service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter></service>Handling data messages in Kotlin
Extend FirebaseMessagingService and implement onMessageReceived:
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) { // Pushwoosh Android SDK handles token submission automatically }
override fun onMessageReceived(remoteMessage: RemoteMessage) { // Silent push = data payload only, no notification object if (remoteMessage.data.isNotEmpty() && remoteMessage.notification == null) { handleSilentPush(remoteMessage.data) } }
private fun handleSilentPush(data: Map<String, String>) { when (data["update_type"]) { "content_refresh" -> { // Fetch new content from your server refreshContentFeed(data["content_id"]) } "segment_update" -> { // Push updated tags to Pushwoosh syncUserSegmentData() } "location_check" -> { // Evaluate current geofence status evaluateGeofences() } } }}FCM payload for silent push
The payload must contain a data object and no notification object:
{ "to": "DEVICE_TOKEN", "data": { "update_type": "content_refresh", "content_id": "latest_news_feed" }}Set priority to ‘high’ only for time-sensitive background tasks. Standard priority is fine for most content refresh use cases and avoids unnecessary battery impact.
Cross-platform silent push with Pushwoosh
Managing silent push manually across iOS and Android means maintaining two separate payload formats, two sets of delivery headers, and two sets of SDK integrations. Pushwoosh abstracts that.
When you trigger a silent push through Pushwoosh — via the UI or API — the platform generates the correct payload for each target platform automatically. APNs gets content-available: 1 with the right headers. FCM gets a data-only message. You configure the campaign once.
Device token management is centralized. iOS tokens, Android tokens, and web push subscriptions are all stored and updated in one place. When a token changes (reinstall, OS upgrade), Pushwoosh handles the refresh.
For non-technical team members, Pushwoosh provides a UI for scheduling and triggering silent pushes without writing a payload. This makes it practical to integrate silent pushes into Customer Journey Builder workflows alongside visible notifications and in-app messages.
Strategic use cases
Silent push notifications are most valuable when visibility would actually work against you. Here are the scenarios where they fit better than a standard push.
| Use case | What the silent push triggers | Why it's better than a visible push |
|---|---|---|
| Content pre-fetch | App fetches new articles, products, or feed items | User opens app to fresh content; no loading screen |
| Geofence evaluation | App checks user location vs. stored geofences | Location check happens without a visible notification; in-app message or local push fires only if conditions match |
| Segment update | App sends updated tags or events to Pushwoosh | Targeting data stays accurate after off-app activity (e.g., web purchase) |
| Pre-delivery setup | App pre-loads in-app message or offer screen | Visible notification or in-app message appears instantly with no lag |
| RFM recalculation | App pushes latest purchase/activity data to CDP | User moves into correct RFM segment in real time; follow-up campaigns trigger accurately |
Content pre-fetch for news and media apps
A news app that sends a breaking news alert benefits from a silent push sent 30 seconds earlier. The silent push wakes the app, which fetches the article and caches it locally. When the visible alert fires, tapping it opens the article instantly. No waiting for the story to load.
For apps with personalized feeds, a silent push at typical wake-up times pre-fetches the morning content before the user opens the app. The app feels fast because it is — the data is already there.
Geofence evaluation without a visible trigger
A user walks near a store. The standard approach: send a location-based push notification. The problem: the user has to be opted in, the timing might be off, and they may feel tracked.
The silent push approach: the server sends a silent push when the user is within a region. The app checks the precise geofence client-side. If conditions match, the app activates an in-app message or a local notification at the right moment. The visible communication only happens if the logic passes — not as the trigger itself.
Keeping segment data accurate after off-app activity
A user makes a purchase on your website. Their RFM segment should update immediately. But the app doesn’t know until the user opens it.
A silent push sent after the web purchase wakes the app in the background, which syncs the latest purchase event to Pushwoosh. The user moves into the correct RFM segment in real time. A follow-up campaign — loyalty reward, cross-sell, thank-you sequence — fires based on accurate data.
Related reading: RFM segmentation guide | Rich push notifications
Pre-loading content for in-app messages
In-app messages that require a server fetch to render can have noticeable lag. A silent push sent before the user is expected to trigger the in-app message pre-fetches the content and stores it locally. When the message fires, it displays immediately.
This pattern works well for onboarding flows, feature announcements, and promotional overlays where the content is personalized and can’t be hardcoded into the app binary.
Best practices
Respect OS throttling limits
iOS throttles silent pushes that arrive too frequently. Apple’s guidance is roughly 2-3 per hour, or about one every 21 minutes at most. Apps that exceed this may find their silent pushes delayed or dropped without any error.
Android’s Doze mode and App Standby restrict background execution when the device is idle. High-priority FCM messages can wake the app during Doze, but should be used selectively. Standard priority messages are deferred until the device exits Doze.
The practical rule: send silent pushes only when the background task is genuinely time-sensitive. Pre-fetching content once at a natural cadence (morning, or after a server-side update) is fine. Sending every 10 minutes to keep data fresh is not.
Keep payloads small and tasks fast
The silent push payload should be a signal, not a data transfer. Send the minimum needed to tell the app what to fetch and where. The actual data fetch happens inside the app after the push arrives.
Background tasks should complete well within the time limit. If a task requires more than a few seconds, design it to be interruptible: save progress, call the completion handler, and pick up on the next opportunity. Lengthy background tasks risk OS termination and can affect battery life enough that users notice.
Test across power states and OEM variants
Silent push behavior varies significantly across Android OEMs. Xiaomi, Huawei, and OnePlus all have aggressive battery optimization that can prevent background execution entirely for apps that aren’t whitelisted. Test on real devices from these manufacturers, not just stock Android emulators.
On iOS, test in low power mode and with the app force-quit. Silent push delivery in those states is less reliable, and your background logic should handle the case where the task didn’t run before the user opens the app.
Track effectiveness through downstream events
Silent pushes don’t produce click metrics. Track their effectiveness through the events they’re supposed to trigger: content_refreshed, segment_updated, geofence_evaluated. If those events stop firing at the expected rate after a silent push campaign, the delivery is being throttled or the background handler is failing.
Pushwoosh Analytics surfaces app events alongside campaign data. Map your background task completion events to silent push sends to confirm the pipeline is working.
Integrate into journey automation, not one-off sends
A silent push sent in isolation is a technical operation. A silent push embedded in a Customer Journey is a strategic one. The most useful patterns use silent pushes as a step that enables a better visible interaction downstream: update the segment before the promotional push, pre-fetch the content before the in-app message, evaluate the geofence before the location-based alert.
Pushwoosh’s Customer Journey Builder supports silent pushes as journey steps alongside visible notifications and in-app messages.
Improve app freshness and campaign precision with Pushwoosh
Silent push notifications are the infrastructure layer under better user experiences. Fresh content on open, accurate segment data, seamless geofence-triggered interactions — none of these work reliably without background app updates.
Pushwoosh handles cross-platform silent push delivery, payload formatting, token management, and Customer Journey integration. Developers get clean SDK abstractions; marketing teams get silent push as a first-class step in automated workflows.