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

@capacitor/contacts

v1.0.0

Published

Access, search, pick, create, update and remove device contacts.

Downloads

623

Readme

@capacitor/contacts

Access, search, pick, create, update and remove device contacts.

Install

To use npm

npm install @capacitor/contacts

To use yarn

yarn add @capacitor/contacts

Sync native files

npx cap sync

iOS

Add the NSContactsUsageDescription key to your app's Info.plist and describe why the app accesses the user's contacts; iOS crashes on first contacts access without it:

<key>NSContactsUsageDescription</key>
<string>We need access to contacts to search, save and remove them.</string>

Notes:

  • The plugin uses the modern Contacts framework (CNContactStore, never the deprecated AddressBook APIs), so it fully supports iOS 18+ Limited Access: find, save and remove operate on the subset the user shared with the app, and pickContact presents the system picker (which needs no permission and always shows the full contact list).
  • The note field is not supported on iOS: reading or writing it requires Apple's restricted com.apple.developer.contacts.notes entitlement. The field is omitted on read and ignored on save.
  • Contact ids are opaque CNContact identifiers; ids persisted by the legacy AddressBook-based Cordova plugin do not resolve after migration.

Android

The plugin declares READ_CONTACTS and WRITE_CONTACTS in its own manifest; Gradle manifest merging adds them to your app automatically. Each method requests the runtime permission it needs the first time it runs; read for find/pickContact, read + write for save/remove.

Permission model

This plugin intentionally exposes no checkPermissions() / requestPermissions() methods: permissions are requested implicitly by each method, matching the legacy cordova-plugin-contacts behavior. A call rejects with OS-PLUG-CONT-0020 when the user denies access.

Errors

Every rejection carries a structured code + message:

| Code | Meaning | | ------------------- | ----------------------------------- | | OS-PLUG-CONT-0000 | Unknown error | | OS-PLUG-CONT-0001 | Invalid argument (e.g. unknown id) | | OS-PLUG-CONT-0002 | Timeout (reserved, currently unused) | | OS-PLUG-CONT-0003 | Pending operation (e.g. picker already open) | | OS-PLUG-CONT-0004 | I/O error | | OS-PLUG-CONT-0005 | Not supported | | OS-PLUG-CONT-0006 | Operation cancelled (picker closed) | | OS-PLUG-CONT-0020 | Permission denied |

Usage

import { Contacts } from '@capacitor/contacts';

// Search every field for "ada" and return all matches with a phone number
const { contacts } = await Contacts.find({
  fields: ['*'],
  filter: 'ada',
  multiple: true,
  hasPhoneNumber: true,
});

// Create a contact
const saved = await Contacts.save({
  contact: {
    name: { givenName: 'Ada', familyName: 'Lovelace' },
    phoneNumbers: [{ type: 'mobile', value: '+351910000000' }],
    emails: [{ type: 'home', value: '[email protected]' }],
  },
});

// Update it (id present -> update)
await Contacts.save({ contact: { ...saved, nickname: 'Countess' } });

// Pick a contact with the native picker
const picked = await Contacts.pickContact();

// Remove it by id
await Contacts.remove({ id: saved.id! });

API

find(...)

find(options: ContactFindOptions) => Promise<ContactFindResult>

Queries the device contacts database and returns the matching contacts.

Requests the READ_CONTACTS (Android) / Contacts (iOS) permission internally the first time it runs; there is no separate permission method.

iOS 18+: under Limited Access the search runs against (and returns only) the subset of contacts the user shared with the app.

| Param | Type | | ------------- | ----------------------------------------------------------------- | | options | ContactFindOptions |

Returns: Promise<ContactFindResult>

Since: 1.0.0


save(...)

save(options: ContactSaveOptions) => Promise<Contact>

Persists a new contact or updates an existing one (matched by contact.id). Resolves with the full saved contact.

Requests the READ/WRITE_CONTACTS (Android) / Contacts (iOS) permission internally.

iOS 18+: works under Limited Access: new contacts are added to the app's accessible set; updating requires the target contact to be in that set (otherwise the call rejects with OS-PLUG-CONT-0001).

| Param | Type | | ------------- | ----------------------------------------------------------------- | | options | ContactSaveOptions |

Returns: Promise<Contact>

Since: 1.0.0


remove(...)

remove(options: ContactRemoveOptions) => Promise<void>

Removes the contact with the given id from the device contacts database. Rejects with OS-PLUG-CONT-0001 when no contact has that id (on iOS 18+ Limited Access, also when the contact is outside the accessible set).

Requests the READ/WRITE_CONTACTS (Android) / Contacts (iOS) permission internally.

| Param | Type | | ------------- | --------------------------------------------------------------------- | | options | ContactRemoveOptions |

Since: 1.0.0


pickContact()

pickContact() => Promise<Contact>

Launches the native contact picker UI and resolves with the contact the user selects. Rejects with OS-PLUG-CONT-0006 if the user cancels.

On iOS the system picker requires no permission and always shows the full contact list, even under iOS 18+ Limited Access (the picked contact is returned without joining the app's accessible set). On Android the READ_CONTACTS permission is requested internally to read the picked contact's details.

Returns: Promise<Contact>

Since: 1.0.0


Interfaces

ContactFindResult

Result of a {@link ContactsPlugin.find} call.

| Prop | Type | Description | Since | | -------------- | ---------------------- | ------------------------------------------ | ----- | | contacts | Contact[] | The contacts matching the search criteria. | 1.0.0 |

Contact

A single device contact.

| Prop | Type | Description | Since | | ------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | id | string | Globally unique, platform-assigned identifier. Absent for contacts not yet saved to the device. | 1.0.0 | | rawId | string | Android raw-contact id backing this aggregated contact. iOS leaves this unset. | 1.0.0 | | displayName | string | Name suitable for display to end users. | 1.0.0 | | name | ContactName | The structured name components. | 1.0.0 | | nickname | string | A casual name by which to address the contact. | 1.0.0 | | phoneNumbers | ContactField[] | The contact's phone numbers. | 1.0.0 | | emails | ContactField[] | The contact's email addresses. | 1.0.0 | | addresses | ContactAddress[] | The contact's postal addresses. | 1.0.0 | | ims | ContactField[] | The contact's instant-messaging handles. | 1.0.0 | | organizations | ContactOrganization[] | The contact's organizations. | 1.0.0 | | birthday | number | The contact's birthday as epoch milliseconds. | 1.0.0 | | note | string | A free-form note about the contact. iOS: not supported by default: reading/writing a contact's note requires Apple's restricted com.apple.developer.contacts.notes entitlement. Without it the field is omitted on read and ignored on save. Android has no such restriction. | 1.0.0 | | photos | ContactField[] | The contact's photos. Reads return type: 'url' with the value holding a reference to the image, never image bytes: on Android the contact's content:// photo URI, on iOS the path of a copy written to the app's temporary directory (cleared by the system). On save, the first entry is applied: pass type: 'base64' with base64 data, or type: 'url' with a local file:///content:// URI to import. | 1.0.0 | | categories | ContactField[] | User-defined categories associated with the contact. Read-only: populated from the contact's group memberships on Android, never returned on iOS (the Contacts framework has no equivalent), and ignored on save. | 1.0.0 | | urls | ContactField[] | Web pages associated with the contact. | 1.0.0 |

ContactName

Structured name of a {@link Contact}.

| Prop | Type | Description | Since | | --------------------- | ------------------- | ------------------------------------- | ----- | | formatted | string | The complete formatted name. | 1.0.0 | | familyName | string | Family (last) name. | 1.0.0 | | givenName | string | Given (first) name. | 1.0.0 | | middleName | string | Middle name. | 1.0.0 | | honorificPrefix | string | Honorific prefix (e.g. Mr., Dr.). | 1.0.0 | | honorificSuffix | string | Honorific suffix (e.g. Esq.). | 1.0.0 |

ContactField

A generic, repeatable contact field (phone number, email, IM, photo, URL, category).

| Prop | Type | Description | Since | | ----------- | -------------------- | -------------------------------------------------------------------------------- | ----- | | type | string | The kind of field, e.g. home, work, mobile. For photos, url or base64. | 1.0.0 | | value | string | The field value (phone number, email address, URI, etc.). | 1.0.0 | | pref | boolean | true if this is the contact's preferred value for the field. | 1.0.0 | | id | string | Platform-assigned id of this individual field entry. | 1.0.0 |

ContactAddress

A postal address of a {@link Contact}.

| Prop | Type | Description | Since | | ------------------- | -------------------- | -------------------------------------------------- | ----- | | id | string | Platform-assigned id of this address entry. | 1.0.0 | | pref | boolean | true if this is the contact's preferred address. | 1.0.0 | | type | string | The kind of address, e.g. home, work. | 1.0.0 | | formatted | string | The full address formatted for display. | 1.0.0 | | streetAddress | string | The street address. | 1.0.0 | | locality | string | The city or locality. | 1.0.0 | | region | string | The state or region. | 1.0.0 | | postalCode | string | The ZIP or postal code. | 1.0.0 | | country | string | The country name. | 1.0.0 |

ContactOrganization

An organization a {@link Contact} belongs to.

| Prop | Type | Description | Since | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ----- | | id | string | Platform-assigned id of this organization entry. Android only; iOS models the organization as flat contact properties without an id. | 1.0.0 | | pref | boolean | true if this is the contact's preferred organization. | 1.0.0 | | type | string | The kind of organization, e.g. work. | 1.0.0 | | name | string | The organization name. | 1.0.0 | | department | string | The department within the organization. | 1.0.0 | | title | string | The contact's title at the organization. | 1.0.0 |

ContactFindOptions

Search options accepted by {@link ContactsPlugin.find}.

| Prop | Type | Description | Since | | -------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | fields | ContactFieldType[] | Fields to search against. Pass ['*'] to match every field. An empty array is invalid and rejects with OS-PLUG-CONT-0001. The id field matches by exact identifier; all other fields match case-insensitive substrings. photos and categories are not searchable. | 1.0.0 | | filter | string | Search string matched (case-insensitively) against the selected fields. An empty/omitted filter returns every contact. | 1.0.0 | | multiple | boolean | When true, returns every match; when false (default), returns at most one contact. | 1.0.0 | | desiredFields | ContactFieldType[] | If set, each returned {@link Contact} only includes these fields (plus the always-present id). | 1.0.0 | | hasPhoneNumber | boolean | OutSystems extension: when true, only contacts that have at least one phone number are returned. Defaults to false. | 1.0.0 |

ContactSaveOptions

Options accepted by {@link ContactsPlugin.save}.

| Prop | Type | Description | Since | | ------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | contact | Contact | The contact to create (no id) or update (existing id). Update semantics: every field present on the contact replaces the stored value entirely (e.g. name replaces the whole structured name, phoneNumbers replaces all phone numbers); omitted fields are left unchanged. | 1.0.0 |

ContactRemoveOptions

Options accepted by {@link ContactsPlugin.remove}.

| Prop | Type | Description | Since | | -------- | ------------------- | --------------------------------------- | ----- | | id | string | The native id of the contact to remove. | 1.0.0 |

Type Aliases

ContactFieldType

The set of contact fields a {@link ContactsPlugin.find} call can search against or request back. Mirrors the legacy Cordova ContactFieldType string values exactly.

'addresses' | 'birthday' | 'categories' | 'country' | 'department' | 'displayName' | 'emails' | 'familyName' | 'formatted' | 'givenName' | 'honorificPrefix' | 'honorificSuffix' | 'id' | 'ims' | 'locality' | 'middleName' | 'name' | 'nickname' | 'note' | 'organizations' | 'phoneNumbers' | 'photos' | 'postalCode' | 'region' | 'streetAddress' | 'title' | 'urls'