

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
scheduledUse case type
syncReal-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.
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
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.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Email Address | email | |
| First Name | firstname | |
| Last Name | lastname | |
3 optional fieldsāø show
| Phone Number | phone |
| Company Name | company |
| Contact Source | hs_analytics_source |
Step-by-Step Setup
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.
- 1Click the + button to add a new node
- 2Search for 'Google Sheets' and select it
- 3Choose 'Read' operation from the dropdown
- 4Click 'Create New' next to Credential for Google Sheets API
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.
- 1Paste your Google Sheet ID into the Document field
- 2Enter your sheet name (usually 'Sheet1' or 'Contacts')
- 3Set Range to 'A:Z' to capture all contact columns
- 4Toggle 'Has Header Row' to true
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.
- 1Add a new node and select 'HubSpot'
- 2Choose 'Contact' as the resource
- 3Select 'Get All' operation
- 4Create new HubSpot credential with your private app token
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.
- 1Click 'Add Option' in the HubSpot node
- 2Select 'Properties to Return'
- 3Enter 'email,firstname,lastname,phone,company' in the field
- 4Set limit to 500 to handle larger contact lists
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.
- 1Add a new 'Code' node after both data sources
- 2Select 'Run Once for All Items' mode
- 3Connect both Google Sheets and HubSpot nodes as inputs
- 4Name the node 'Contact Comparison'
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])));
};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.
- 1Clear the default code in the JavaScript editor
- 2Paste the comparison logic that iterates through both contact arrays
- 3Add logic to normalize email addresses to lowercase for comparison
- 4Return arrays of missing contacts from each system
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])));
};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.
- 1Add a 'Split In Batches' node after the Code node
- 2Change the operation to 'Split Out' instead
- 3Set the field name to split on (like 'source_system')
- 4Connect the output to two different paths
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.
- 1Add another Google Sheets node on one output path
- 2Select 'Append' operation
- 3Choose your results spreadsheet (can be same or different sheet)
- 4Map the contact fields to appropriate columns
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.
- 1Click the 'Manual Trigger' node at the start
- 2Change to 'Schedule Trigger' if you want automation
- 3Set frequency to weekly or monthly for contact reconciliation
- 4Configure the specific day and time to run
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.
- 1Click 'Execute Workflow' button in the top toolbar
- 2Monitor each node's execution status and output
- 3Verify the comparison logic found actual missing contacts
- 4Check that results were written to Google Sheets correctly
Scaling Beyond 1000+ contacts per system+ Records
If your volume exceeds 1000+ contacts per system records, apply these adjustments.
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.
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
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.
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.
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
How to Share Notion Meeting Notes to Slack with Pipedream
~15 min setup
How to Share Notion Meeting Notes to Slack with Power Automate
~15 min setup
How to Share Notion Meeting Notes to Slack with n8n
~20 min setup
How to Send Notion Meeting Notes to Slack with Zapier
~8 min setup
How to Share Notion Meeting Notes to Slack with Make
~12 min setup
How to Create Notion Tasks from Slack with Pipedream
~15 min setup