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

@capgo/capacitor-incoming-call-kit

v8.2.1

Published

Capacitor plugin for native incoming call UI with Android full-screen notifications and iOS CallKit.

Readme

@capgo/capacitor-incoming-call-kit

Display a native incoming-call surface in Capacitor with Android full-screen notifications and iOS CallKit.

This plugin was built for teams who want something in the same space as olarewajuakeemope/capacitor-incoming-call-kit, but with a small API, typed events, clearer platform boundaries, and documentation you can actually ship from.

Documentation

The most complete doc is available here: https://capgo.app/docs/plugins/incoming-call-kit/

Compatibility

| Plugin version | Capacitor compatibility | Maintained | | -------------- | ----------------------- | ---------- | | v8.*.* | v8.*.* | ✅ | | v7.*.* | v7.*.* | On demand | | v6.*.* | v6.*.* | ❌ |

Note: The major version of this plugin follows the major version of Capacitor. Use the version that matches your Capacitor installation. Only the latest major version is actively maintained.

Install

bun add @capgo/capacitor-incoming-call-kit
bunx cap sync

What This Plugin Does

  • Shows a native incoming call UI from JavaScript.
  • Emits buffered callAccepted, callDeclined, callEnded, and callTimedOut events so the action still reaches JS if the bridge was cold.
  • Uses Android notifications plus a full-screen activity.
  • Uses iOS CallKit for the system incoming-call sheet.
  • Keeps the push transport out of scope so you can wire it to your own FCM, PushKit, SIP, or backend flow.

What This Plugin Does Not Do

  • It does not register FCM, APNs, or PushKit for you.
  • It does not create or manage the underlying audio/video session.
  • It does not replace your VoIP SDK. It only handles the native incoming-call presentation layer.

Quick Start

import { IncomingCallKit } from '@capgo/capacitor-incoming-call-kit';

await IncomingCallKit.requestPermissions();
await IncomingCallKit.requestFullScreenIntentPermission();

await IncomingCallKit.addListener('callAccepted', async ({ call }) => {
  console.log('Accepted:', call.callId, call.extra);
  // Join your voice/video session here.
});

await IncomingCallKit.addListener('callDeclined', ({ call }) => {
  console.log('Declined:', call.callId);
});

await IncomingCallKit.addListener('callTimedOut', ({ call }) => {
  console.log('Timed out:', call.callId);
});

await IncomingCallKit.showIncomingCall({
  callId: 'call-42',
  callerName: 'Ada Lovelace',
  handle: '+39 555 010 020',
  appName: 'Capgo Phone',
  hasVideo: true,
  timeoutMs: 45_000,
  extra: {
    roomId: 'room-42',
    callerUserId: 'user_ada',
  },
  android: {
    channelId: 'calls',
    channelName: 'Incoming Calls',
    showFullScreen: true,
  },
  ios: {
    handleType: 'phoneNumber',
  },
});

Event Model

  • incomingCallDisplayed: native UI was shown successfully.
  • callAccepted: the user accepted from the native UI.
  • callDeclined: the user declined before joining.
  • callEnded: your app or the platform ended the tracked call.
  • callTimedOut: the call stayed unanswered until timeoutMs.

Each event carries the normalized call payload and your original extra object.

Platform Notes

Android

  • requestPermissions() requests POST_NOTIFICATIONS on Android 13+.
  • requestFullScreenIntentPermission() opens the Android 14+ settings page for full-screen intents.
  • showIncomingCall() posts a high-priority notification and can raise a full-screen activity while the app is already running.
  • The timeout is best-effort and also uses the notification timeout when available.

iOS

  • showIncomingCall() reports the call to CallKit.
  • CallKit itself does not require a runtime permission prompt, so requestPermissions() resolves immediately on iOS.
  • Your app is responsible for starting the real call session after callAccepted.
  • If you need background incoming-call delivery from VoIP pushes, wire your PushKit/APNs flow to call this plugin as soon as your Capacitor bridge is available.

Choosing An Architecture

  • If your app already uses Twilio, Stream, Daily, or a SIP stack, use this plugin as the native ringing layer and keep the media session in your existing SDK.
  • If you only need foreground testing or a custom backend event, calling showIncomingCall() directly from JS is enough.
  • If you need true background delivery, pair this plugin with your own native push integration instead of baking a push provider into the plugin itself.

Example App

The repository includes example-app with a small control panel for:

  • requesting permissions,
  • showing a demo incoming call,
  • inspecting active calls,
  • and watching listener payloads in real time.

API

Capacitor API for presenting a native incoming-call surface.

showIncomingCall(...)

showIncomingCall(options: ShowIncomingCallOptions) => Promise<ShowIncomingCallResult>

Displays the native incoming call UI.

Android shows a high-priority notification and can raise a full-screen activity. iOS reports the call to CallKit.

| Param | Type | | ------------- | --------------------------------------------------------------------------- | | options | ShowIncomingCallOptions |

Returns: Promise<ShowIncomingCallResult>


endCall(...)

endCall(options: EndCallOptions) => Promise<ActiveCallsResult>

Ends a specific tracked call.

| Param | Type | | ------------- | --------------------------------------------------------- | | options | EndCallOptions |

Returns: Promise<ActiveCallsResult>


endAllCalls(...)

endAllCalls(options?: EndAllCallsOptions | undefined) => Promise<ActiveCallsResult>

Ends every tracked call.

| Param | Type | | ------------- | ----------------------------------------------------------------- | | options | EndAllCallsOptions |

Returns: Promise<ActiveCallsResult>


getActiveCalls()

getActiveCalls() => Promise<ActiveCallsResult>

Returns the currently tracked calls.

Returns: Promise<ActiveCallsResult>


checkPermissions()

checkPermissions() => Promise<IncomingCallPermissionStatus>

Returns the current permission state for notifications and full-screen intents.

Returns: Promise<IncomingCallPermissionStatus>


requestPermissions()

requestPermissions() => Promise<IncomingCallPermissionStatus>

Requests the notification permission when the platform supports it.

iOS CallKit itself does not require a runtime prompt, so iOS resolves without prompting.

Returns: Promise<IncomingCallPermissionStatus>


requestFullScreenIntentPermission()

requestFullScreenIntentPermission() => Promise<IncomingCallPermissionStatus>

Opens the Android 14+ full-screen intent settings page when available.

On other platforms this resolves with the current permission status.

Returns: Promise<IncomingCallPermissionStatus>


getPluginVersion()

getPluginVersion() => Promise<PluginVersionResult>

Returns the native implementation version marker.

Returns: Promise<PluginVersionResult>


addListener('incomingCallDisplayed', ...)

addListener(eventName: 'incomingCallDisplayed', listenerFunc: (event: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

Fired after the call has been handed to the native platform UI.

| Param | Type | | ------------------ | ----------------------------------------------------------------------------------- | | eventName | 'incomingCallDisplayed' | | listenerFunc | (event: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callAccepted', ...)

addListener(eventName: 'callAccepted', listenerFunc: (event: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

Fired when the user accepts the call from native UI.

| Param | Type | | ------------------ | ----------------------------------------------------------------------------------- | | eventName | 'callAccepted' | | listenerFunc | (event: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callDeclined', ...)

addListener(eventName: 'callDeclined', listenerFunc: (event: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

Fired when the user declines the call from native UI.

| Param | Type | | ------------------ | ----------------------------------------------------------------------------------- | | eventName | 'callDeclined' | | listenerFunc | (event: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callEnded', ...)

addListener(eventName: 'callEnded', listenerFunc: (event: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

Fired when a call ends through the API or a platform action.

| Param | Type | | ------------------ | ----------------------------------------------------------------------------------- | | eventName | 'callEnded' | | listenerFunc | (event: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


addListener('callTimedOut', ...)

addListener(eventName: 'callTimedOut', listenerFunc: (event: IncomingCallEvent) => void) => Promise<PluginListenerHandle>

Fired when an unanswered call reaches its configured timeout.

| Param | Type | | ------------------ | ----------------------------------------------------------------------------------- | | eventName | 'callTimedOut' | | listenerFunc | (event: IncomingCallEvent) => void |

Returns: Promise<PluginListenerHandle>


removeAllListeners()

removeAllListeners() => Promise<void>

Removes every native listener registered by the plugin.


Interfaces

ShowIncomingCallResult

Result payload for showIncomingCall().

| Prop | Type | Description | | ---------- | ----------------------------------------------------------------- | ------------------------------------------- | | call | IncomingCallRecord | The call record that was created or reused. |

IncomingCallRecord

Represents a currently tracked call.

| Prop | Type | Description | | ---------------- | --------------------------------------------------------------- | ------------------------------------------------------ | | callId | string | Stable call identifier provided by your app. | | callerName | string | Name shown in the native UI. | | handle | string | Secondary handle shown by the platform when available. | | hasVideo | boolean | Whether this call should be treated as a video call. | | state | IncomingCallState | Current platform-reported call state. | | platform | 'android' | 'ios' | 'web' | Platform that produced the record. | | extra | Record<string, any> | Arbitrary metadata passed in at call creation time. |

ShowIncomingCallOptions

Common options used to present an incoming call.

| Prop | Type | Description | | ----------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | callId | string | Stable identifier for the call. Reuse the same value when ending the call later. | | callerName | string | Primary name shown to the user. | | handle | string | Optional secondary handle such as a phone number, SIP URI, or user ID. | | appName | string | Label shown by Android in notifications. iOS uses the app display name configured in the host app bundle. | | hasVideo | boolean | Whether the incoming session should be marked as video-capable. | | timeoutMs | number | Best-effort timeout in milliseconds. Defaults to 60000. | | acceptText | string | Custom label for the accept action. Android only. | | declineText | string | Custom label for the decline action. Android only. | | extra | Record<string, any> | Arbitrary JSON metadata echoed back in all events. | | android | AndroidIncomingCallOptions | Android-specific behavior overrides. | | ios | IOSIncomingCallOptions | iOS-specific behavior overrides. |

AndroidIncomingCallOptions

Android-specific incoming call presentation options.

| Prop | Type | Description | | -------------------- | -------------------- | ------------------------------------------------------------------------------------------ | | channelId | string | Notification channel identifier. Defaults to incoming_call_kit. | | channelName | string | Notification channel display name. Defaults to Incoming Calls. | | showFullScreen | boolean | Whether Android should request full-screen presentation when possible. Defaults to true. | | accentColor | string | Optional accent color in #RRGGBB or #AARRGGBB form. | | ringtoneUri | string | Optional ringtone URI string. Example: android.resource://com.example.app/raw/ringtone | | isHighPriority | boolean | Whether to mark the notification as high priority. Defaults to true. |

IOSIncomingCallOptions

iOS-specific incoming call presentation options.

| Prop | Type | Description | | ------------------------ | --------------------------------------------------------- | ---------------------------------------------------------------- | | handleType | 'generic' | 'phoneNumber' | 'emailAddress' | CallKit handle type. Defaults to generic. | | supportsHolding | boolean | Whether the call should support hold. Defaults to true. | | supportsDTMF | boolean | Whether the call should support DTMF. Defaults to false. | | supportsGrouping | boolean | Whether the call should support grouping. Defaults to false. | | supportsUngrouping | boolean | Whether the call should support ungrouping. Defaults to false. |

ActiveCallsResult

Result payload for getActiveCalls().

| Prop | Type | Description | | ----------- | --------------------------------- | ------------------------------------------------- | | calls | IncomingCallRecord[] | Calls still tracked by the native implementation. |

EndCallOptions

Options for ending a single tracked call.

| Prop | Type | Description | | ------------ | ------------------- | -------------------------------------------------------------- | | callId | string | The call identifier originally passed to showIncomingCall(). | | reason | string | Optional application-defined reason string. |

EndAllCallsOptions

Options for ending all tracked calls.

| Prop | Type | Description | | ------------ | ------------------- | ------------------------------------------- | | reason | string | Optional application-defined reason string. |

IncomingCallPermissionStatus

Result payload for permission checks.

| Prop | Type | Description | | ---------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | notifications | PermissionState | 'notApplicable' | Notification permission state. iOS CallKit itself does not require runtime notification permission, so iOS returns notApplicable. | | fullScreenIntent | PermissionState | 'notApplicable' | Full-screen intent permission state. iOS returns notApplicable. Android 13 and below resolve this as granted. |

PluginVersionResult

Plugin version payload.

| Prop | Type | Description | | ------------- | ------------------- | ----------------------------------------------------------- | | version | string | Version identifier returned by the platform implementation. |

PluginListenerHandle

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

IncomingCallEvent

Payload delivered by plugin listeners.

| Prop | Type | Description | | ------------ | ----------------------------------------------------------------- | ----------------------------------------- | | call | IncomingCallRecord | The call that triggered the event. | | reason | string | Optional reason for the state transition. | | source | 'api' | 'user' | 'system' | Origin of the action. |

Type Aliases

IncomingCallState

Supported incoming call states.

'ringing' | 'accepted' | 'ended'

Record

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

{ [P in K]: T; }

PermissionState

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