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

How to Sync Bulk Property Updates from Google Sheets to HubSpot with N8n

Watch for changes in specific Google Sheets columns and automatically update the corresponding contact or company properties in HubSpot.

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

Best for

Teams updating 500+ HubSpot contacts monthly with custom data validation or transformation needs

Not ideal for

Simple column-to-property syncs under 100 records monthly where Zapier's reliability outweighs cost savings

Sync type

polling

Use case type

sync

Real-World Example

💡

A 25-person B2B marketing agency uses this to bulk update lead scores in HubSpot after their data analyst calculates new values in Google Sheets weekly. Before automation, the ops manager manually imported CSV files and overwrote contact properties, taking 2+ hours and occasionally duplicating contacts. Now the sync runs automatically and processes 800+ contact updates in 15 minutes.

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.

HubSpot admin access to create private app tokens
Google Sheets with contact emails and properties to update
HubSpot contacts that exist and match your sheet emails
N8n cloud account or self-hosted N8n instance

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Email Addressemail
5 optional fields▸ show
Phone Numberphone
Lead Scorehs_lead_score
Company Namecompany
Job Titlejobtitle
Lifecycle Stagelifecyclestage

Step-by-Step Setup

1

Workflows > New > Triggers > Google Sheets

Create New N8n Workflow

Start a fresh workflow and set up the initial trigger. This will monitor your Google Sheets for changes.

  1. 1Click '+ New Workflow' from the N8n dashboard
  2. 2Delete the default Manual Trigger node
  3. 3Click the '+' button and search for 'Google Sheets'
  4. 4Select 'Google Sheets Trigger' from the results
What you should see: You should see a Google Sheets trigger node on your canvas with connection options.
2

Node Settings > Credentials > Google Sheets API

Configure Google Sheets Connection

Connect N8n to your Google account and select the spreadsheet containing your property updates. You'll need OAuth permissions for read access.

  1. 1Click 'Create New Credential' under Google Sheets API
  2. 2Choose 'OAuth2' and click 'Connect my account'
  3. 3Authorize N8n in the Google popup window
  4. 4Select your spreadsheet from the 'Document' dropdown
  5. 5Choose the specific sheet tab from 'Sheet' dropdown
What you should see: The credential shows 'Connected' and your sheet columns appear in the field mapping section.
Common mistake — Don't use Service Account auth here — OAuth2 gives better error messages when permissions fail
3

Trigger Settings > Operation > Row Updated

Set Update Detection Method

Configure how N8n detects changes in your sheet. Use 'On Row Update' to catch edits to existing records rather than just new rows.

  1. 1Set 'Trigger On' to 'Row Updated'
  2. 2Enter the range containing your data (e.g., 'A1:F1000')
  3. 3Set 'Poll Times' to 'Every 5 Minutes'
  4. 4Enable 'Include Headers' checkbox
What you should see: The trigger shows 'Row Updated' mode with your specified range and polling interval.
Common mistake — Polling every minute will hit Google's rate limits — stick to 5+ minute intervals for bulk updates
4

Nodes > Add > HubSpot > Contact > Update

Add HubSpot Connection Node

Add the HubSpot node that will receive the updated property data. This handles the actual sync to your CRM.

  1. 1Click the '+' button after your Google Sheets trigger
  2. 2Search for 'HubSpot' and select it
  3. 3Choose 'Contact' as the Resource
  4. 4Set Operation to 'Update'
What you should see: A HubSpot node appears connected to your trigger, showing Contact Update configuration options.
5

Node Settings > Credentials > HubSpot API

Configure HubSpot API Credentials

Set up your HubSpot API connection using a private app token. This requires admin access to create the token in HubSpot.

  1. 1Click 'Create New Credential' under HubSpot API
  2. 2Choose 'Private App Token'
  3. 3Paste your HubSpot private app token
  4. 4Click 'Save' and test the connection
What you should see: The credential shows 'Connected' with a green checkmark next to HubSpot API.
Common mistake — Make sure your HubSpot token has 'contacts.write' scope — read-only tokens will fail silently on updates
6

HubSpot Node > Contact to Update > By Email

Map Contact Identification Field

Tell HubSpot which contact to update by mapping your sheet's email column to HubSpot's contact lookup. This is critical for targeting the right records.

  1. 1Click the 'Contact to Update' field
  2. 2Select 'By Email' from the dropdown
  3. 3Click the 'Email' input field
  4. 4Select your email column from the Google Sheets data (e.g., '{{ $json.email }}')
What you should see: The Email field shows your mapped column reference like '{{ $json.email }}'.
Common mistake — If contacts don't have emails in HubSpot, use 'By ID' instead — email lookup will fail for contacts without email addresses
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
7

HubSpot Node > Properties to Set > Add Property

Map Property Fields

Connect your spreadsheet columns to HubSpot contact properties. Each column becomes a property update in HubSpot.

  1. 1Scroll to 'Properties to Set' section
  2. 2Click 'Add Property'
  3. 3Enter the HubSpot property name (e.g., 'phone')
  4. 4Map to your sheet column (e.g., '{{ $json.phone_number }}')
  5. 5Repeat for each column you want to sync
What you should see: Multiple property mappings appear, each showing a HubSpot property linked to a sheet column.
Common mistake — Use exact HubSpot internal property names — 'Phone Number' won't work, but 'phone' will
8

HubSpot Node > Settings > Error Handling

Add Error Handling

Set up error handling to prevent one bad record from stopping your entire sync. This is essential for bulk operations.

  1. 1Click the three dots on the HubSpot node
  2. 2Select 'Settings'
  3. 3Set 'On Error' to 'Continue (with error)'
  4. 4Enable 'Always Output Data' checkbox
What you should see: The node settings show error handling enabled with continue-on-error behavior.
9

Toolbar > Test Workflow

Test with Sample Data

Run a test execution to verify your field mappings work correctly. This catches mapping errors before you go live.

  1. 1Click 'Test Workflow' in the top toolbar
  2. 2Wait for the Google Sheets trigger to poll
  3. 3Check the HubSpot node output for success/error messages
  4. 4Verify the update appeared in HubSpot by checking a test contact
What you should see: Both nodes show green checkmarks with execution data, and your HubSpot contact reflects the updated properties.
Common mistake — Test with real data, not sample JSON — HubSpot's validation differs between test and live data
n8n
▶ Run once
executed
Google Sheets
HubSpot
HubSpot
🔔 notification
received
10

Nodes > Add > Wait > Fixed Time

Add Rate Limiting

Insert a delay node to avoid hitting HubSpot's 100 requests/10 seconds rate limit when processing many rows at once.

  1. 1Add a 'Wait' node between Google Sheets and HubSpot
  2. 2Set 'Wait Time' to '200ms'
  3. 3Choose 'Fixed Time' as the wait type
  4. 4Connect the nodes: Sheets → Wait → HubSpot
What you should see: A Wait node sits between your trigger and HubSpot node with a 200ms delay configured.
Common mistake — Don't skip this — HubSpot returns 429 errors at high volume and N8n doesn't auto-retry by default
11

Workflow > Active Toggle

Activate the Workflow

Turn on the workflow to start monitoring your sheet for changes. Once active, it will run automatically on your polling schedule.

  1. 1Click the 'Active' toggle in the top right
  2. 2Confirm activation in the popup dialog
  3. 3Verify the status shows 'Active' with a green dot
What you should see: The workflow shows 'Active' status and begins polling your Google Sheet every 5 minutes.
Common mistake — Active workflows count against your execution quota even when no changes occur — monitor usage if you're on a limited plan

Drop this into an n8n Code node.

Copy this template{{ $json.email ? $json.email.toLowerCase().trim() : null }}
▸ Show code
{{ $json.email ? $json.email.toLowerCase().trim() : null }}

... expand to see full code

{{ $json.email ? $json.email.toLowerCase().trim() : null }}

Scaling Beyond 500+ property updates per batch+ Records

If your volume exceeds 500+ property updates per batch records, apply these adjustments.

1

Batch Processing

Add a SplitInBatches node to process 50 contacts at a time instead of one-by-one. This reduces execution count and improves reliability with large datasets.

2

Increase Polling Interval

Change from 5-minute to 15-minute polling to reduce execution usage. Most bulk property updates don't need real-time sync and can tolerate the delay.

3

Add Retry Logic

Use an IF node to catch HubSpot 429 errors and retry failed requests after a 30-second delay. This prevents lost updates during rate limit periods.

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 data transformation logic or want to avoid per-task pricing on large batches. N8n's code nodes let you validate emails, format phone numbers, or merge fields before sending to HubSpot. The flat monthly pricing makes sense when updating 1000+ contacts regularly. Skip N8n if you just need basic column-to-property mapping without transformation — Zapier's interface is simpler for straightforward syncs.

Cost

This workflow uses 1 execution per changed row. At 500 property updates monthly, that's 500 executions total. N8n's Starter plan ($20/month) includes 5,000 executions, so you're well covered. Zapier would cost $49/month for their Professional plan to handle the same volume. Make's Core plan at $10/month works but limits you to 1,000 operations — fine for smaller batches.

Tradeoffs

Zapier handles Google Sheets triggers better — their polling is more reliable and catches formula changes that N8n misses. Make's HubSpot integration has better error messages when property updates fail. But N8n wins on cost and flexibility. The code nodes let you build complex validation logic that would require multiple Zaps or Make scenarios.

Google Sheets API paginates at 100 rows, so bulk updates over that limit need N8n's batch processing node to loop through chunks. HubSpot's contact search by email is case-sensitive — '[email protected]' won't match '[email protected]' in your CRM. The polling trigger has a 10-second minimum interval despite what the UI suggests — faster polling gets throttled automatically.

Ideas for what to build next

  • Add Slack Notifications for Failed UpdatesConnect a Slack node to the error output of your HubSpot node to get notified when property updates fail validation or hit rate limits.
  • Create Audit Log in Another SheetAdd a Google Sheets node that logs successful updates with timestamps to track which contacts were modified and when.

Related guides

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