Handling Notification Payloads
Respond to foreground and background notifications.
Handling Notification Payloads is a free Swift Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Payload Structure
A remote notification is a JSON dictionary your server sends to APNs. The reserved aps key holds the user-visible content — alert, sound, badge — while any sibling keys carry your custom data, such as an item id to open.
// Example payload JSON:
// {
// "aps": { "alert": { "title": "Hi", "body": "..." },
// "sound": "default", "badge": 1 },
// "itemId": "42"
// }The aps Dictionary
Inside aps, alert can be a string or a title/body/subtitle object. sound, badge, and flags like content-available and mutable-content also live here. Everything outside aps is yours to define.
// aps keys:
// alert: { title, subtitle, body }
// sound: "default" or critical sound object
// badge: Int
// content-available: 1 (silent / background)
// mutable-content: 1 (allow modification)Foreground Delivery
By default, a notification that arrives while your app is in the foreground is suppressed. To show it anyway, implement the delegate's willPresent and return the presentation options you want, like a banner and sound.
import UserNotifications
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification
) async -> UNNotificationPresentationOptions {
return [.banner, .sound, .badge]
}Responding to a Tap
When the user taps a notification (whether the app was background or terminated), the delegate's didReceive response runs. This is where you read the payload and navigate to the right screen.
import UserNotifications
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse
) async {
let info = response.notification.request
.content.userInfo
if let id = info["itemId"] as? String {
print("open item", id)
}
}Reading userInfo
The full payload, including your custom keys, is exposed as content.userInfo — a [AnyHashable: Any] dictionary. Cast each value carefully; never force-unwrap, because a malformed payload should not crash the app.
import UserNotifications
func route(_ userInfo: [AnyHashable: Any]) {
guard let screen = userInfo["screen"] as? String
else { return }
switch screen {
case "profile": print("go to profile")
case "cart": print("go to cart")
default: break
}
}Silent (Background) Notifications
Setting content-available: 1 and omitting an alert makes a silent push that wakes the app in the background to fetch data, with no UI. These are throttled by the system and require the Remote notifications background mode.
// Silent payload — no alert, just a wake-up:
// { "aps": { "content-available": 1 }, "sync": true }
let silent = "content-available wakes app quietly"
_ = silentBackground Fetch Handler
A silent push arrives in the app delegate's didReceiveRemoteNotification async method. You do your fetch and return a UIBackgroundFetchResult so the system knows whether new data arrived and can budget future wake-ups.
import UIKit
func application(
_ app: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any]
) async -> UIBackgroundFetchResult {
// fetch fresh data here
return .newData
}Mutable Content and Service Extensions
With mutable-content: 1, a Notification Service Extension can intercept the push before display — to decrypt the body, download an image attachment, or rewrite the title. The extension has a short time budget to finish.
// Service extension entry point (UNNotificationServiceExtension):
// override didReceive(_:withContentHandler:)
// modify bestAttemptContent, then call contentHandler
let mutable = "mutable-content enables interception"
_ = mutableLocalizing the Alert
To localize text on the server side, send title-loc-key and loc-key referencing keys in your app's Localizable strings, plus loc-args for substitutions. The device renders them in the user's language without you sending pre-translated copy.
// Localized alert payload:
// "alert": {
// "loc-key": "NEW_MESSAGE",
// "loc-args": ["Ada"]
// }
let localized = "loc-key resolves on device"
_ = localizedUpdating the Badge
The badge value sets the app icon number. Sending badge: 0 clears it. You can also set it in code via setBadgeCount after the user reads content, keeping the badge in sync with unread state.
import UserNotifications
func clearBadge() async {
try? await UNUserNotificationCenter.current()
.setBadgeCount(0)
}A Robust Handler
Combine the pieces: present in foreground, route on tap, and validate every cast. The handler never crashes on unexpected payloads and always extracts what it can.
import UserNotifications
func handleTap(_ response: UNNotificationResponse) {
let info = response.notification.request
.content.userInfo
guard let id = info["itemId"] as? String else {
print("no item id; open home")
return
}
print("navigate to item", id)
}Quick Check
Recall how to react to a notification tap.
Recap
You learned to handle payloads:
- The
apsdictionary holds user-visible content; sibling keys hold your data, read viauserInfo. - Override
willPresentto show foreground notifications anddidReceive responseto handle taps. content-available: 1drives silent background fetches returning aUIBackgroundFetchResult.mutable-contentenables a service extension;loc-keylocalizes text on device.
Frequently asked questions
Is the “Handling Notification Payloads” lesson free?
Yes — the full text of “Handling Notification Payloads” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “Handling Notification Payloads”?
Respond to foreground and background notifications. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Handling Notification Payloads” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Registering for Push Notifications
- Handling Notification Payloads
- Background Tasks and Refresh
- Notification Actions and Categories