JavaScript Navigator contacts Property

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Experimental

What You’ll Learn

navigator.contacts returns a ContactsManager — the Contact Picker API entry point. Learn feature detection, getProperties(), select(), secure context rules, five examples, and try-it labs.

01

Kind

Read-only property

02

Returns

ContactsManager

03

Status

Experimental

04

Context

Secure (HTTPS)

05

Picker

select()

06

Fields

getProperties()

Introduction

Forms that ask for a friend’s name, email, or phone number are tedious to fill by hand. The Contact Picker API lets the user choose contacts from their device list and share only the fields you request.

Your entry point is navigator.contacts. It is read-only and returns a ContactsManager object. MDN notes that two successive accesses return the same object instance.

💡
User-controlled sharing

The site never scrapes the whole address book. The user opens a picker, chooses contacts (and which details to share), then your Promise resolves with that limited data.

Understanding the contacts Property

Think of navigator.contacts as a handle to the Contact Picker for this page. You do not assign to it — you call methods on the ContactsManager it returns.

  • getProperties() — Promise of supported field names (name, email, tel, address, icon).
  • select(properties, options) — opens the picker; resolves to an array of selected contacts.
  • options.multiple — set true to allow selecting more than one contact.
  • Call select() from a user gesture (button click) on a secure page.

📝 Syntax

General form of the property:

JavaScript
navigator.contacts

Value

  • A ContactsManager object used to open the contact picker and query supported properties.

Common patterns

JavaScript
// MDN-style feature detect:
const supported = "contacts" in navigator && "ContactsManager" in window;

// Supported fields:
const props = await navigator.contacts.getProperties();

// Open picker from a click handler:
const contacts = await navigator.contacts.select(
  ["name", "email", "tel"],
  { multiple: true }
);

⚡ Quick Reference

GoalCode
Get ContactsManagernavigator.contacts
Detect API"contacts" in navigator && "ContactsManager" in window
List fieldsawait navigator.contacts.getProperties()
Open pickerawait navigator.contacts.select(props, opts)
Multi-select{ multiple: true }
Secure page?window.isSecureContext

🔍 At a Glance

Four facts to remember about navigator.contacts.

Returns
ContactsManager

Same object twice

Status
experimental

Not Baseline

HTTPS
required

Secure context

Main call
select()

User gesture

📋 Contact Picker vs Manual Form

navigator.contactsManual form fields
UXNative picker, one tap shareType name / email / phone
PrivacyUser chooses what to shareUser types whatever they want
SupportExperimental / limitedWorks everywhere
Best forEnhancement on supporting devicesAlways-available fallback
Use together?Yes — offer “Pick from contacts” when supported; keep the form

Examples Gallery

Examples follow MDN Contact Picker / navigator.contacts patterns. Prefer Try It Yourself on a supporting mobile browser. Use View Output for expected messaging.

📚 Getting Started

Detect the API and confirm a secure context.

Example 1 — Feature Detection

MDN-style check for Contact Picker support.

JavaScript
const supported = "contacts" in navigator && "ContactsManager" in window;
console.log(supported ? "contacts available" : "contacts missing");
Try It Yourself

How It Works

Desktop Chrome often reports missing. Chrome on Android is a common place where this becomes available.

Example 2 — Secure Context Check

Pair detection with isSecureContext.

JavaScript
const lines = [
  "isSecureContext: " + window.isSecureContext,
  "contacts: " + (("contacts" in navigator) ? "present" : "absent")
];
console.log(lines.join("\n"));
Try It Yourself

How It Works

Serve Contact Picker features over HTTPS (or localhost during development).

📈 Practical Patterns

List fields, pick one contact, or pick several.

Example 3 — getProperties()

Ask which contact fields the system can return.

JavaScript
async function listContactProps() {
  if (!("contacts" in navigator)) {
    return "contacts unavailable";
  }
  const props = await navigator.contacts.getProperties();
  return props.join(", ") || "(empty list)";
}

listContactProps().then((msg) => console.log(msg));
Try It Yourself

How It Works

Pass only supported properties to select() to avoid a TypeError.

Example 4 — select() One Contact

Open the picker from a button and request name / email / tel.

JavaScript
async function pickOneContact() {
  if (!("contacts" in navigator)) {
    return "contacts unavailable";
  }
  try {
    const results = await navigator.contacts.select(
      ["name", "email", "tel"],
      { multiple: false }
    );
    return JSON.stringify(results, null, 2);
  } catch (err) {
    return "select failed: " + err.name;
  }
}

// Call from a button click in Try It
Try It Yourself

How It Works

Each contact property is typically an array of values. Empty arrays mean “no data” or the user opted out of that field.

Example 5 — Multiple Contacts + Helper

MDN-style multi-select with property discovery and error handling.

JavaScript
async function pickContacts() {
  if (!window.isSecureContext) {
    return { ok: false, reason: "insecure-context" };
  }
  if (!("contacts" in navigator)) {
    return { ok: false, reason: "unsupported" };
  }
  try {
    const available = await navigator.contacts.getProperties();
    const want = ["name", "email", "tel"].filter((p) => available.includes(p));
    if (!want.length) {
      return { ok: false, reason: "no-properties" };
    }
    const contacts = await navigator.contacts.select(want, { multiple: true });
    return { ok: true, count: contacts.length, contacts };
  } catch (err) {
    return { ok: false, reason: err.name };
  }
}

// Call from a button click in Try It
Try It Yourself

How It Works

Filter requested fields through getProperties(), then open the picker with multiple: true.

🚀 Common Use Cases

  • Invite friends — pick emails or phone numbers for share / invite flows.
  • Checkout / shipping — fill a recipient name and address from contacts (where supported).
  • Messaging apps — start a chat by selecting a phone number.
  • Event RSVPs — add guests without retyping contact details.
  • Progressive enhancement — show “Pick contact” only when the API exists.

🧠 How navigator.contacts Works

1

Secure page + detect

HTTPS / localhost and "contacts" in navigator.

Detect
2

Query getProperties()

Learn which fields the device can share.

Fields
3

User clicks → select()

Native picker opens; user chooses contacts.

Gesture
4

Promise resolves

You receive only the shared fields — or an error / cancel.

📝 Notes

  • Experimental and not Baseline — support is limited.
  • Secure context required (HTTPS / localhost).
  • Not Deprecated or Non-standard on MDN — it is a specified Contact Picker API feature with limited adoption.
  • select() needs a user gesture; access is on-demand (not a permanent permission dump of the address book).
  • Related: cookieEnabled, Window, JavaScript hub.

Limited Browser Support

navigator.contacts (Contact Picker API) is Experimental and not Baseline. Historical support is strongest on Chrome for Android. Desktop browsers and Safari/Firefox often omit it. Always feature-detect.

Experimental · Not Baseline

Navigator.contacts

Offer Contact Picker as progressive enhancement. Keep a manual name/email/tel form for everyone else.

Limited Not Baseline
Google Chrome Contact Picker mainly on Android builds (check MDN)
Limited
Microsoft Edge Follow Chromium Contact Picker status on supported platforms
Limited
Opera Chromium-based — check current mobile compat
Limited
Mozilla Firefox Not available for typical web content
Unavailable
Apple Safari Not available for typical web content
Unavailable
contacts Limited

Bottom line: Detect navigator.contacts, require HTTPS, call select() from a click, and always ship a form fallback.

Conclusion

navigator.contacts is the Contact Picker API entry point. Feature-detect it, require HTTPS, use getProperties() and select() from a button click, and keep a normal form when the API is missing.

Continue with cookieEnabled, Window methods, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Feature-detect with MDN’s contacts + ContactsManager check
  • Serve over HTTPS
  • Call select() from a user gesture
  • Filter fields with getProperties()
  • Keep a manual contact form as fallback

❌ Don’t

  • Require Contact Picker for core checkout / invite flows
  • Assume desktop browsers support it
  • Request unsupported property names blindly
  • Auto-open the picker on page load
  • Store shared contacts longer than the user expects

Key Takeaways

Knowledge Unlocked

Five things to remember about contacts

Contact Picker entry — user-shared fields only.

5
Core concepts
🔍 02

Fields

getProperties

Query
📞 03

Picker

select()

Gesture
🔒 04

HTTPS

secure context

Security
🔬 05

Status

Experimental

Detect

❓ Frequently Asked Questions

It is a read-only Navigator property that returns a ContactsManager object — the entry point to the Contact Picker API so users can select contacts and share limited details with your site.
Yes. MDN marks it Experimental and not Baseline. Support is limited (historically strongest on Chrome for Android). Always feature-detect and provide a manual form fallback.
Yes. It is available only in secure contexts (HTTPS or localhost) in supporting browsers.
Call await navigator.contacts.select(properties, options) from a user gesture such as a button click. Pass property names like "name", "email", and "tel". Use { multiple: true } to allow several contacts.
await navigator.contacts.getProperties() resolves to an array of property names the system can return. Use it so you only ask select() for supported fields.
No. The property is read-only. Two successive reads return the same ContactsManager object. You call methods on that object.
Did you know?

MDN notes that reading navigator.contacts twice returns the same ContactsManager object — you are not creating a new manager on every access.

Learn cookieEnabled Next

Check whether the browser allows cookies.

cookieEnabled →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful