# Contact Picker API: letting users share selected contacts, not the whole address book

> How the Contact Picker API's navigator.contacts.select() lets a user pick specific contacts and choose which fields to share with a site, why it requires a secure context and a user gesture, and why MDN marks it experimental and not Baseline.

**In one line:** The Contact Picker API lets a web app ask the user to pick one or more
contacts from their address book through a browser-native picker UI, sharing only the
specific contacts and fields the user chooses — never the full contact list.

## Why a picker instead of bulk access

The Contact Picker API allows users to select entries from their contact list and share
limited details of the selected entries with a website or application. `navigator.contacts`
exposes a `ContactsManager`, and `ContactsManager.select()` opens the picker the browser
controls; the user decides which contacts to select and which of the requested properties
(`name`, `email`, `tel`, `address`, `icon`) to release. MDN lists common use cases as
selecting a contact to message via email or chat, choosing a contact's phone number for
VOIP, or discovering which contacts already use a given social platform.

## Using it

```js
const props = ['name', 'email', 'tel'];
const opts = { multiple: true };

async function getContacts() {
  try {
    const contacts = await navigator.contacts.select(props, opts);
    handleResults(contacts);
  } catch (ex) {
    // select() can throw — see "What goes wrong" below.
  }
}
```

`props` lists which fields to request; `getProperties()` reports which of those fields the
current browser actually supports, so a site can adjust its request before calling
`select()`:

```js
async function checkProperties() {
  const supported = await navigator.contacts.getProperties();
  if (supported.includes('email')) {
    // Safe to request "email" in props.
  }
}
```

## Requirements

- **Secure context.** MDN documents `select()` as available only in secure contexts
  (HTTPS).
- **User gesture.** MDN states that `select()` requires a user gesture for the returned
  `Promise` to resolve.
- **Not available in Web Workers.** MDN notes the Contact Picker API is not exposed via
  `WorkerNavigator`.

## Where it is supported

MDN marks the Contact Picker API as an experimental technology that is not part of
Baseline because it does not work in some of the most widely used browsers. Check the
Browser compatibility table on the MDN `Contact_Picker_API` and `ContactsManager` pages
before depending on it in production.

## Feature detection

```js
async function shareContacts(props, opts) {
  if (!('contacts' in navigator && 'ContactsManager' in window)) {
    // Not supported here — fall back to a manual entry form instead.
    return null;
  }
  return navigator.contacts.select(props, opts);
}
```

## What goes wrong

MDN's `select()` reference documents error conditions the call can throw or reject with:

- **`TypeError`** — the requested `properties` list is empty, or includes a property the
  browser does not support.
- **`InvalidStateError`** — the call is made from a browsing context that isn't top-level,
  a contact picker is already open, or the picker otherwise fails to launch.
- **`SecurityError`** — `select()` was not triggered by user activation.

MDN's own example handles them with `try`/`catch`; the promise-returning `select()` can
also be handled with `.catch()`.

## Practical checklist

- [ ] Feature-detect with `'contacts' in navigator && 'ContactsManager' in window` before
      calling `select()`.
- [ ] Call `select()` only from a real user gesture — MDN documents that it requires one to
      resolve.
- [ ] Call `getProperties()` to confirm which fields the browser actually returns before
      relying on them.
- [ ] Handle `TypeError`, `InvalidStateError`, and `SecurityError` — with `try`/`catch` or
      a `.catch()` on the returned promise.
- [ ] Have a manual-entry fallback UI ready — MDN marks this API as not Baseline.
- [ ] Never assume persistent access — a fresh user action is required for every request.

## Where to go next

- [Web Push](/reference/notifications/web-push/)
- [Notification triggers](/reference/notifications/notification-triggers/)