CallKit Implementation for iOS (Integration with System Calls)

CallKit Implementation for iOS (Integration with System Calls) We have encountered situations where a VoIP app receives an incoming call, but the user misses it because the system notification looks like a regular banner. The result: lost calls and unhappy clients. CallKit solves this by turning

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
CallKit Implementation for iOS (Integration with System Calls)
Complex
~2-3 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

CallKit Implementation for iOS (Integration with System Calls)

We have encountered situations where a VoIP app receives an incoming call, but the user misses it because the system notification looks like a regular banner. The result: lost calls and unhappy clients. CallKit solves this by turning an app call into a full system call with a large screen, buttons, and history entry. In this article, we will explain how to set up CallKit from scratch, avoid common mistakes, and increase the answer rate.

How CallKit Changes the User Experience for Incoming Calls

Without CallKit, an incoming VoIP call appears as a push notification. With CallKit, it displays full-screen with the contact’s name and photo, and options to answer or decline. According to statistics, this format boosts successful connection rates by 3–4 times compared to a standard push notification.

Architecture: CXProvider and CXCallController

The central class is CXProvider. It is the communication point between the app and the system: through it we report an incoming call, update information, and end the call. The second class is CXCallController, through which the app initiates and manages outgoing calls.

let providerConfiguration = CXProviderConfiguration() providerConfiguration.supportsVideo = true providerConfiguration.maximumCallsPerCallGroup = 1 providerConfiguration.supportedHandleTypes = [.phoneNumber, .emailAddress, .generic] provider = CXProvider(configuration: providerConfiguration) provider.setDelegate(self, queue: nil) 

Incoming Call. It arrives via a VoIP push (PushKit, not APNs). This is important: a regular APNs push does not support CallKit calls since iOS 13 — Apple requires using PKPushType.voIP and in the delegate PKPushRegistryDelegate.pushRegistry(_:didReceiveIncomingPushWith:) immediately call reportNewIncomingCall. Any delay between the push and the reportNewIncomingCall call will cause the system to terminate the app.

func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool) { let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .generic, value: handle) update.hasVideo = hasVideo provider.reportNewIncomingCall(with: uuid, update: update) { error in // if error != nil — the system rejected the call (e.g., DND) } } 

Answer/Decline.

The system calls CXProviderDelegate methods: provider(_:perform:) with CXAnswerCallAction or CXEndCallAction. In response to the Answer action, you need to connect the audio — start a WebRTC session or connect your VoIP SDK (Twilio Voice, Agora, Daily).

WebRTC and Audio Session

CallKit manages the system’s audio session. You must not configure AVAudioSession yourself — that is CallKit’s responsibility. When the call is answered, the system activates the audio session and calls provider(_:didActivate:). At that moment, connect the WebRTC audio stream to the AVAudioSession. When the call ends, provider(_:didDeactivate:) is called, and you disconnect.

If you call AVAudioSession.setActive(true) before this moment, the call may drop or audio may not work. This is a common bug in first-time integrations.

Twilio Voice SDK: TwilioVoice.handleNotificationcall.accept(with: delegate) → in callDidConnect activate audio through CallKit. The SDK encapsulates part of this logic, but you still need your own CXProvider.

Call History and Siri

After the call ends, call provider.reportCall(with: uuid, endedAt: Date(), reason: .remoteEnded). iOS automatically adds a record to the Phone app’s call history with the name and duration. The user can call back from the Phone app — this will open a call through your app if the CXHandle of type .generic matches the identifier.

Siri Shortcuts for calls: through INStartCallIntent (iOS 13+), the app registers the intent. “Call Ivan using MyApp” — Siri starts a call via CallKit.

Common Problems

Duplicate Calls.

The UUID must be unique for each call and must not change between the push and the answer. If a push arrives twice (retry), check the UUID — do not create a second CXCallUpdate for the same UUID.

Stuck Call in History. If the app crashes without calling reportCall(endedAt:), the call remains as “active” in the history. Solution: at next app launch, check CXCallObserver.calls — if there are unfinished calls, end them.

VoIP Push on iOS 13+.

PKPushRegistry must be initialized in application(_:didFinishLaunchingWithOptions:), not lazily. Apple checks this and may terminate the app.

Comparison: CallKit vs Regular Push

Parameter Without CallKit With CallKit
Call display Push notification banner Full-screen interface with name and photo
Action buttons None (only “Later”) Answer, Decline, Remind Me
Call history entry No Automatic entry in the Phone app
Answer rate ~20-30% ~70-80% (based on client data)

Statistics are based on Apple CallKit documentation and real-world cases.

How Long Does CallKit Integration Take?

Basic implementation of incoming/outgoing calls with one VoIP SDK: 2–3 days. With group calls, video, Siri Shortcuts, and custom UI: 4–5 days. The cost is determined after analyzing your VoIP infrastructure and requirements. Contact us — we will evaluate your project and propose the optimal solution.

What Is Included in the Work

  • Setup of CXProvider and CXCallController with configuration tailored to the app’s needs
  • Integration of PushKit for VoIP push
  • Handlers for answer, decline, end, hold, mute
  • Connection to WebRTC/VoIP SDK (Twilio Voice, Agora, Daily, Vonage)
  • Audio session management through CallKit lifecycle
  • Call history recording
  • Crash scenario handling and unfinished call cleanup

We guarantee correct CallKit operation in accordance with Apple documentation. Over 5+ years, we have implemented more than 30 projects with VoIP and CallKit, so we know all the pitfalls.