Google contacts label filtering

Describe the problem/error/question

I can’t seem to get the google contacts node to give me the correct labels for contacts. In google contacts, they are called “memberships” and I get a unique one for every contact, often duplicated for the same contact, but completely unique between contacts.

What is the error message (if any)?

I should be seeing the same memberships over and over in an array, but I’m not. There’s no error messages.

Please share your workflow

Share the output returned by the last node

Here’s some example json output. I have changed the name and phone, but everything else is the same. You’ll see below that the membership numbers are different between contacts, they never repeat, but should based on if that contact is in that label or membership. And those with multiple memberships are listed as the same one multiple times when returned in the json.

Is this a bug?

[
  {
    "resourceName": "people/c2760342921159988432",
    "etag": "%EgcBAgsuNz0/GgQBAgUHIgxUc0hMMVVrbTRrQT0=",
    "names": {
      "displayName": "Jane Doe",
      "familyName": "Doe",
      "givenName": "Jane",
      "displayNameLastFirst": "Doe, Jane",
      "unstructuredName": "Jane Doe"
    },
    "memberships": [
      "264eb5430a0154d0"
    ],
    "contactId": "c2760342921159988432"
  },
  {
    "resourceName": "people/c5336719263179391161",
    "etag": "%EgcBAgsuNz0/GgQBAgUHIgxxbktCMXhkMnVOZz0=",
    "names": {
      "displayName": "John Jones",
      "familyName": "Jones",
      "givenName": "John",
      "displayNameLastFirst": "Jones, John",
      "unstructuredName": "John Jones"
    },
    "phoneNumbers": {
      "work": [
        "555-555-5555"
      ]
    },
    "memberships": [
      "4a0fd5e50bcac0b9",
      "4a0fd5e50bcac0b9",
      "4a0fd5e50bcac0b9"
    ],
    "contactId": "c5336719263179391161"
  }
]

Here’s a quick python script that will check if there’s an issue. Just have a contacts.json file in the same directory and run it.


import json
from collections import defaultdict
from typing import Dict, List, Set

def find_shared_memberships(file_path: str) -> Dict[str, List[str]]:
    # Dictionary to store membership -> contacts mapping
    membership_contacts: Dict[str, Set[str]] = defaultdict(set)
    # Dictionary to store results of shared memberships
    shared_memberships: Dict[str, List[str]] = {}
    
    with open(file_path, 'r') as f:
        data = json.load(f)
        
    # Process each contact
    for contact in data:
        names = contact.get('names')
        if not names or 'displayName' not in names:
            continue  # skip this contact if no displayName
        name = names['displayName']
        memberships = contact.get('memberships', [])
        
        # Add contact to each of their memberships
        for membership in memberships:
            membership_contacts[membership].add(name)
    
    # Find memberships with multiple contacts
    for membership, contacts in membership_contacts.items():
        if len(contacts) > 1:
            shared_memberships[membership] = sorted(list(contacts))
    
    # Print how many duplicate checks are being performed
    from itertools import combinations
    memberships = list(membership_contacts.keys())
    num_checks = 0
    for m1, m2 in combinations(memberships, 2):
        num_checks += 1
        # Uncomment below if you want to see each pair being checked
        # print(f"Checking {m1} vs {m2}")
    print(f"Number of duplicate membership checks: {num_checks}")

    return shared_memberships

if __name__ == "__main__":
    file_path = "contacts.json"  # Update this to your JSON file path
    shared = find_shared_memberships(file_path)
    
    if not shared:
        print("No shared memberships found.")
    else:
        print("Found shared memberships:")
        for membership, contacts in shared.items():
            print(f"\nMembership ID: {membership}")
            print("Shared between:")
            for contact in contacts:
                print(f"  - {contact}") 

Information on your n8n setup

  • n8n version: 1.81.4
  • Database (default: SQLite): Postgresql
  • n8n EXECUTIONS_PROCESS setting (default: own, main): own
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: Docker

What does the node output look like?

The google contacts node output looks like what I have in the original post

[
  {
    "resourceName": "people/c2760342921159988432",
    "etag": "%EgcBAgsuNz0/GgQBAgUHIgxUc0hMMVVrbTRrQT0=",
    "names": {
      "displayName": "Jane Doe",
      "familyName": "Doe",
      "givenName": "Jane",
      "displayNameLastFirst": "Doe, Jane",
      "unstructuredName": "Jane Doe"
    },
    "memberships": [
      "264eb5430a0154d0"
    ],
    "contactId": "c2760342921159988432"
  },
  {
    "resourceName": "people/c5336719263179391161",
    "etag": "%EgcBAgsuNz0/GgQBAgUHIgxxbktCMXhkMnVOZz0=",
    "names": {
      "displayName": "John Jones",
      "familyName": "Jones",
      "givenName": "John",
      "displayNameLastFirst": "Jones, John",
      "unstructuredName": "John Jones"
    },
    "phoneNumbers": {
      "work": [
        "555-555-5555"
      ]
    },
    "memberships": [
      "4a0fd5e50bcac0b9",
      "4a0fd5e50bcac0b9",
      "4a0fd5e50bcac0b9"
    ],
    "contactId": "c5336719263179391161"
  }
]

Some contacts have a single membership like “264eb5430a0154d0”

Other contacts have multiple memberships that are all the same like

"memberships": [
      "4a0fd5e50bcac0b9",
      "4a0fd5e50bcac0b9",
      "4a0fd5e50bcac0b9"
    ],

The multiple memberships that are the same feels like a bug as there should be different ones there, not just the first one repeated several times as that contact has multiple labels/memberships.

And how does it look when running the request locally via curl or python instead of n8n? If its the same its either a bug by google api or potentially intentional, I have not personally used the api before.

I was able to use google’s APIs directly with curl and got different results.

There were a bunch of contacts with the same membership. This is how the json comes back.

{
      "resourceName": "people/c3621375355930107857",
      "etag": "%EgoBAgkLDC43PT4/GgQBAgUHIgxIVFM3UlNaTmxFZz0=",
      "names": [
        {
          "metadata": {
            "primary": true,
            "source": {
              "type": "CONTACT",
              "id": "3241b5b308915fd1"
            },
            "sourcePrimary": true
          },
          "displayName": "Alex Smith",
          "familyName": "Smith",
          "givenName": "Alex",
          "displayNameLastFirst": "Smith, Alex",
          "unstructuredName": "Alex Smith"
        }
      ],
      "organizations": [
        {
          "metadata": {
            "primary": true,
            "source": {
              "type": "CONTACT",
              "id": "3241b5b308915fd1"
            },
            "sourcePrimary": true
          },
          "name": "Coldwell",
          "title": "Account Manager and Realtor"
        }
      ],
      "memberships": [
        {
          "metadata": {
            "source": {
              "type": "CONTACT",
              "id": "3241b5b308915fd1"
            }
          },
          "contactGroupMembership": {
            "contactGroupId": "56c8d407898751fb",
            "contactGroupResourceName": "contactGroups/56c8d407898751fb"
          }
        },
        {
          "metadata": {
            "source": {
              "type": "CONTACT",
              "id": "3241b5b308915fd1"
            }
          },
          "contactGroupMembership": {
            "contactGroupId": "734c9cb60bc15453",
            "contactGroupResourceName": "contactGroups/734c9cb60bc15453"
          }
        },
        {
          "metadata": {
            "source": {
              "type": "CONTACT",
              "id": "3241b5b308915fd1"
            }
          },
          "contactGroupMembership": {
            "contactGroupId": "myContacts",
            "contactGroupResourceName": "contactGroups/myContacts"
          }
        }

I think what’s happening in n8n is that there’s memberships, then under that, one or more “metadata” and it’s reading that id like 3241b5b308915fd1 instead which is for the contact which is why all of them would be unique per contact, which is why there are multiple copies like you saw in the original post, but they are unique between contacts.

It doesn’t read "contactGroupId": "734c9cb60bc15453" which is the information I’m looking for. Instead, it just prints out the contact ID multiple times if that contact is in multiple memberships (labels).

So this seems like a bug in n8n’s implementation. I need the contactGroupIDs, not the contact’s ID repeated multiple times which is hiding them in the results that come back.

1 Like

Can confirm I’m having the same issue in a workflow where I’m trying to send labeled contacts somewhere.

Seems to have been a skill issue on my part.

The solution is to let the Google Contacts Node have the raw format flag enabled

Once that’s done, in the filter node, make sure you have the following in the filter

{{ $json.memberships.map(m => m.contactGroupMembership.contactGroupId) }}

That will give you an array of all of the label (membership) ids that you need. Just compare it to an array, containing the text string you want.

2 Likes

Oh man, I’m extremely grateful for you following up with this answer.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.