Skip to content

CallKit & LiveCommunicationKit ​

CallKit integrates your VoIP app with the system call UI — the full-screen incoming-call screen, the lock screen, Recents, Do Not Disturb, and audio routing. LiveCommunicationKit (iOS 17.4+) extends the model to Apple Watch and visionOS and powers default calling/dialer apps. IdentityLookup handles caller identification, blocking, and message filtering.

Part of the axiom-integration suite (skills/callkit-livecommunicationkit.md and skills/callkit-livecommunicationkit-ref.md).

When to Use ​

Use this skill when you're:

  • Building a VoIP calling app (incoming/outgoing calls, hold, mute, DTMF)
  • Wiring VoIP push notifications to the system call UI
  • Diagnosing "my app gets killed" / "VoIP pushes stopped arriving"
  • Fixing call audio that's silent, routed wrong, or doesn't start
  • Reaching Apple Watch / visionOS, or becoming a default calling/dialer app
  • Identifying or blocking spam callers, or filtering messages

Example Prompts ​

  • "My VoIP app gets killed when a call comes in"
  • "How do I report a CallKit call from a PushKit push?"
  • "Why is my call audio silent?"
  • "How do I make an outgoing call with CallKit?"
  • "How do I block spam callers?"
  • "What's LiveCommunicationKit for?"

Key Concepts ​

The PushKit rule (the one that bricks your app) ​

When built against the iOS 13 SDK or later, a VoIP push must report a call — to CallKit via reportNewIncomingCall(...), or to LiveCommunicationKit via reportNewIncomingConversation(...) — before the push handler's completion() runs. If it doesn't, iOS terminates your app and stops delivering VoIP pushes entirely. From iOS 26.4 the requirement is decided per push: PushKit's newer delegate hands you a PKVoIPPushMetadata whose mustReport is false for pushes you're already handling, and those need no report. The older delegate carries no such signal, so it reports on every push. Report the call immediately with what you have, then do the network round-trip. Never use VoIP pushes for non-call data.

CallKit owns the audio session ​

You configure the audio category, but CallKit activates the session. Start audio only in provider(_:didActivate:) and stop it in provider(_:didDeactivate:). Activating AVAudioSession yourself produces silent or misrouted audio.

Fulfill every action ​

System-initiated actions (provider(_:perform:) for answer/end/hold/mute/DTMF) must call action.fulfill() or .fail(), or the call gets stuck and times out.

LiveCommunicationKit complements CallKit ​

It's not a replacement — it expands the model to watchOS 10.4+ and visionOS 1.1+ and enables default calling (com.apple.developer.calling-app, iOS 18.2+) and default dialer (com.apple.developer.dialing-app, EU) apps. Use CallKit on iOS as the baseline.

Caller ID: bulk vs real-time ​

CXCallDirectoryProvider supplies a bulk, offline, ascending-ordered list to identify/block — no runtime lookups. Live Caller ID Lookup (iOS 18+, LiveCallerIDLookupManager) does real-time identification via Private Information Retrieval so your server never learns who's calling whom.

Common Mistakes ​

MistakeCostFix
Not reporting a call on a VoIP push that required a reportApp killed, pushes cut offReport in the push handler before completion(). On iOS 26.4+ the metadata delegate lets you skip pushes whose mustReport is false; the older delegate has no such signal, so report on every push
Network work before reportingPush times outReport first, fetch after
Activating AVAudioSession yourselfSilent / misrouted audioStart audio in provider(_:didActivate:)
Not fulfilling a CXActionStuck callfulfill() / fail() every action
VoIP push for non-call dataSame kill penaltyUse APNs / UserNotifications
Expecting runtime lookups from a Call DirectoryNo live dataUse Live Caller ID Lookup (iOS 18+)
  • Push Notifications – PushKit VoIP vs APNs delivery
  • For the call audio session category (.playAndRecord), see the axiom-media suite
  • For LiveCommunicationKit on Apple Watch, see the axiom-watchos suite

Resources ​

WWDC: 2016-230, 2019-707, 2020-10113

Docs: /callkit, /callkit/cxprovider, /callkit/cxcallcontroller, /callkit/cxproviderdelegate, /pushkit, /livecommunicationkit, /livecommunicationkit/conversationmanager, /identitylookup, /identitylookup/livecalleridlookupmanager

Released under the MIT License