iOS VoIP CallKit is a native Apple framework that allows developers to integrate VoIP calling functionality into the standard iOS phone interface. It provides the lock-screen, Dynamic Island, and system-level call UI users expect, managed through core classes like CXProvider and CXCallController. When paired with a real-time communication backend like VideoSDK, CallKit handles the native UI while VideoSDK manages the underlying audio and video media streams.
Building a VoIP app on iOS means competing with the native phone experience. Users expect incoming calls to appear on the lock screen, integrate with the Dynamic Island, and respect Do Not Disturb settings. If your app relies on a custom in-app notification, you will lose users and potentially face App Store rejection. Apple requires VoIP apps to use CallKit for these exact reasons. This guide covers everything you need to know about iOS VoIP CallKit, from configuring PushKit for high-priority notifications to managing the call lifecycle with CXProvider. We will also explore how VideoSDK's iOS SDK handles the media layer while CallKit manages the system UI.

What is iOS VoIP CallKit?

iOS VoIP CallKit is defined as a framework introduced by Apple that lets VoIP apps integrate seamlessly with the native iOS calling interface. CallKit works by acting as a bridge between your app's communication logic and the iOS system's telephony features. Instead of building a custom incoming call screen, your app tells the system about an incoming call, and the system presents the familiar native UI.
VideoSDK provides robust real-time communication capabilities through its iOS SDK, but the visual presentation of incoming and outgoing calls on an Apple device should always be handled by CallKit. The two core classes you will interact with are CXProvider, which acts as the engine receiving call updates from your app, and CXCallController, which manages call actions initiated by the user or the system.

Why CallKit Is Essential for VoIP Apps

CallKit is essential because it elevates a third-party VoIP app to feel like a first-party system service. When a call comes in, the user sees the standard lock screen interface, complete with caller ID and swipe-to-answer gestures. On newer devices, the call appears in the Dynamic Island. This system-level integration means your VoIP calls respect Do Not Disturb modes, route audio correctly through Bluetooth accessories and CarPlay, and appear in the native Recents list.
From a compliance standpoint, Apple's App Store Review Guidelines mandate that any app offering voice or video calling over the internet must use CallKit. Failing to implement it correctly will result in rejection during the review process. CallKit ensures a consistent user experience across all iOS communication apps.

Preparing Your App for VoIP

Before you can display a native call UI, your app must be configured to receive incoming communications while in the background. This requires specific capabilities and certificates.

Enabling Background Modes

You must enable the Voice over IP background mode in your app's capabilities. This tells iOS that your app needs to run in the background to handle VoIP traffic. Without this mode enabled, the system will terminate your app when it moves to the background, making it impossible to receive incoming calls. You also need to enable Push Notifications to support the high-priority VoIP push mechanism.

Obtaining a VoIP Services Certificate

To send VoIP pushes, you need a specific VoIP Services Certificate from the Apple Developer portal. This is distinct from a standard APNs certificate. You create a certificate signing request, generate the VoIP certificate, and install it on your backend push server. This certificate allows your server to authenticate with Apple Push Notification service (APNs) using the VoIP push topic. VideoSDK's backend infrastructure can handle this push delivery for you, simplifying the process of connecting your custom SIP or WebRTC backend to Apple's push systems.

Setting Up PushKit for VoIP Pushes

Persistent background sockets are strongly discouraged by Apple because they drain battery and are unreliable. Instead, you must use PushKit to receive VoIP push notifications. PushKit delivers high-priority pushes that wake your app from a terminated or background state. When the push arrives, your app is given a brief window of execution time to process the payload and report the incoming call to CallKit. This workflow ensures energy efficiency and immediate call delivery.
Architecture Diagram

Integrating CallKit Core Classes

The CallKit framework revolves around a few core classes that manage the state and presentation of calls.

CXProvider – The Call Engine

CXProvider is the object that communicates call state changes to the system. You configure a CXProvider with a CXProviderConfiguration object, which defines settings like supported handle types, whether video is supported, and ringtone preferences. When your app receives an incoming call signal from PushKit, you use the CXProvider to report this new call to the system. The provider also receives non-user actions, such as the system ending a call because another higher-priority call came in on the native phone line. You must respond to these actions by updating your actual call state in the VideoSDK room.

CXCallController – Managing Calls

CXCallController is your app's interface for requesting call actions. When a user taps the end call button on the native UI, CallKit sends an action to your app. Conversely, when your app wants to initiate an outgoing call, it requests an action through the CXCallController. The controller coordinates these requests with the CXProvider to ensure the UI and the underlying media state remain in sync. For example, if a user places a call on hold via the system UI, the controller receives this action, and your app must pause the media stream in the VideoSDK session.

CXHandle and CXCallUpdate – Identifying Call Participants

To display caller information, you use CXHandle and CXCallUpdate. A CXHandle represents the caller's identity, which can be a phone number, an email address, or a generic identifier like a SIP URI. The CXCallUpdate object contains metadata about the call, such as the caller's name, whether the call has video capabilities, and whether it is an incoming or outgoing call. You pass this update to the CXProvider when reporting a new incoming call, ensuring the lock screen displays the correct information.

Handling Incoming Calls

The incoming call sequence is the most critical flow to get right in a VoIP app. It begins when your backend server, such as the VideoSDK REST API, detects an incoming call intended for a specific user. The server sends a VoIP push notification via APNs. The iOS device receives this push and wakes your app. Your app's PushKit delegate immediately processes the push payload to extract caller information.
You must then create a CXCallUpdate, configure a CXHandle with the caller's details, and call the reportNewIncomingCall method on your CXProvider. This must happen within a few seconds of receiving the push. If you delay, iOS will terminate your app and you will miss the call. Once reported, the system presents the native incoming call UI. When the user answers, your app must configure the audio session and connect to the VideoSDK room to begin streaming audio and video.
Architecture Diagram

Handling Outgoing Calls

Outgoing calls start within your app's UI. When the user selects a contact and taps call, your app requests a start call action via the CXCallController. You provide a CXHandle and a CXCallUpdate just as you would for an incoming call. CallKit then displays the native outgoing call interface.
While the UI is showing, your app must connect to the VideoSDK backend, initialize the room, and begin streaming media. Throughout the call, you must keep CallKit updated with the call's state. If the connection drops, you report that the call failed. If the user switches to a different audio output, like a Bluetooth headset, CallKit handles the UI, but your app must respect the audio routing changes. CallKit also manages hold, mute, and resume actions. When the user places the call on hold, your app receives a setHold action and must pause media transmission in the VideoSDK session accordingly.

Best Practices for Energy Efficiency and User Experience

Apple is strict about how VoIP apps consume battery. The most important rule is to always use PushKit for incoming calls rather than keeping a persistent socket open. Persistent sockets prevent the device from sleeping and will lead to app termination. When a VoIP push wakes your app, execute your code quickly and report the call to CallKit immediately. Do not perform heavy network requests before reporting the call.
Respect system interruptions. If a native cellular call comes in during a VoIP call, your app will receive an interruption notification. You should pause your VideoSDK media streams and wait for the user to return. Minimize background wake-ups by only sending pushes when a real call is incoming. Sending VoIP pushes for non-call events, like chat messages, is a violation of Apple's guidelines and will result in your push certificate being revoked.

Testing, Debugging, and App Store Review Tips

Testing VoIP apps requires a real physical device. The simulator does not support PushKit or CallKit's full telephony features. Verify that your app receives pushes when fully terminated, when in the background, and when in the foreground. Inspect the CallKit logs in Console.app to ensure your CXProvider is reporting calls without delays.
For App Store review, Apple will test your incoming call flow. The reviewer must be able to trigger a call and see the native UI appear within a few seconds. Ensure your VoIP certificate is valid and your backend push server is reliable. If the reviewer cannot receive a call, your app will be rejected. Provide clear testing instructions in your App Store submission notes, including any test accounts needed to trigger a call via your VideoSDK backend.

Common Pitfalls and How to Avoid Them

One frequent pitfall is failing to enable the VoIP background mode, causing the app to never wake from a terminated state. Another is using the wrong push certificate. A standard APNs certificate will not deliver VoIP pushes. You must generate a specific VoIP Services Certificate. Developers also often delay reporting the incoming call to CallKit by trying to fetch additional data from the network first. This causes iOS to kill the app. Extract all necessary caller info from the push payload itself and report the call instantly. Finally, ensure you handle the audio session correctly. Failing to activate the audio session when the user answers will result in a call with no audio.

Definitions Glossary

CallKit: An Apple framework that allows VoIP apps to integrate with the native iOS calling interface, providing lock-screen and Dynamic Island UI.
CXProvider: The core CallKit class responsible for receiving call updates from your app and reporting them to the system.
PushKit: A framework that receives high-priority VoIP push notifications, waking the app from the background to handle incoming calls.
VoIP Services Certificate: A specific Apple Developer certificate required to send high-priority VoIP push notifications via APNs.
Room: A VideoSDK meeting room that participants join to share real-time audio and video media streams.

Key Takeaways

  • iOS VoIP CallKit is mandatory for any app offering internet-based calling to ensure App Store compliance and a native user experience.
  • PushKit must be used to wake the app for incoming calls, and the call must be reported to CXProvider within seconds to avoid termination.
  • CXProvider manages incoming call UI, while CXCallController handles user-initiated actions like starting, ending, and holding calls.
  • VideoSDK's iOS SDK manages the underlying WebRTC media streams, while CallKit handles the system-level telephony UI.
  • Always test VoIP flows on physical devices, as the iOS simulator does not support PushKit or full CallKit functionality.

Conclusion

Integrating iOS VoIP CallKit is the cornerstone of a polished, App Store-compliant calling experience. By leveraging PushKit for high-priority wake-ups and CXProvider for native UI presentation, you give users the seamless telephony experience they expect. Pairing CallKit with VideoSDK's iOS SDK allows you to separate the system UI layer from the complex WebRTC media management, letting you focus on building great communication features. Ready to build your VoIP app? Explore the VideoSDK iOS SDK documentation and start integrating today. What are you building with VideoSDK? Drop a comment below.

Free $20 Balance for AI Voice Agents & Video Calls

FAQ