npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ionic-callkit

v1.0.0-beta.4

Published

Native call UI for Ionic/Capacitor: CallKit + PushKit on iOS, ConnectionService + FCM on Android

Readme

ionic-callkit

Native incoming / outgoing call UI for Ionic & Capacitor 7 apps.

| Platform | Native layer | Push | |---|---|---| | Android | Self-managed ConnectionService (ported from react-native-callkeep), full-screen ringing notification, phoneCall foreground service | FCM (data-only, high priority) | | iOS | CallKit (CXProvider) | PushKit VoIP | | Web | Emits the same events so you can drive an HTML call screen | — |

The plugin shows and tracks the call. Media is yours: start your WebRTC / SIP session on callAnswered / callStarted and stop it on callEnded.

Status: Android, iOS and web implement the API below. Android is verified on an emulator; the iOS implementation (ported from callkeep's RNCallKeep.m) still needs its first build and device test — see WORK.md. The previous iOS plugin_events listener is gone; the legacy ConnectionId / Username push keys are still accepted.

Install

npm install ionic-callkit
npx cap sync

Requires Capacitor 7, Android 8.0+ (API 26) and iOS 14+.

Android setup

  1. Firebase — add your app in the Firebase console and place google-services.json in android/app/. The Capacitor Android template applies the Google Services plugin automatically when that file exists.
  2. minSdk 26 — in android/variables.gradle set minSdkVersion = 26.
  3. Permissions — the plugin manifest already declares everything self-managed mode needs (MANAGE_OWN_CALLS, RECORD_AUDIO, FOREGROUND_SERVICE_PHONE_CALL, FOREGROUND_SERVICE_MICROPHONE, POST_NOTIFICATIONS, USE_FULL_SCREEN_INTENT, …). At runtime call requestPermissions() for microphone + notifications.
  4. Full-screen intent (Android 14+) — Google Play only grants USE_FULL_SCREEN_INTENT by default to calling / alarm apps. Check canUseFullScreenIntent() and send the user to openFullScreenIntentSettings() if needed; without it a locked phone shows a heads-up notification instead of the full-screen call.
  5. Incoming-call screen — when the phone is locked or the screen is off, the ringing call opens a native full-screen call screen (caller, Answer, Decline) over the lock screen, even a PIN/biometric one; Answer then opens your app over the lock screen. When the phone is unlocked and in use, Android shows a heads-up notification with Answer/Decline instead (same as every calling app). Set android.incomingCallScreen: 'app' to open your own call page instead of the native screen. Translate / restyle the native screen by overriding the ionic_callkit_* strings and colors in your app's res/values.
  6. Ringtone — the plugin rings with the device ringtone and vibrates, following the phone's ringer mode (normal → sound + vibration, vibrate → vibration, silent → nothing); a volume-key press silences it. Custom sound: put a file in android/app/src/main/res/raw/ and set android.ringtoneSound: 'my_ring'; disable vibration with android.vibrate: false.
  7. Managed mode (optional) — setup({ android: { selfManaged: false } }) uses the system dialer UI instead. Add READ_PHONE_STATE, READ_PHONE_NUMBERS and CALL_PHONE to your app manifest, request the phone permission, and have the user enable the calling account (openPhoneAccountSettings()).

Using it with @capacitor/push-notifications

Both plugins work together with no extra setup. Android delivers FCM to a single FirebaseMessagingService; ionic-callkit's service is declared with a higher priority, handles call pushes (type: incoming_call / call_ended) itself, and forwards every other message and token refresh to @capacitor/push-notifications, so your pushNotificationReceived / registration listeners keep firing. Both plugins see the same FCM token.

If your app has its own FirebaseMessagingService, remove the plugin's from the merged manifest and pass call messages to it:

<service android:name="io.kreador.callkit.CallMessagingService" tools:node="remove" />
if (io.kreador.callkit.CallMessagingService.handleRemoteMessage(this, remoteMessage)) return;

Web

Browsers have no system call UI, so on the web your app renders the call screen (e.g. an ion-modal or a /call/:id page). The web implementation tracks calls and fires the same events as native, so the same listeners drive it. Web gets no pushes: call displayIncomingCall() when your own signalling (WebSocket, LiveKit room event, …) reports a call.

// Web: your signalling reports an incoming call
await CallKit.displayIncomingCall({ callId, callerName: 'Alice' });
// → 'incomingCall' fires → the same listener opens your call page

registerVoipToken, getAudioRoutes, setAudioRoute and the Android settings helpers reject with "not implemented" on web.

iOS setup

  1. Xcode → Signing & Capabilities: add Push Notifications and Background Modes → Voice over IP.

  2. Create a VoIP Services certificate on developer.apple.com/certificates, download it and import it into Keychain Access.

  3. Export it as .p12, then convert it for the test script:

    openssl pkcs12 -in YOUR_CERTIFICATES.p12 -out app.pem -nodes -clcerts

iOS notes

  • Every VoIP push must show a call. iOS 13+ terminates apps that receive a VoIP push without reporting a call to CallKit. The plugin reports calls synchronously from the push. For pushes it can't show (not a call payload, call_ended for an unknown call, busy) it reports and immediately ends a call, which can appear briefly or as a missed call. Prefer sending call_ended over your signalling or a regular (non-VoIP) push when the app is running.
  • Answering from the lock screen does not open the app. CallKit keeps the call in the system UI; your app is running in the background, so start media on callAnswered without relying on the WebView being visible.
  • Call ids: CallKit needs UUIDs. Use UUIDs as callId if you can; other strings work too and are mapped internally.
  • Early PushKit registration (recommended): call CallKitVoip.start() in application(_:didFinishLaunchingWithOptions:) (import IonicCallkit with CocoaPods, import CallKitPlugin with SPM). The plugin also registers when it loads, but registering at launch means a VoIP push that starts the app doesn't wait for the WebView.
  • Audio: ios.audioSession.autoConfigure: false lets your media SDK own AVAudioSession; otherwise the plugin configures play-and-record with Bluetooth when CallKit activates the session.
  • Not available on iOS: backToForeground, openPhoneAccountSettings, openFullScreenIntentSettings (reject as unimplemented); setAvailable, setReachable are no-ops; showIncomingCallUi / silenceIncomingCall / checkReachability / hasActiveCall are Android-only events.

Usage

import { CallKit } from 'ionic-callkit';

// Register listeners first: events that happened while the app was starting
// (e.g. the user answered from the lock screen) are delivered as soon as you listen.
await CallKit.addListener('voipToken', ({ token }) => {
  // POST the token to your backend (PushKit token on iOS, FCM token on Android)
});

await CallKit.addListener('incomingCall', ({ callId, callerName }) => {
  router.navigate(['/call', callId]);
});

await CallKit.addListener('callAnswered', ({ callId }) => webrtc.startSession(callId));
await CallKit.addListener('callEnded', ({ callId }) => webrtc.endSession(callId));
await CallKit.addListener('callRejected', ({ callId }) => signalling.decline(callId));

await CallKit.setup({ appName: 'My App', supportsVideo: true });
await CallKit.requestPermissions();
await CallKit.registerVoipToken();

Outgoing:

await CallKit.startCall({ callId, calleeName: 'Bob', handle: '[email protected]' });
// …when the remote side picks up:
await CallKit.setCallActive({ callId });
// …when it hangs up:
await CallKit.reportEndCall({ callId, reason: CallEndReason.RemoteEnded });

A complete Ionic Angular demo lives in example/.

Cold starts, reachability and concurrency (Android)

  • Cold start: when a push wakes a killed app, events raised before your listeners exist (incomingCall, callAnswered from the lock screen, …) are queued natively, persisted, and delivered as soon as you add listeners. getInitialEvents() also returns them (oldest first) so you can route straight to the call screen at startup; call clearInitialEvents() once handled. Events marked restored: true come from a previous process that died before delivering them — Android has already dropped those calls.
  • Reachability watchdog: if a call is answered but your app never comes up to handle it, the plugin ends it after android.answerReachabilityTimeout ms (default 10000, 0 disables). Adding a callAnswered listener or calling setReachable() marks the app as ready.
  • Call state: setCallState({ callId, state }) reports dialing / ringing / active / held to the system; every change is emitted as callStateChanged.
  • One call at a time: setCanMakeMultipleCalls({ allow: false }) (or android.canMakeMultipleCalls: false) refuses a second incoming call with incomingCallFailed { error: 'busy' } and makes startCall reject — tell the caller "busy" from that event.

Backend contract

The plugin only produces tokens; your server sends the pushes. Never ship APNs / FCM credentials in the app.

Both platforms read the same keys:

| Key | Required | Notes | |---|---|---| | type | no | incoming_call (default) or call_ended (caller hung up / cancelled) | | callId | yes | Your call id; every event carries it | | callerName | no | Shown in the call UI | | handle | no | Number / user id; defaults to callerName | | hasVideo | no | "true" / "false" |

The legacy keys ConnectionId / Username are still accepted.

Use a new callId per call (a UUID is ideal — iOS uses it directly). Pushes are de-duplicated per call id, and a push for a call id that ended in the last 5 minutes is ignored, so retries and a call_ended that overtakes its incoming_call never ring a finished call.

iOS — APNs VoIP push (https://api.push.apple.com/3/device/<token>, headers apns-topic: <bundle>.voip, apns-push-type: voip, apns-priority: 10):

{
  "aps": { "alert": "Incoming call", "content-available": 1 },
  "type": "incoming_call",
  "callId": "abc-123",
  "callerName": "Alice",
  "hasVideo": "false"
}

iOS 13+ terminates apps that receive a VoIP push without reporting a call, so only send VoIP pushes for real incoming calls.

Android — FCM HTTP v1 (POST https://fcm.googleapis.com/v1/projects/<project>/messages:send). The message must be data-only (no notification block) with high priority, otherwise it will not reach the app while it is killed:

{
  "message": {
    "token": "<fcm token>",
    "android": { "priority": "high", "ttl": "30s" },
    "data": { "type": "incoming_call", "callId": "abc-123", "callerName": "Alice", "hasVideo": "false" }
  }
}

Test scripts

# iOS (needs app.pem in the current directory)
dev/sendVoip.sh <callId> <voipToken> <bundleId> [hasVideo] [callerName] [sandbox|production]

# Android (service account JSON from Firebase → Project settings → Service accounts)
dev/sendFcm.sh <service-account.json> <fcmToken> [callId] [callerName] [hasVideo]
dev/sendFcm.sh <service-account.json> <fcmToken> <callId> --end

For production APNs use api.push.apple.com; sending a sandbox token there returns BadDeviceToken.

Credits

The Android implementation is a port of livekit/react-native-callkeep (ISC, © The CallKeep Authors), adapted for Capacitor.

API

setup(...)

setup(options: CallSetupOptions) => Promise<void>

Configure the plugin. Call once at app start, before any other call method.

Android: registers the PhoneAccount with Telecom and stores the settings so that a push received while the app is killed can still ring.

| Param | Type | | ------------- | ------------------------------------------------------------- | | options | CallSetupOptions |


registerVoipToken()

registerVoipToken() => Promise<{ token: string; }>

Get the push token used to ring this device. iOS: PushKit VoIP token. Android: FCM registration token. Also emitted as the voipToken event (including on token refresh).

Returns: Promise<{ token: string; }>


unregisterVoipToken()

unregisterVoipToken() => Promise<void>

Stop receiving call pushes (Android: deletes the FCM token).


displayIncomingCall(...)

displayIncomingCall(options: IncomingCallOptions) => Promise<void>

Show the native incoming call UI. Normally triggered natively by a push; call it yourself when the call arrives over your own signalling channel.

| Param | Type | | ------------- | ------------------------------------------------------------------- | | options | IncomingCallOptions |


answerCall(...)

answerCall(options: CallIdOptions) => Promise<void>

Answer a ringing call from your own UI. Emits callAnswered.

| Param | Type | | ------------- | ------------------------------------------------------- | | options | CallIdOptions |


rejectCall(...)

rejectCall(options: CallIdOptions) => Promise<void>

Decline a ringing call. Emits callRejected.

| Param | Type | | ------------- | ------------------------------------------------------- | | options | CallIdOptions |


startCall(...)

startCall(options: OutgoingCallOptions) => Promise<void>

Start an outgoing call. Emits callStarted.

| Param | Type | | ------------- | ------------------------------------------------------------------- | | options | OutgoingCallOptions |


setCallActive(...)

setCallActive(options: CallIdOptions) => Promise<void>

Mark an outgoing call as connected (remote side picked up).

| Param | Type | | ------------- | ------------------------------------------------------- | | options | CallIdOptions |


setCallState(...)

setCallState(options: { callId: string; state: SettableCallState; }) => Promise<void>

Report the call's connection state to the system (callkeep's setConnectionState), e.g. dialing while your signalling connects, active once media flows. Emits callStateChanged.

| Param | Type | | ------------- | ------------------------------------------------------------------------------------------- | | options | { callId: string; state: SettableCallState; } |


endCall(...)

endCall(options: CallIdOptions) => Promise<void>

Hang up a call locally. Emits callEnded.

| Param | Type | | ------------- | ------------------------------------------------------- | | options | CallIdOptions |


endAllCalls()

endAllCalls() => Promise<void>

Hang up every call.


reportEndCall(...)

reportEndCall(options: ReportEndCallOptions) => Promise<void>

Report that a call ended for a reason other than the local user hanging up (remote hang-up, missed, answered elsewhere…). Does not emit callEnded.

| Param | Type | | ------------- | --------------------------------------------------------------------- | | options | ReportEndCallOptions |


updateDisplay(...)

updateDisplay(options: UpdateDisplayOptions) => Promise<void>

Update the name / handle shown in the system call UI.

| Param | Type | | ------------- | --------------------------------------------------------------------- | | options | UpdateDisplayOptions |


setMuted(...)

setMuted(options: { callId: string; muted: boolean; }) => Promise<void>

Update the mute state shown in the system UI. Emits muted. The plugin does not touch your media tracks — mute them in your WebRTC layer.

| Param | Type | | ------------- | ------------------------------------------------ | | options | { callId: string; muted: boolean; } |


setSpeaker(...)

setSpeaker(options: { on: boolean; callId?: string; }) => Promise<void>

Route audio to the loudspeaker or back to the earpiece. Emits speakerChanged.

| Param | Type | | ------------- | ---------------------------------------------- | | options | { on: boolean; callId?: string; } |


setOnHold(...)

setOnHold(options: { callId: string; hold: boolean; }) => Promise<void>

Put a call on hold / resume it. Emits held.

| Param | Type | | ------------- | ----------------------------------------------- | | options | { callId: string; hold: boolean; } |


sendDTMF(...)

sendDTMF(options: { callId: string; digits: string; }) => Promise<void>

Play DTMF digits on a call. Emits dtmf.

| Param | Type | | ------------- | ------------------------------------------------ | | options | { callId: string; digits: string; } |


getAudioRoutes()

getAudioRoutes() => Promise<{ routes: AudioRoute[]; }>

List available audio routes. Android and iOS.

Returns: Promise<{ routes: AudioRoute[]; }>


setAudioRoute(...)

setAudioRoute(options: { callId: string; route: AudioRouteType; }) => Promise<void>

Select an audio route. Android and iOS.

| Param | Type | | ------------- | ------------------------------------------------------------------------------------- | | options | { callId: string; route: AudioRouteType; } |


setAvailable(...)

setAvailable(options: { available: boolean; }) => Promise<void>

Tell the ConnectionService whether the app can take calls (e.g. false while logged out) so the user doesn't get stuck in the native UI. Android only; no-op elsewhere.

| Param | Type | | ------------- | ------------------------------------ | | options | { available: boolean; } |


setReachable()

setReachable() => Promise<void>

Tell the plugin the JS layer is ready to handle calls. Android only. Adding a callAnswered listener counts as reachable too. Answered calls are ended if the app isn't reachable within android.answerReachabilityTimeout.


setCanMakeMultipleCalls(...)

setCanMakeMultipleCalls(options: { allow: boolean; }) => Promise<void>

Allow or refuse concurrent calls. When false, a new incoming call while another is in progress is refused and incomingCallFailed is emitted with error: 'busy', and startCall rejects. Persisted, so pushes handled while the app is killed respect it.

| Param | Type | | ------------- | -------------------------------- | | options | { allow: boolean; } |


getInitialEvents()

getInitialEvents() => Promise<{ events: InitialEvent[]; }>

Events that happened before JS attached (e.g. the call was answered from the lock screen during a cold start), oldest first. They are also delivered to listeners; use this to route directly at startup. Events with restored: true come from a previous app process that died before delivering them — their calls no longer exist. Kept until clearInitialEvents(). Android and iOS (empty on web).

Returns: Promise<{ events: InitialEvent[]; }>


clearInitialEvents()

clearInitialEvents() => Promise<void>

Forget the events returned by getInitialEvents().


hasPhoneAccount()

hasPhoneAccount() => Promise<{ value: boolean; }>

Whether the calling account is registered and enabled. Always true in self-managed mode. Android only.

Returns: Promise<{ value: boolean; }>


openPhoneAccountSettings()

openPhoneAccountSettings() => Promise<void>

Open the system "Calling accounts" screen (managed mode). Android only.


canUseFullScreenIntent()

canUseFullScreenIntent() => Promise<{ value: boolean; }>

Whether the app may show a full-screen incoming call over the lock screen. Android 14+ may revoke this. Android only.

Returns: Promise<{ value: boolean; }>


openFullScreenIntentSettings()

openFullScreenIntentSettings() => Promise<void>

Open the settings page to grant full-screen intents (Android 14+).


backToForeground()

backToForeground() => Promise<void>

Bring the app to the foreground (e.g. after answering from the lock screen). Android only; rejects as unimplemented on iOS, which doesn't allow it.


getActiveCalls()

getActiveCalls() => Promise<{ calls: ActiveCall[]; }>

Currently tracked calls.

Returns: Promise<{ calls: ActiveCall[]; }>


checkPermissions()

checkPermissions() => Promise<CallKitPermissionStatus>

Returns: Promise<CallKitPermissionStatus>


requestPermissions(...)

requestPermissions(options?: { permissions: CallKitPermissionType[]; } | undefined) => Promise<CallKitPermissionStatus>

| Param | Type | | ------------- | ------------------------------------------------------ | | options | { permissions: CallKitPermissionType[]; } |

Returns: Promise<CallKitPermissionStatus>


addListener('voipToken', ...)

addListener(eventName: 'voipToken', listenerFunc: (data: { token: string; }) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | -------------------------------------------------- | | eventName | 'voipToken' | | listenerFunc | (data: { token: string; }) => void |

Returns: Promise<PluginListenerHandle>


addListener('incomingCall', ...)

addListener(eventName: 'incomingCall', listenerFunc: (data: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ---------------------------------------------------------------------------------- | | eventName | 'incomingCall' | | listenerFunc | (data: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callAnswered', ...)

addListener(eventName: 'callAnswered', listenerFunc: (data: CallAnsweredEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ---------------------------------------------------------------------------------- | | eventName | 'callAnswered' | | listenerFunc | (data: CallAnsweredEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callStarted', ...)

addListener(eventName: 'callStarted', listenerFunc: (data: CallStartedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | -------------------------------------------------------------------------------- | | eventName | 'callStarted' | | listenerFunc | (data: CallStartedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callEnded', ...)

addListener(eventName: 'callEnded', listenerFunc: (data: CallEndedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ---------------------------------------------------------------------------- | | eventName | 'callEnded' | | listenerFunc | (data: CallEndedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callRejected', ...)

addListener(eventName: 'callRejected', listenerFunc: (data: CallEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------------------------------------ | | eventName | 'callRejected' | | listenerFunc | (data: CallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('muted', ...)

addListener(eventName: 'muted', listenerFunc: (data: MutedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | -------------------------------------------------------------------- | | eventName | 'muted' | | listenerFunc | (data: MutedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('held', ...)

addListener(eventName: 'held', listenerFunc: (data: HeldEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------------------------------------ | | eventName | 'held' | | listenerFunc | (data: HeldEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callStateChanged', ...)

addListener(eventName: 'callStateChanged', listenerFunc: (data: CallStateChangedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------------------------------------------------------------ | | eventName | 'callStateChanged' | | listenerFunc | (data: CallStateChangedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('dtmf', ...)

addListener(eventName: 'dtmf', listenerFunc: (data: DtmfEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------------------------------------ | | eventName | 'dtmf' | | listenerFunc | (data: DtmfEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('speakerChanged', ...)

addListener(eventName: 'speakerChanged', listenerFunc: (data: SpeakerChangedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | -------------------------------------------------------------------------------------- | | eventName | 'speakerChanged' | | listenerFunc | (data: SpeakerChangedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('audioRouteChanged', ...)

addListener(eventName: 'audioRouteChanged', listenerFunc: (data: AudioRouteChangedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | -------------------------------------------------------------------------------------------- | | eventName | 'audioRouteChanged' | | listenerFunc | (data: AudioRouteChangedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('audioSessionActivated', ...)

addListener(eventName: 'audioSessionActivated', listenerFunc: () => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------ | | eventName | 'audioSessionActivated' | | listenerFunc | () => void |

Returns: Promise<PluginListenerHandle>


addListener('showIncomingCallUi', ...)

addListener(eventName: 'showIncomingCallUi', listenerFunc: (data: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ---------------------------------------------------------------------------------- | | eventName | 'showIncomingCallUi' | | listenerFunc | (data: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('silenceIncomingCall', ...)

addListener(eventName: 'silenceIncomingCall', listenerFunc: (data: CallEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------------------------------------ | | eventName | 'silenceIncomingCall' | | listenerFunc | (data: CallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('incomingCallFailed', ...)

addListener(eventName: 'incomingCallFailed', listenerFunc: (data: CallFailedEvent) => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ------------------------------------------------------------------------------ | | eventName | 'incomingCallFailed' | | listenerFunc | (data: CallFailedEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('checkReachability', ...)

addListener(eventName: 'checkReachability', listenerFunc: () => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | -------------------------------- | | eventName | 'checkReachability' | | listenerFunc | () => void |

Returns: Promise<PluginListenerHandle>


addListener('hasActiveCall', ...)

addListener(eventName: 'hasActiveCall', listenerFunc: () => void) => Promise<PluginListenerHandle>

| Param | Type | | ------------------ | ---------------------------- | | eventName | 'hasActiveCall' | | listenerFunc | () => void |

Returns: Promise<PluginListenerHandle>


removeAllListeners()

removeAllListeners() => Promise<void>

Interfaces

CallSetupOptions

| Prop | Type | Description | | ------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | appName | string | Name of the calling account on Android. Defaults to the app label. iOS always shows the app's display name (CallKit no longer accepts a custom one). | | supportsVideo | boolean | Default: false | | imageName | string | Android drawable / iOS asset name used as the calling account / CallKit icon. | | android | AndroidSetupOptions | | | ios | IOSSetupOptions | |

AndroidSetupOptions

| Prop | Type | Description | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | selfManaged | boolean | Self-managed ConnectionService: the app owns the call UI and no "enable calling account" step is needed. Default: true. Set to false for managed mode (system dialer UI, needs phone permissions). | | showIncomingCallNotification | boolean | Show the plugin's native incoming-call notification (full-screen intent + Answer/Decline) in self-managed mode. Default: true. | | incomingCallScreen | 'native' | 'app' | What the full-screen incoming-call alert opens over the lock screen: - native (default): the plugin's built-in call screen (caller + Answer / Decline). Shows instantly and reliably over a secure lock screen; Answer then opens your app. - app: your app's own call page (listen to incomingCall). Needs the WebView to load first. Restyle / translate the native screen by overriding the ionic_callkit_* resources. | | ringtoneSound | string | Ringtone file in android/app/src/main/res/raw/ (name with or without extension). Default: the device ringtone. The plugin rings itself; silent / vibrate modes are respected. | | vibrate | boolean | Vibrate while ringing (unless the phone is on silent). Default: true. | | notificationIcon | string | Small icon (drawable or mipmap resource name) for call notifications. | | incomingCallChannelName | string | Channel name for incoming calls. Default: "Incoming calls". | | foregroundService | false | { channelId?: string; channelName?: string; notificationTitle?: string; notificationIcon?: string; } | Ongoing-call foreground service notification (keeps the mic alive in the background). Enabled by default; pass false to disable. | | canMakeMultipleCalls | boolean | Allow more than one simultaneous call. Default: true. See setCanMakeMultipleCalls. | | answerReachabilityTimeout | number | End an answered call if the app hasn't called setReachable() (or added a callAnswered listener) within this many milliseconds — e.g. the WebView failed to start after answering from the lock screen. Default: 10000. 0 disables. | | displayCallReachabilityTimeout | number | If set, an incoming call is dropped when the JS layer hasn't called setReachable() within this many milliseconds. |

IOSSetupOptions

| Prop | Type | Description | | ------------------------------ | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ringtoneSound | string | Ringtone sound file in the app bundle. | | maximumCallGroups | number | Default: 1 | | maximumCallsPerCallGroup | number | Default: 1 | | includesCallsInRecents | boolean | Default: false | | handleType | 'number' | 'generic' | 'email' | CallKit handle type for handle values. Default: generic. | | audioSession | { autoConfigure?: boolean; categoryOptions?: number; mode?: string; } | Audio session CallKit activates for the call (callkeep's audioSession setting). Set autoConfigure: false if your media SDK configures AVAudioSession itself. |

IncomingCallOptions

| Prop | Type | Description | | ---------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------- | | callId | string | | | callerName | string | | | handle | string | Phone number / user id shown as the caller address. Defaults to callerName. | | hasVideo | boolean | | | payload | Record<string, string> | Extra data passed back in the incomingCall event. |

CallIdOptions

| Prop | Type | | ------------ | ------------------- | | callId | string |

OutgoingCallOptions

| Prop | Type | Description | | ---------------- | -------------------- | --------------------------------------------------------------- | | callId | string | | | calleeName | string | | | handle | string | Phone number / user id of the callee. Defaults to calleeName. | | hasVideo | boolean | |

ReportEndCallOptions

| Prop | Type | | ------------ | ------------------------------------------------------- | | callId | string | | reason | CallEndReason |

UpdateDisplayOptions

| Prop | Type | | ---------------- | ------------------- | | callId | string | | callerName | string | | handle | string |

AudioRoute

| Prop | Type | | -------------- | --------------------------------------------------------- | | name | string | | type | AudioRouteType | | selected | boolean |

InitialEvent

| Prop | Type | Description | | --------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------- | | name | string | Event name, e.g. incomingCall, callAnswered. | | data | Record<string, unknown> | | | timestamp | number | Epoch milliseconds. | | restored | boolean | From a previous app process that died before delivering it; the call is gone. |

ActiveCall

| Prop | Type | | ---------------- | ----------------------------------------------- | | callId | string | | callerName | string | | handle | string | | state | CallState |

CallKitPermissionStatus

| Prop | Type | | ------------------- | ----------------------------------------------------------- | | microphone | PermissionState | | notifications | PermissionState | | phone | PermissionState |

PluginListenerHandle

| Prop | Type | | ------------ | ----------------------------------------- | | remove | () => Promise<void> |

IncomingCallEvent

| Prop | Type | | ---------------- | --------------------------------------------------------------- | | callerName | string | | handle | string | | hasVideo | boolean | | payload | Record<string, string> |

CallAnsweredEvent

| Prop | Type | | -------------- | -------------------- | | hasVideo | boolean |

CallStartedEvent

| Prop | Type | | ---------------- | ------------------- | | calleeName | string | | handle | string |

CallEndedEvent

| Prop | Type | Description | | ------------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | reason | CallEndReason | Set when the call was ended remotely by a call_ended push (Missed if it was never answered, otherwise RemoteEnded). Absent when the user hung up. |

CallEvent

| Prop | Type | | ------------ | ------------------- | | callId | string |

MutedEvent

| Prop | Type | | ----------- | -------------------- | | muted | boolean |

HeldEvent

| Prop | Type | | ---------- | -------------------- | | hold | boolean |

CallStateChangedEvent

| Prop | Type | | ----------- | ----------------------------------------------- | | state | CallState |

DtmfEvent

| Prop | Type | | ------------ | ------------------- | | digits | string |

SpeakerChangedEvent

| Prop | Type | | ------------ | -------------------- | | callId | string | | on | boolean |

AudioRouteChangedEvent

| Prop | Type | Description | | ------------ | ------------------- | ----------------------------------------------------------------------- | | callId | string | | | output | string | Android: EARPIECE | SPEAKER | WIRED_HEADSET | BLUETOOTH | STREAMING |

CallFailedEvent

| Prop | Type | | ---------------- | ------------------- | | callerName | string | | handle | string | | error | string |

Type Aliases

Record

Construct a type with a set of properties K of type T

{ [P in K]: T; }

SettableCallState

States an app may set with setCallState.

'initializing' | 'ringing' | 'dialing' | 'active' | 'held'

AudioRouteType

'Phone' | 'Speaker' | 'Headset' | 'Bluetooth'

CallState

Connection states reported by callStateChanged / getActiveCalls.

'initializing' | 'new' | 'ringing' | 'dialing' | 'active' | 'held' | 'disconnected' | 'pulling'

PermissionState

'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'

CallKitPermissionType

  • microphone: RECORD_AUDIO
  • notifications: POST_NOTIFICATIONS (Android 13+)
  • phone: READ_PHONE_STATE / CALL_PHONE — managed mode only; must be declared in your app manifest

'microphone' | 'notifications' | 'phone'

Enums

CallEndReason

| Members | Value | | ----------------------- | -------------- | | Failed | 1 | | RemoteEnded | 2 | | Unanswered | 3 | | AnsweredElsewhere | 4 | | DeclinedElsewhere | 5 | | Missed | 6 |