A local notification is a message that the app sends to the user without involving a remote server. All data is processed and displayed directly on the recipient’s device. This mechanism is suitable for reminders, timers, and alarms when the app is in the background or closed. According to Apple Developer Documentation, UNUserNotificationCenter provides centralized management of local notifications on iOS.
Key Takeaways
A local notification is a trigger message that is generated and displayed by the operating system on the same device where the app is installed. Unlike push notifications, local notifications do not go through an external server — all scheduling logic runs on the client.
Such notifications work regardless of the app’s state: active, minimized, or completely closed. The operating system handles delivery at the scheduled time, while the developer only specifies the content and trigger.
The system guarantees delivery of local notifications even without network access. This is a key advantage over push notifications, which require a stable internet connection and a working server.
Each local notification consists of three parts: content (title, body, sound), trigger (time or geo condition), and request identifier. The identifier allows canceling or updating the notification before delivery.
A developer can schedule up to 64 local notifications per app on iOS and an unlimited number on Android. This difference is due to architectural constraints of the operating systems.
Both platforms provide their own APIs for working with local notifications. On iOS, the central component is UNUserNotificationCenter, on Android — NotificationManager. Despite different interfaces, the logic is the same: the app creates a request, registers it with the system, and the OS delivers the notification at the scheduled time.
iOS uses UNCalendarNotificationTrigger for calendar events, UNTimeIntervalNotificationTrigger for intervals, and UNLocationNotificationTrigger for geolocation. Android offers AlarmManager, WorkManager, and precise scheduling via setExact.
Since Android 12 — SCHEDULE_EXACT_ALARM requires special permission from the user. On iOS, permission is requested once through UNUserNotificationCenter.requestAuthorization, and the user chooses access level: banners, sounds, badges.
Local notifications are classified by trigger type, not by content. Each type determines when and under what conditions the notification will be shown to the user.
On iOS and Android, trigger types are implemented differently, although the logical classification is the same. iOS uses UNCalendarNotificationTrigger for dates, UNTimeIntervalNotificationTrigger for intervals, and UNLocationNotificationTrigger for geolocation. Android offers AlarmManager with setExact and setRepeating, as well as WorkManager for deferred tasks.
| Trigger Type | Description | Example |
|---|---|---|
| Time Interval | Notification N seconds after launch | Countdown timer |
| Calendar Date | Notification at a specific time and date | Meeting reminder |
| Geolocation | Notification on entering/leaving a region | Store reminder |
| Immediate | Instant delivery upon API call | Download notification |
iOS also supports UNNotificationAttachment — attaching an image, audio, or video to the notification body. Android supports custom templates with buttons and large images via NotificationCompat.Style.
The choice of trigger depends on the scenario: calendar reminders work best with calendar triggers, geo reminders with geolocation. Interval triggers are suitable for recurring events with a fixed period.
On iOS, local notifications are delivered by the system even when the app is closed — UNUserNotificationCenter manages the queue independently. On Android, delivery depends on the chosen mechanism: AlarmManager fires even with the screen off, while WorkManager accounts for power saving.
Local notifications solve tasks where external infrastructure is excessive or unavailable. Main scenarios: reminders, timers, onboarding tips, and deferred actions.
Research by Localytics shows that apps using local reminders retain 35% more users in the first week after installation. This makes local notifications a powerful onboarding tool.
It is important not to overuse frequency — the system groups notifications from the same app, and the user can disable all local notifications if they become annoying. Optimal frequency is no more than 2–3 notifications per day for non-critical events.
To schedule a local notification on Android, use NotificationManager together with AlarmManager. On Android 8+, you must first create a notification channel, otherwise the notification will not be displayed.
val channelId = "reminder_channel"
val notificationId = "task_reminder_42"
val channel = NotificationChannel(
channelId,
"Reminders",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Channel for task reminders"
}
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
val intent = Intent(this, ReminderReceiver::class.java).apply {
putExtra("notification_id", notificationId)
putExtra("channel_id", channelId)
}
val pendingIntent = PendingIntent.getBroadcast(
this, notificationId.hashCode(),
intent, PendingIntent.FLAG_UPDATE_CURRENT
)
val alarmManager = getSystemService(AlarmManager::class.java)
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
triggerTimeMillis,
pendingIntent
)
On Android 12+, check the SCHEDULE_EXACT_ALARM permission before calling setExact. If permission is not granted — use setWindow, which guarantees delivery within a time window.
When AlarmManager fires, the system sends a broadcast Intent that is received by BroadcastReceiver. Inside it, you need to create and show the notification via NotificationManager. Make sure that PendingIntent uses FLAG_UPDATE_CURRENT, otherwise old notifications will continue using outdated Intent when data changes.
On iOS, local notifications are created via UNUserNotificationCenter using UNMutableNotificationContent and one of the triggers. Before scheduling, you must request permission from the user.
import UserNotifications
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
guard granted else { return }
}
let content = UNMutableNotificationContent()
content.title = "Task reminder"
content.body = "Don’t forget to complete the report by 6:00 PM"
content.sound = .default
content.userInfo = ["task_id": "42"]
let trigger = UNTimeIntervalNotificationTrigger(
timeInterval: 3600,
repeats: false
)
let request = UNNotificationRequest(
identifier: "task_reminder_42",
content: content,
trigger: trigger
)
center.add(request)
iOS supports up to 64 concurrent local notification requests. If the limit is exceeded, the system rejects new requests until active ones are delivered or canceled. Use getPendingNotificationRequests to check the current queue.
When a user interacts with a local notification on iOS, the userNotificationCenter:didReceive response method of the UNUserNotificationCenterDelegate is called. This method provides the request identifier, actionIdentifier (which button was pressed), and custom userInfo. This allows distinguishing between a simple notification open and pressing a specific action button.
To make local notifications useful rather than annoying, follow several key rules. First: control frequency — no more than 2–3 notifications per day for non-critical events, otherwise the user will disable all app notifications.
Second: give the user choice. Add the ability in the interface to disable certain types of local notifications. On Android, use a separate NotificationChannel with low importance for this; on iOS, use a separate category in the app settings.
Third: contextual relevance — the notification should appear when the user needs it. Geo triggers are ideal for reminders near home, calendar triggers for meetings, interval triggers for regular activities like drinking water or stretching. Do not mix types unnecessarily.
Fourth: test on real devices. The iOS simulator does not emulate all local notification delivery scenarios, especially in the background. On Android, use adb shell dumpsys notification to check the queue of scheduled notifications and their parameters. Fifth: always provide the user with the ability to disable notifications through the app interface — this is a mandatory UX and App Store Review Guidelines requirement.
Frequently Asked Questions
A local notification is scheduled and delivered by the device without server involvement. A push notification requires an external service (FCM, APNS) and an internet connection. Local notifications work offline, push only work with network access.
iOS limits to 64 concurrently scheduled requests. Android does not have a strict limit, but over 500 notifications may reduce system performance and affect delivery time.
Yes, on iOS use removePendingNotificationRequests with the request identifier. On Android, call NotificationManager.cancel or cancel the PendingIntent via AlarmManager. A unique identifier is mandatory for cancellation.
On iOS, permission is mandatory via requestAuthorization. On Android 13+ (Tiramisu), the POST_NOTIFICATIONS permission is also required. Older Android versions do not require explicit permission for local notifications.
On iOS, create UNNotificationAction and add it to UNNotificationCategory. On Android, use NotificationCompat.Builder.addAction with a PendingIntent targeting BroadcastReceiver. Each button triggers a separate action in the app.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also