Skip to content
Skip to main content

How to list Google contacts

Last updated:

Google retired its standalone Contacts API in January 2022 and folded everything into the People API, so any code written against the old google.com/m8/feeds endpoints stopped working. The People API that replaced it splits a user’s address book across “connections” (saved contacts) and “other contacts” (auto-created from Gmail), each behind a different OAuth scope and verification tier. That split, plus Google’s app verification review, is where most teams get stuck.

This recipe shows how to pull Gmail and Google Workspace contacts through one call to the Nylas Contacts API, then filter and sync them. You get a single contact schema and one set of credentials instead of two People API resources and a GCP verification process.

Why use Nylas instead of the Google People API directly?

Section titled “Why use Nylas instead of the Google People API directly?”

The People API asks for more setup than a contact picker usually warrants:

  • Two resources, two scopes. Saved contacts come from people.connections.list with the contacts scope; auto-created suggestions come from otherContacts.list with the separate contacts.other.readonly scope. The API merges them for you and exposes both through the source field.
  • App verification. Both contact scopes are classified as sensitive, so a production Google app needs OAuth verification before users outside your test list can connect. The API handles token storage and refresh once a grant exists.
  • Per-project quotas. The People API enforces a default 90 read requests per minute per user. Polling many users from your own GCP project can exhaust that fast, and the API smooths it with managed retries.
  • One schema across providers. The same GET /v3/grants/{grant_id}/contacts request reads a Gmail address book, an Outlook one, or Exchange, so your picker code doesn’t branch on provider.

You’ll need a working project and an authorized account before any contacts come back. A grant represents one connected Google account, and the contacts you list always belong to that single grant. Set these up first:

Send a GET request to /v3/grants/{grant_id}/contacts with the grant ID for the connected Google account. The response is a data array of contact objects plus a request_id, and by default a single page returns up to 50 contacts. Every object carries the same fields (emails, phone_numbers, job_title, company_name, and groups) whether the account is Gmail or Google Workspace.

The samples below list contacts for one grant and print the unified response.

For create, update, and delete operations plus the complete field list, see Manage contacts with the Contacts API.

Four query parameters narrow a Google contact list: email, phone_number, group, and source. The source parameter is the most useful one for Google, since it picks between saved contacts (address_book) and the auto-created suggestions Gmail builds from your sent mail (inbox). A fifth parameter, recurse, exists but is Microsoft-only, so it has no effect on Google grants. Combine these with limit to keep pages small.

The email filter matches any contact whose email address contains the value you pass, which makes it the right choice for an autocomplete box.

To list only the contacts inside one Google label, pass that label’s ID to the group parameter. Google contact groups map directly to the labels you create in Google Contacts, so group reads the same membership Gmail shows in its sidebar.

Google’s contact model has a few quirks that shape how a list call behaves. The four below cover where contacts come from, how groups and photos work, which scope you need, and the quotas that throttle reads.

The source field maps to People API resources

Section titled “The source field maps to People API resources”

Google exposes contacts through two People API resources, and the source field tells you which one a contact came from. address_book contacts are the saved entries from people.connections.list, the ones a user typed into Google Contacts. inbox contacts are the “other contacts” Gmail auto-creates from people you’ve emailed, returned by otherContacts.list. A heavy email user can have thousands of these auto-created entries against a few hundred saved ones, so filter on source=address_book when you only want real, saved contacts.

The group query parameter filters by Google’s contact labels, which the People API calls contact groups. Each label has a stable resource ID, and the groups array on every contact object lists the labels that contact belongs to. System groups like myContacts and starred are always present, while user-created labels get their own IDs. Use the List contact groups endpoint to fetch the IDs before filtering, because passing a display name instead of an ID returns an empty list.

The list response doesn’t embed photo bytes; instead each contact carries a picture_url you fetch separately when you need the image. Google stores high-resolution profile photos, often 512 by 512 pixels, so loading them inline for a long list is wasteful. Request the photo lazily as a contact scrolls into view, and cache it, rather than pulling every image up front.

Reading saved contacts needs the contacts or contacts.readonly scope, and the inbox source additionally needs contacts.other.readonly. Both are sensitive scopes, so a production app must pass Google’s OAuth verification. On quotas, the People API defaults to 90 read requests per minute per user, and your GCP project carries an overall daily ceiling on top of that. The API retries throttled requests, but if you sync many accounts on a schedule, stagger the jobs rather than firing them at once. See Google’s People API documentation for the current quota figures and scope definitions.