---
title: Exploring the Capacitor Contacts API
description: "Practical guide to the Capacitor Contacts API: read, write, and select device contacts in your Ionic and Capacitor apps."
date: 
  created: 2025-07-17
  updated: 2026-07-17
authors:
  - robingenz
categories:
  - Capacitor
  - Guides
  - SDKs
links:
  - Capacitor Contacts: sdks/capacitor/contacts.md
faq: true
---

# Exploring the Capacitor Contacts API

Many mobile apps need access to device contacts, from social features to communication tools. The [Capacitor Contacts plugin](../../sdks/capacitor/contacts.md) from Capawesome lets you create, read, update, and delete contacts on Android, iOS, and Web through one API, so you do not have to write a separate implementation for each platform.

<!-- more -->

## Installation

To install the Capacitor Contacts plugin, please refer to the [Installation](../../sdks/capacitor/contacts.md/#installation) section in the plugin documentation.

## Usage

Let's explore the key features of the Capacitor Contacts API and how to implement them effectively in your Ionic applications.

### Checking Availability

Before implementing contact functionality, verify that contact features are available on the device. The Capacitor Contacts API provides the [`isAvailable(...)`](../../sdks/capacitor/contacts.md#isavailable) method for this purpose:

```ts
import { Contacts } from '@capawesome-team/capacitor-contacts';

const checkAvailability = async () => {
  const { isAvailable } = await Contacts.isAvailable();

  if (isAvailable) {
    console.log('Contacts API is ready to use!');
  } else {
    console.log('Contacts API is not available on this device.');
  }
};
```

If contacts are not available, disable the contact-related features or fall back to alternative functionality.

### Handling Permissions

Contact access requires permissions. Use the [`checkPermissions(...)`](../../sdks/capacitor/contacts.md#checkpermissions) and [`requestPermissions(...)`](../../sdks/capacitor/contacts.md#requestpermissions) methods to manage contact permissions:

```ts
import { Contacts } from '@capawesome-team/capacitor-contacts';

const checkPermissions = async () => {
  const { readContacts, writeContacts } = await Contacts.checkPermissions();

  if (readContacts !== 'granted') {
    console.log('Contacts can not be read.');
  }
  if (writeContacts !== 'granted') {
    console.log('Contacts can not be written.');
  }
};

const requestPermissions = async () => {
  const { readContacts, writeContacts } = await Contacts.requestPermissions();

  if (readContacts !== 'granted') {
    console.log('Contacts can not be read.');
  }
  if (writeContacts !== 'granted') {
    console.log('Contacts can not be written.');
  }
};
```

Always check and request permissions before performing contact operations.

### Creating a Contact

Use the [`createContact(...)`](../../sdks/capacitor/contacts.md#createcontact) method to create a new contact:

```ts
import { Contacts, EmailAddressType, PhoneNumberType } from '@capawesome-team/capacitor-contacts';

const createContact = async () => {
  const newContact = {
    givenName: 'John',
    familyName: 'Doe',
    organizationName: 'Capawesome',
    phoneNumbers: [
      {
        value: '+1-555-123-4567',
        type: PhoneNumberType.Mobile,
      },
    ],
    emailAddresses: [
      {
        value: 'john.doe@example.com',
        type: EmailAddressType.Work,
      },
    ],
    postalAddresses: [
      {
        street: '123 Main Street',
        city: 'New York',
        region: 'NY',
        postalCode: '10001',
        country: 'United States',
      },
    ],
  };

  await Contacts.createContact({ contact: newContact });
  console.log('Contact created successfully.');
};
```

The method accepts a contact object with fields for names, phone numbers, email addresses, and postal addresses.

### Retrieving Contacts

To retrieve contacts from the device, use the [`getContacts(...)`](../../sdks/capacitor/contacts.md#getcontacts) method with various filtering and pagination options:

```ts
const getContacts = async () => {
  const { contacts } = await Contacts.getContacts({
    fields: [
      'id',
      'givenName',
      'familyName',
      'emailAddresses',
      'phoneNumbers',
      'postalAddresses'
    ],
    limit: 10,
    offset: 0
  });
  return contacts;
};
```

This method allows you to specify which fields to retrieve, which reduces memory usage. You can also implement pagination by adjusting the `limit` and `offset` parameters to load contacts in manageable chunks. There is also a [`getContactById(...)`](../../sdks/capacitor/contacts.md#getcontactbyid) method to retrieve a single contact by its ID.

### Updating a Contact

Existing contacts can be updated using the [`updateContactById(...)`](../../sdks/capacitor/contacts.md#updatecontactbyid) method. This method requires the contact ID of the contact you want to update, along with the new contact data:

```ts
import { Contacts, PhoneNumberType } from '@capawesome-team/capacitor-contacts';

const updateContactById = async (contactId: string) => {
  await Contacts.updateContactById({
    id: contactId,
    contact: {
      givenName: 'Jane',
      familyName: 'Smith',
      organizationName: 'Capawesome Inc.',
      phoneNumbers: [
        {
          value: '+1-555-987-6543',
          type: PhoneNumberType.Work,
        },
      ],
    },
  });
  console.log('Contact updated successfully');
};
```

When updating a contact, make sure to provide all fields, even those that have not changed. This is necessary because the update operation replaces the entire contact record. We recommend retrieving the existing contact first to ensure you have all the necessary fields.

### Deleting a Contact

To remove a contact from the device, use the [`deleteContactById(...)`](../../sdks/capacitor/contacts.md#deletecontactbyid) method:

```ts
const deleteContactById = async (contactId: string) => {
  await Contacts.deleteContactById({ id: contactId });
  console.log('Contact deleted successfully');
};
```

Be cautious when implementing contact deletion, as this operation is irreversible. Consider adding confirmation dialogs to prevent accidental data loss.

### Picking a Contact

For user-driven contact selection, the [`pickContacts(...)`](../../sdks/capacitor/contacts.md#pickcontacts) method opens the native contact picker:

```ts
const pickContacts = async () => {
  const { contacts } = await Contacts.pickContacts({
    fields: [
      'id',
      'givenName',
      'familyName',
      'emailAddresses',
      'phoneNumbers',
      'postalAddresses'
    ],
    multiple: false
  });

  if (contacts.length > 0) {
    console.log('Contact selected:', contacts[0]);
  } else {
    console.log('No contact selected');
  }
};
```

The native contact picker provides a familiar interface for users to select contacts, with options to choose single or multiple contacts.

### Advanced

#### Accounts and Groups

On Android, contacts can be associated with different accounts (like Google, CalDAV, etc.). The Capawesome Contacts plugin allows you to retrieve a list of available accounts:

```ts
const getAccounts = async () => {
  const result = await Contacts.getAccounts();
  console.log('Available contact accounts:', result.accounts);
};
```

Unfortunately, Android does not offer a way to create new accounts programmatically due to security and privacy restrictions. However, you can use the retrieved accounts to offer users the option to select a specific account when creating or updating contacts.

On iOS, contacts can be organized into groups. The Capawesome Contacts plugin can manage these groups without user intervention:

```ts
import { Contacts } from '@capawesome-team/capacitor-contacts';

const getGroups = async () => {
  const result = await Contacts.getGroups();
  console.log('Available contact groups:', result.groups);
  
  result.groups.forEach(group => {
    console.log(`Group: ${group.name} (ID: ${group.id})`);
  });
};

const createContactGroup = async () => {
  const result = await Contacts.createGroup({
    group: {
      name: 'Friends'
    }
  });
  console.log('Group created with ID:', result.id);
};
```

Unlike Android, iOS allows you to create new groups programmatically.

#### Photos

The Capawesome Contacts plugin can also retrieve, set, and delete contact photos.

Here’s how to retrieve a contact's photo:

```ts
const getContactWithPhoto = async (contactId: string) => {
  const { contact } = await Contacts.getContactById({
    id: contactId,
    fields: ['id', 'givenName', 'familyName', 'photo'],
  });

  if (contact?.photo) {
    console.log('Contact photo as base64:', contact.photo);
  } else {
    console.log('No photo available for this contact.');
  }
};
```

Contact photos are always handled as base64-encoded strings. You can display them in your user interface or upload them to a server.

## Best Practices

When implementing contact management with the Capacitor Contacts API, consider these best practices:

1. **Implement proper permission handling**: Always check and request contact permissions before attempting any contact operations. Provide clear explanations to users about why your app needs contact access, and gracefully handle permission denials by offering alternative functionality or limited features.

2. **Use fields wisely**: When retrieving contacts, specify only the fields you need. This reduces memory usage and improves performance, especially when dealing with large contact lists. Avoid requesting unnecessary fields to keep your application efficient.

3. **Handle updates carefully**: When updating contacts, ensure you retrieve the existing contact first to avoid losing any data. The update operation replaces the entire contact record, so include all fields, even those that have not changed.

## FAQ

### Can I update just one field of a contact without touching the rest?

No — `updateContactById()` replaces the entire contact record, so any fields you omit are effectively cleared. Always retrieve the existing contact first with `getContactById()`, merge in your change, and pass the full object back, rather than sending a partial update.

### Can my app create a new contact account, like a custom sync account, on Android?

No. Android lets you retrieve the list of existing accounts (Google, CalDAV, etc.) via `getAccounts()` so users can choose which one a contact belongs to, but creating new accounts programmatically isn't possible due to Android's own security and privacy restrictions. That's a platform limitation, not something the plugin can work around.

### Can I organize contacts into groups on Android the same way as iOS?

No — contact groups are an iOS-only concept in this plugin. `getGroups()` and `createGroup()` work on iOS, letting you manage groups without user intervention, but Android's contact model doesn't expose an equivalent grouping feature through this API.

### What format are contact photos returned in?

Base64-encoded strings, consistently across platforms. This makes them straightforward to display directly in an `<img>` tag or upload to a server, without needing platform-specific handling of a native image format.

### Do I need to request both read and write permissions even if my app only reads contacts?

No — request only what you use. `checkPermissions()` and `requestPermissions()` return separate `readContacts` and `writeContacts` statuses, so an app that only displays contacts should request read access alone, rather than asking for write permission it doesn't need.

## Related Posts

- [Alternative to the Capacitor Community Contacts plugin](./alternative-to-capacitor-community-contacts-plugin.md)
- [Announcing the Contacts Plugin for Capacitor](./announcing-the-capacitor-contacts-plugin.md)
- [Announcing the Capacitor Calendar Plugin](./announcing-the-capacitor-calendar-plugin.md)

## Conclusion

Start with `isAvailable()` and `requestPermissions()`, then add only the calls your feature needs. If your app only displays contacts, request read access alone and keep the `fields` list short. If it writes contacts, read the existing record with `getContactById()` first, because `updateContactById()` replaces the whole record.

To stay updated with the latest updates, features, and news about the Capawesome, Capacitor, and Ionic ecosystem, subscribe to the [Capawesome newsletter](/newsletter/){:target="_blank"} and follow us on [X (formerly Twitter)](https://x.com/capawesomeio){:target="_blank"}.

If you have questions about the Capacitor Contacts plugin, ask in the [Capawesome Discord server](https://discord.gg/VCXxSVjefW){:target="_blank"}.
