Jump to Table of Contents Collapse Sidebar

Contact Picker API

Unofficial Proposal Draft,

This version:
https://beverloo.github.io/contact-api/spec
Issue Tracking:
GitHub
Editors:
(Google)
(Google)

Abstract

An API to give one-off access to a user’s contact information with full control over the shared data.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

1. Introduction

Contact pickers are frequently seen in native mobile applications for a variety of use cases, and in various desktop applications such as e-mail clients and calendars.

This specification defines an API to bring contact pickers to the web. The contact picker model was chosen to give full control to users over the shared data, allowing users to choose exactly which contacts to provide to the website. The contact picker model also gives websites one-off access to a user’s contacts, meaning developers have to request access to the user’s contacts every time they need it. This differs from some native contact APIs, but is necessary for ensuring users' contacts are not accessed without their knowledge and explicit consent.

1.1. Use cases

1.2. Example

Requesting contacts as a result of a user click.
selectRecipientsButton.addEventListener('click', async () => {
  const contacts = await navigator.contacts.select({
      properties: ['name', 'email'],
      multiple: true,
  });

  if (!contacts.length) {
    // Either no contacts were selected in the picker, or the picker could
    // not be launched. Exposure of the API implies expected availability.
    return;
  }

  // Use the names and e-mail addresses in |contacts| to populate the
  // recipients field in the website’s UI.
  populateRecipients(contacts);
});

In the above example selectRecipientsButton is a HTMLButtonElement, and populateRecipients is a developer-defined function.

2. Privacy Considerations

Exposing contact information has a clear privacy impact, in terms of exposing PII of uninvolved parties. A picker model is enforced so that the user agent can offer a user experience that makes it clear what information is going to be shared with the website and when.

The following constraints are also enforced:

3. API Description

3.1. Extensions to Navigator

[Exposed=(Window,SecureContext)]
partial interface Navigator {
    readonly attribute ContactsManager contacts;
};

3.2. ContactsManager

dictionary ContactInfo {
    sequence<USVString> name;
    sequence<USVString> email;
    sequence<USVString> tel;
};

enum ContactProperty { "email", "name", "tel" };

dictionary ContactsSelectOptions {
    required sequence<ContactProperty> properties;
    boolean multiple = false;
};

[Exposed=(Window,SecureContext)]
interface ContactsManager {
    Promise<sequence<ContactInfo>> select(ContactsSelectOptions options);
};

3.2.1. select()

The select(options) method, when invoked, runs these steps:
  1. Let promise be a new Promise.

  2. Let selectQueue be a new parallel queue.

  3. If the browsing context is not a top-level browsing context, then return a promise rejected with an InvalidStateError DOMException.

  4. If the algorithm is not triggered by user activation then return a promise rejected with a SecurityError DOMException.

  5. Enqueue the following steps to selectQueue:

    1. Launch a new contact picker with select options set to options. If this fails, then reject promise with an InvalidStateError DOMException and abort these steps.

    2. Wait for contact picker's contacts selected flag to be set.

    3. Resolve promise with contact picker's selected contacts.

  6. Return promise.

4. Contact Picker

A contact picker instance consists of:

Note: It is up to the user agent to choose the source of the contact information displayed in the picker.

To launch a contact picker, the user agent MUST present a user interface that follows these rules:
  • The UI MUST prominently display the browsing context's origin.

  • The UI MUST make it clear which properties of the contact will be shared.

  • The UI MUST provide a way to select individual contacts. If select options' multiple member is false, only one contact should be pickable.

  • The UI MUST provide an option to cancel/return without sharing any contacts, in which case set contacts selected flag.

  • The UI MUST provide an a way for users to indicate that they are done selecting, in which case complete contact picker.

4.1. Complete contact picker

To complete contact picker, run the following steps:
  1. For each selectedContact of the user’s chosen contacts:

    1. Let contactInfo be a new ContactInfo.

    2. If select options' property member contains `name`, then:

      1. Append all name data in selectedContact to contactInfo’s name member.

    3. If select options' property member contains `email`, then:

      1. Append all email data in selectedContact to contactInfo’s email member.

    4. If select options' property member contains `tel`, then:

      1. Append all telephone data in selectedContact to contactInfo’s tel member.

    5. Append contactInfo to selected contacts.

  2. If select options' multiple member is false, and selected contacts' size is greater than 1, then remove all items not equal to selected contacts[0].

  3. Set contacts selected flag.

TODO: Add more details about shared contact info.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PROMISES-GUIDE]
Domenic Denicola. Writing Promise-Using Specifications. 16 February 2016. TAG Finding. URL: https://www.w3.org/2001/tag/doc/promises-guide
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SECURE-CONTEXTS]
Mike West. Secure Contexts. 15 September 2016. CR. URL: https://www.w3.org/TR/secure-contexts/
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

IDL Index

[Exposed=(Window,SecureContext)]
partial interface Navigator {
    readonly attribute ContactsManager contacts;
};

dictionary ContactInfo {
    sequence<USVString> name;
    sequence<USVString> email;
    sequence<USVString> tel;
};

enum ContactProperty { "email", "name", "tel" };

dictionary ContactsSelectOptions {
    required sequence<ContactProperty> properties;
    boolean multiple = false;
};

[Exposed=(Window,SecureContext)]
interface ContactsManager {
    Promise<sequence<ContactInfo>> select(ContactsSelectOptions options);
};