Notification Content Extension is a type of iOS extension that replaces the standard push notification template with a fully custom user interface. Developers can display images, audio players, action buttons, progress bars, and custom animations inside a notification, extending the standard banner into a full-fledged mini-application. According to WWDC 2025, the extension uses UNNotificationContentExtension and supports up to 4 media attachments in a single notification, as well as handling interactive actions through UNNotificationAction.
Key Takeaways
Notification Content Extension is an app extension that overrides the display of push notifications on iOS. Instead of a standard banner with a title, message body and buttons, you can show an interface fully designed in Interface Builder or programmatically via UIKit or SwiftUI.
Unlike Notification Service Extension, which modifies content before display, Content Extension is responsible only for the visual presentation. The extension receives the completed notification after all modifications and decides how to display it. This is the key difference between the two types of notification extensions.
The extension is activated when the user performs an expansion gesture — scrolling down on the notification or tapping it (depending on the device model). iOS launches the extension process, creates a controller from the specified nib or storyboard, and delivers the notification via UNNotificationContentExtension .
Development begins by adding a new target in Xcode with the Notification Content Extension template. Xcode creates a MainInterface.storyboard file and a class inheriting from UIViewController that implements the UNNotificationContentExtension protocol.
The maximum height of the custom area is 320 points on iPhone (for large screen models) and 352 points on iPad. Content that exceeds these boundaries is clipped. To adapt to different sizes, it is recommended to use Auto Layout and UIScrollView for scrollable content. The width always matches the notification width and changes automatically when the device is rotated.
Apple Human Interface Guidelines warn: the notification interface should be concise and contain only one primary element — an image, player, map, or quick input form. Multiple interactive elements overwhelm the user and complicate interaction.
App Group is the only mechanism for sharing data between the extension and the main application. Through the shared App Group directory, cached images, tokens, and settings can be transferred. Direct API calls to the main application or access to its UserDefaults are not available due to process isolation.
class NotificationViewController: UIViewController {
func didReceive(
_ notification: UNNotification
) {
guard let attachment = notification
.request.content.attachments.first()
else { return }
if attachment.url.startAccessingSecurityScopedResource() {
imageView.image = UIImage(contentsOfFile:
attachment.url.path)
attachment.url.stopAccessingSecurityScopedResource()
}
}
}
UNNotificationContentExtension is the main protocol that defines the lifecycle of a custom notification. The protocol provides methods for receiving content, handling actions, and managing the interface.
didReceive(_:with:) is called when a notification is received. The extension receives a UNNotification object and UNNotificationContentExtensionMediaPlayPauseButtonType for managing the media player. In this method, you need to configure the interface — load an image, initialize the player, or display data. The system calls this method each time the notification is updated in real time.
It is important to note that the extension has limited time to execute — about 30 seconds for a full display cycle. If the interface is not prepared within this time, iOS will show the system notification. For heavy resources — loading images from the network, decoding video — it is recommended to use asynchronous operations with pre-caching via App Group.
The protocol includes optional methods for play/pause buttons: mediaPlay, mediaPause, mediaPlayPauseButtonType. If the notification contains audio or video content, the extension can display a built-in player with a system control element. iOS automatically adds a playback button to the upper right corner of the extension when the appropriate button type is returned.
UNNotificationAttachment is an object that contains media data attached to a notification. Images, audio files, and video are added at the notification creation stage on the server or in the Notification Service Extension via UNNotificationAttachment.
For images: JPEG, PNG, GIF, HEIF. For audio: MP3, AAC, ALAC, WAV. For video: MPEG-4, H.264, HEVC. Maximum size of each attachment is 50 MB, up to 4 attachments per notification. The system automatically downloads attachments in the background before displaying the notification and provides the extension access to local URLs through security-scoped resources.
According to Apple, the extension should not download media itself — UNNotificationAttachment already contains a local URL after the system completes downloading. However, if the attachment was not downloaded in time (e.g., due to a poor connection), the extension can display a placeholder or alternative text.
Each UNNotificationAttachment provides a security-scoped URL that the extension must access via startAccessingSecurityScopedResource() and release via stopAccessingSecurityScopedResource(). These methods must be called in pairs — otherwise the resource will not be released and will cause an access rights leak.
let attachment = notification.request.content.attachments.first()
guard attachment.url.startAccessingSecurityScopedResource()
else { return }
defer { attachment.url.stopAccessingSecurityScopedResource() }
let data = try Data(contentsOf: attachment.url)
imageView.image = UIImage(data: data)
Notification Content Extension supports custom interactive actions — buttons that are displayed below the notification content. Actions are registered when creating the notification category via UNNotificationCategory and can be destructive, text-based, or background.
UNNotificationAction is a simple action with a title and an optional destructive flag. UNTextInputNotificationAction is an action with a text input field, for example for quick replies to messages. Both types support the UNNotificationActionOptions.authenticationRequired option — requiring device unlock before execution.
The extension receives the selected action via the method didReceive(_:withCompletionHandler:), which passes a UNNotificationResponse object with the action identifier and optional text. The extension can process the response itself or pass it to the main application through the shared App Group container.
let category = UNNotificationCategory(
identifier: "message",
actions: [
UNTextInputNotificationAction(
identifier: "reply",
title: "Reply",
options: .authenticationRequired
),
UNNotificationAction(
identifier: "mark_read",
title: "Mark Read",
options: .foreground
)
],
intentIdentifiers: []
)
Frequently Asked Questions
Content Extension is responsible for the visual display of the notification, while Service Extension is responsible for modifying content before display. Content Extension works after Service Extension and cannot change the notification payload.
Swift and Objective-C for UIKit. Starting from iOS 16, SwiftUI is also supported for creating notification interfaces via NotificationContentView with size and configuration modifiers.
Yes, starting from iOS 16, the extension can use SwiftUI through UIHostingController. However, all UIKit competencies — size, constraints, security-scoped resources — are preserved and applied to SwiftUI content.
4 attachments per notification. Each attachment can be up to 50 MB. Supported formats include images (JPEG, PNG, HEIF), audio (MP3, AAC), and video (MPEG-4, H.264).
App Group — a shared directory on disk. UserDefaults with the app group suffix also works. Direct API calls to the main application are not available due to process isolation.
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