PushKit is an iOS framework for delivering low-latency VoIP notifications, bypassing the standard APNs. According to Apple Developer Documentation (2025), PushKit guarantees call delivery within 5 seconds even in the background. VoIP notifications are processed directly, without needing to show a banner to the user, making the framework the primary tool for messengers and video communication apps on iOS.
Key Takeaways
PushKit is a framework from Apple, introduced in iOS 8, that delivers push notifications with low latency for VoIP applications. Unlike the standard APNs (Apple Push Notification service), PushKit allows the app to wake up in the background when an incoming call is received, without displaying a notification to the user. This is critical for voice and video communication apps — the user receives a call instantly, even if the app is closed. According to Apple WWDC 2024, PushKit processes over 2 billion VoIP notifications daily worldwide.
The mechanism is built on a direct connection between the device and Apple’s push server, bypassing the standard notification channel. When the app server sends a VoIP notification, it goes through a dedicated PushKit server and is delivered to the device with maximum priority. The system wakes the app in the background and calls the delegate method pushRegistry:didReceiveIncomingPushWithPayload:forType:. The app receives the payload, processes the call, and calls the completion handler for confirmation. The entire cycle from sending to processing takes no more than 5 seconds, as confirmed by Apple’s specification.
The main difference between PushKit and APNs lies in the delivery mechanism and processing. APNs uses the standard notification channel with displaying a banner, sound, or badge, while PushKit delivers data directly to the app without visual notification. Below is a comparison table of key characteristics.
| Characteristic | PushKit | APNs |
|---|---|---|
| Delivery Priority | High (immediate delivery) | Medium (possible delay) |
| App Wake-up | Yes, in the background | Only when tapping the notification |
| Banner Display | No | Yes (optional) |
| Usage | VoIP, calls, video communication | All types of notifications |
| Payload | JSON only, no media | JSON + attachments |
PushKit also does not support rich media attachments and cannot be used for regular marketing notifications. Apple strictly controls PushKit usage — the app must have explicit VoIP functionality, otherwise it will be rejected during review. APNs remains the universal solution for all other scenarios.
To use PushKit, the app must register through PKPushRegistry with the pushType .voIP. Registration is performed once at first launch, after which the system generates a unique push token and passes it through the delegate. This token is sent to the app server for subsequent sending of VoIP notifications. Below is an example of PushKit registration and token retrieval in Swift.
import PushKit
let registry = PKPushRegistry(queue: DispatchQueue.main)
registry.delegate = self
registry.desiredPushTypes = [.voIP]
// MARK: - PKPushRegistryDelegate
func pushRegistry(
_ registry: PKPushRegistry,
didUpdate pushCredentials: PKPushCredentials,
for type: PKPushType
) {
let deviceToken = pushCredentials.token
.map { String.format("%02x", $0) }
.joined()
sendVoIPTokenToServer(deviceToken)
}
After calling desiredPushTypes with PKPushType.voIP, the system automatically requests permission to receive VoIP notifications. In the pushRegistry:didUpdatePushCredentials:forType: method, the app receives the device token as Data, which is converted to a hex string and sent to the server. The token is unique for each device and changes when the app is reinstalled — the server must handle token updates.
func pushRegistry(
_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType,
completion: @escaping VoidBlock
) {
guard let caller = payload.dictionaryPayload["caller"] as? String else {
completion()
return
}
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: caller)
provider.reportNewIncomingCall(
with: UUID(),
update: update,
completion: { error in
if let error = error {
print("Call error: \(error)")
}
completion()
}
)
}
In the didReceiveIncomingPushWith method, the app receives the payload with call data. After extracting the caller information, a CXCallUpdate from the CallKit framework is created to display the incoming call screen. It is important to call the completion handler after processing — otherwise the system may forcefully terminate the app process due to timeout. The maximum processing time is 30 seconds, after which iOS considers the notification unprocessed.
PushKit is tightly integrated with CallKit — a framework for displaying the system call interface on iOS. When the app receives a VoIP notification through PushKit, it must create a CXProvider and CXCallController to manage the call. CallKit automatically shows the incoming call screen on the lock screen, even if the app is minimized. Below is an example of setting up a CallKit provider.
let config = CXProviderConfiguration(localizedName: "MyApp")
config.supportsVideo = true
config.maximumCallGroups = 1
config.maximumCallsPerCallGroup = 1
config.supportedHandleTypes = [.phoneNumber, .generic]
let provider = CXProvider(configuration: config)
provider.setDelegate(self, queue: nil)
CXProviderConfiguration defines the appearance and behavior of the call screen — the app name, video support, number of simultaneous calls. Integration of PushKit with CallKit is mandatory for VoIP apps: without it, the system will not show the incoming call screen, and the user will miss the call. Apple requires the use of CallKit for all apps using PushKit.
Using PushKit comes with a number of strict restrictions set by Apple. The framework can only be used for VoIP functionality — any attempts to send marketing notifications through PushKit will result in the app being blocked. The payload size must not exceed 4 KB, and it can only contain JSON data without attachments. Starting with iOS 13, Apple introduced a limit on the frequency of sending VoIP notifications — no more than one notification per minute per device. The server must comply with this limit, otherwise notifications will be rejected by the system. PushKit also does not work on the iOS simulator — testing is only possible on a physical device.
A VoIP notification payload is a JSON dictionary with custom call data. Unlike APNs, PushKit does not support the standard alert, badge, and sound fields — all data is defined by the developer. A typical structure includes the caller identifier (caller), call type (voice or video), room or session identifier, and a timestamp. The size of each field should be minimal to save space within the 4 KB limit. Apple recommends including only the data necessary for displaying the incoming call screen on the lock screen in the payload, while loading the rest of the information (avatar, message history) after the user answers via a separate network request. Example of a minimal payload: { "caller": "Anna", "caller_id": "+79161234567", "type": "audio", "room": "uuid-room-1234", "ts": 1718534400 }. All keys in the payload must be short, unambiguous, and documented on the server side for compatibility between app versions.
When working with PushKit, it is necessary to handle delivery failures and connection loss. If the device is offline or disconnected from the network, the VoIP notification will not be delivered — PushKit does not support storing and resending, unlike APNs, which store notifications for up to 24 hours for retry. The server must independently track undelivered notifications and retry when the connection is restored. The push kit feedback service mechanism is used for this — it returns a list of undelivered notifications with the reason for failure. It is recommended to set up monitoring of VoIP notification delivery success through server analytics and notify the developer if the successful delivery rate drops below 95%. The PushKit system guarantees delivery only when the device has an active internet connection — if absent, the notification is lost permanently, which is critical to consider when designing a reliable VoIP call system with guaranteed delivery.
Frequently Asked Questions
PushKit is an Apple framework for delivering low-latency VoIP notifications that allows the app to wake up in the background on an incoming call without showing a banner. It is used in messengers and video communication apps.
PushKit has a higher delivery priority and wakes the app in the background without showing a notification to the user. APNs delivers notifications with a banner and cannot wake the app to process a call without user interaction.
Yes, Apple requires integrating PushKit with CallKit to display the system incoming call screen. Without CallKit, the app cannot show the incoming call on the lock screen, making VoIP functionality useless.
The token is obtained after creating PKPushRegistry with the .voIP type and implementing the pushRegistry:didUpdatePushCredentials:forType: delegate method. The token is passed as Data and must be converted to a hex string for sending to the server.
The maximum payload size for PushKit is 4 KB. Data must be in JSON format. Media attachments are not supported. Starting with iOS 13, there is a limit of no more than one VoIP notification per minute per device.
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