Intermediate~20 min setupProductivity & CRMVerified April 2026
Google Sheets logo
HubSpot logo

How to Compare Google Sheets and HubSpot Contact Lists with N8n

Find contacts missing from either Google Sheets or HubSpot by comparing both lists and identifying gaps in your data.

Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.

Best for

Teams that need custom contact matching logic beyond simple email comparison

Not ideal for

Simple one-time imports or teams without JavaScript knowledge

Sync type

scheduled

Use case type

sync

Real-World Example

šŸ’”

A 25-person B2B software company runs this weekly to find contacts that sales reps added to Google Sheets but forgot to create in HubSpot, and vice versa. Before automation, their sales ops person spent 3 hours every Friday manually comparing spreadsheets and CRM records, missing about 20% of discrepancies.

What Will This Cost?

Drag the slider to your expected monthly volume.

/mo
505005K50K

Each platform counts differently — Zapier: 1 task per trigger. Make: 1 operation per module per record. n8n: 1 execution per run.

Prices shown for annual billing. Based on published pricing as of April 2026.

Estimated ROI

1000

min saved/mo

$583

labor value/mo

Free

no platform cost

Based on ~2 min manual effort per operation at $35/hr fully loaded labor cost.

Implementation

Skip the setup

Import this workflow directly into n8n

Copy the pre-built n8n blueprint and paste it straight into n8n. All modules, filters, and field mappings are already configured — you just need to connect your accounts.

Before You Start

Make sure you have everything ready.

Google Sheets with contact data including email addresses
HubSpot private app token with contacts read permission
N8n instance running (cloud or self-hosted)
Basic JavaScript knowledge for customizing comparison logic

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Email Addressemail
First Namefirstname
Last Namelastname
3 optional fieldsā–ø show
Phone Numberphone
Company Namecompany
Contact Sourcehs_analytics_source

Step-by-Step Setup

1

Workflow > Add Node > Google Sheets

Connect Google Sheets

Add your Google Sheets account to N8n and authorize access. You'll need the Sheet ID from your URL to target the right document.

  1. 1Click the + button to add a new node
  2. 2Search for 'Google Sheets' and select it
  3. 3Choose 'Read' operation from the dropdown
  4. 4Click 'Create New' next to Credential for Google Sheets API
āœ“ What you should see: Green connection badge appears next to Google Sheets credential.
2

Google Sheets Node > Parameters

Configure Sheet Data Source

Point N8n to your contacts spreadsheet and specify which columns contain the contact data. The Sheet ID comes from the URL between /d/ and /edit.

  1. 1Paste your Google Sheet ID into the Document field
  2. 2Enter your sheet name (usually 'Sheet1' or 'Contacts')
  3. 3Set Range to 'A:Z' to capture all contact columns
  4. 4Toggle 'Has Header Row' to true
āœ“ What you should see: Test execution shows your contact data with proper column headers as field names.
⚠
Common mistake — Don't leave Range empty — N8n will only grab column A and you'll miss contact details.
3

Workflow > Add Node > HubSpot > Contact

Add HubSpot Connection

Connect to HubSpot's API to fetch your CRM contact list. You'll need a private app token with contacts read permission.

  1. 1Add a new node and select 'HubSpot'
  2. 2Choose 'Contact' as the resource
  3. 3Select 'Get All' operation
  4. 4Create new HubSpot credential with your private app token
āœ“ What you should see: HubSpot node shows green connection status and test returns contact records.
⚠
Common mistake — Make sure your HubSpot token has 'crm.objects.contacts.read' scope or the API call fails.
4

HubSpot Node > Additional Options

Set HubSpot Contact Properties

Specify which contact fields to retrieve from HubSpot. Include at minimum email, first name, and last name for comparison.

  1. 1Click 'Add Option' in the HubSpot node
  2. 2Select 'Properties to Return'
  3. 3Enter 'email,firstname,lastname,phone,company' in the field
  4. 4Set limit to 500 to handle larger contact lists
āœ“ What you should see: Test execution returns HubSpot contacts with only the specified properties populated.
Google Sheets fields
Column A
Column B
Email
Status
Notes
available as variables:
1.props.Column A
1.props.Column B
1.props.Email
1.props.Status
1.props.Notes
5

Workflow > Add Node > Code

Add Code Node for Comparison Logic

Create a JavaScript function to compare both contact lists and identify missing contacts. This node will receive data from both previous nodes.

  1. 1Add a new 'Code' node after both data sources
  2. 2Select 'Run Once for All Items' mode
  3. 3Connect both Google Sheets and HubSpot nodes as inputs
  4. 4Name the node 'Contact Comparison'
āœ“ What you should see: Code node appears with two input connections and shows both data sources in the input panel.
⚠
Common mistake — Use 'Run Once for All Items' not 'Run Once for Each Item' or you'll compare one record at a time instead of full lists.

Drop this into an n8n Code node.

JavaScript — Code Node// Normalize emails for better matching
ā–ø Show code
// Normalize emails for better matching
const normalizeEmail = (email) => {
  return email.toLowerCase().trim().replace(/\+.*@/, '@');

... expand to see full code

// Normalize emails for better matching
const normalizeEmail = (email) => {
  return email.toLowerCase().trim().replace(/\+.*@/, '@');
};

// Find contacts in A but not in B
const findMissing = (listA, listB, keyField) => {
  const bEmails = new Set(listB.map(item => normalizeEmail(item[keyField])));
  return listA.filter(item => !bEmails.has(normalizeEmail(item[keyField])));
};
6

Code Node > JavaScript Code Editor

Write Comparison JavaScript

Add code that compares email addresses between both lists and identifies contacts missing from either system. The code accesses input data from both connected nodes.

  1. 1Clear the default code in the JavaScript editor
  2. 2Paste the comparison logic that iterates through both contact arrays
  3. 3Add logic to normalize email addresses to lowercase for comparison
  4. 4Return arrays of missing contacts from each system
āœ“ What you should see: Code executes successfully and returns two arrays: contacts missing from HubSpot and contacts missing from Google Sheets.
⚠
Common mistake — N8n's input data structure uses $input().all() to access all items from connected nodes — don't use items[0].json directly.

Drop this into an n8n Code node.

JavaScript — Code Node// Normalize emails for better matching
ā–ø Show code
// Normalize emails for better matching
const normalizeEmail = (email) => {
  return email.toLowerCase().trim().replace(/\+.*@/, '@');

... expand to see full code

// Normalize emails for better matching
const normalizeEmail = (email) => {
  return email.toLowerCase().trim().replace(/\+.*@/, '@');
};

// Find contacts in A but not in B
const findMissing = (listA, listB, keyField) => {
  const bEmails = new Set(listB.map(item => normalizeEmail(item[keyField])));
  return listA.filter(item => !bEmails.has(normalizeEmail(item[keyField])));
};
7

Workflow > Add Node > Split Out

Add Split Node for Results

Split the comparison results into separate paths so you can handle missing contacts from each system differently. This creates two workflow branches.

  1. 1Add a 'Split In Batches' node after the Code node
  2. 2Change the operation to 'Split Out' instead
  3. 3Set the field name to split on (like 'source_system')
  4. 4Connect the output to two different paths
āœ“ What you should see: Two output connectors appear, allowing separate handling of Google Sheets vs HubSpot missing contacts.
8

Google Sheets Node > Append Operation

Configure Google Sheets Output

Create a new sheet or update an existing one with the reconciliation results. This writes the missing contacts back to Google Sheets for review.

  1. 1Add another Google Sheets node on one output path
  2. 2Select 'Append' operation
  3. 3Choose your results spreadsheet (can be same or different sheet)
  4. 4Map the contact fields to appropriate columns
āœ“ What you should see: Missing contacts appear in your designated Google Sheet with proper column mapping.
⚠
Common mistake — If appending to the same sheet, use a different tab name or you'll mix source data with results.
9

Start Node > Trigger Configuration

Set Manual Trigger

Configure when this reconciliation runs. Manual trigger lets you run it on-demand, or you can schedule it to run automatically.

  1. 1Click the 'Manual Trigger' node at the start
  2. 2Change to 'Schedule Trigger' if you want automation
  3. 3Set frequency to weekly or monthly for contact reconciliation
  4. 4Configure the specific day and time to run
āœ“ What you should see: Workflow shows the trigger type and schedule in the node header.
⚠
Common mistake — Don't run contact reconciliation daily — contact lists don't change that fast and you'll hit API limits.
n8n
+
click +
search apps
Google Sheets
GO
Google Sheets
Set Manual Trigger
Google Sheets
GO
module added
10

Workflow > Execute Workflow

Test Full Workflow

Execute the complete workflow to verify it properly compares contact lists and identifies missing records. Check both output paths for accuracy.

  1. 1Click 'Execute Workflow' button in the top toolbar
  2. 2Monitor each node's execution status and output
  3. 3Verify the comparison logic found actual missing contacts
  4. 4Check that results were written to Google Sheets correctly
āœ“ What you should see: All nodes show green checkmarks and your results sheet contains the missing contacts from both systems.
⚠
Common mistake — If any node shows red errors, click it to see the error details — don't just re-run the workflow blindly.
n8n
ā–¶ Run once
executed
āœ“
Google Sheets
āœ“
HubSpot
HubSpot
šŸ”” notification
received

Scaling Beyond 1000+ contacts per system+ Records

If your volume exceeds 1000+ contacts per system records, apply these adjustments.

1

Batch API Calls

Use Split In Batches to process contacts in groups of 100-200. This prevents timeout errors and helps manage API rate limits from both Google and HubSpot.

2

Optimize Comparison Algorithm

Pre-sort contact arrays by email address before comparison. This reduces the comparison from O(n²) to O(n) complexity and significantly speeds up processing time.

Going live

Production Checklist

Before you turn this on for real, confirm each item.

Troubleshooting

Common errors and how to fix them.

Frequently Asked Questions

Common questions about this workflow.

Analysis

VerdictWhy n8n for this workflow

Use N8n for this if you need custom comparison logic beyond simple email matching. The JavaScript code node lets you build sophisticated matching rules — fuzzy name matching, phone number normalization, or company domain correlation. You get full control over the reconciliation algorithm without the limitations of visual workflow builders. Pick Zapier instead if you just need basic email matching and don't want to write any code.

Cost

This workflow consumes about 4-6 executions per run depending on your contact volume. With 500 contacts in each system, expect 8-10 total executions including API calls and data processing. Running weekly, that's roughly 40 executions monthly, which fits N8n's Starter plan at $20/month. Make would cost $9/month for the same volume, and Zapier Premium runs $20/month but limits you to 2,000 tasks total.

Tradeoffs

Make handles the visual data mapping better — their Google Sheets and HubSpot modules show field previews and have better error messages when mappings break. Zapier's HubSpot integration includes more pre-built filters for contact properties and handles pagination automatically. But N8n wins on the comparison logic — neither competitor lets you write custom JavaScript for sophisticated matching rules, and you'll hit their limitations fast with complex reconciliation needs.

You'll discover that HubSpot's API paginates at 100 contacts per call, so large lists require multiple requests and proper handling of the pagination tokens. Google Sheets has a 1000-cell limit per read operation — if your contact data spans more cells, you need to batch the reads. Both APIs occasionally return stale data, so add timestamp checks if you're reconciling frequently updated lists.

Ideas for what to build next

  • →
    Add Data Sync for Mismatched Contacts — Extend the workflow to not just find missing contacts, but also sync data differences between systems when the same contact exists in both.
  • →
    Set Up Slack Notifications — Add a Slack node that posts a summary of reconciliation results to your sales channel, showing how many missing contacts were found in each system.

Related guides

Was this guide helpful?
← Google Sheets + HubSpot overviewn8n profile →