Se lavori con campagne, liste e pipeline, sai quanto tempo si perde tra esportazioni CSV e copia-incolla. Con hubspot google sheets n8n puoi costruire una sincronizzazione affidabile che aggiorni automaticamente i contatti tra CRM e fogli di lavoro, senza interventi manuali e con controllo sui conflitti. In questa guida impari a progettare un’integrazione tra HubSpot e Google Sheets con n8n: definire lo schema dei dati, scegliere tra real‑time e schedulato, impostare credenziali OAuth, normalizzare email e telefoni, orchestrare l’upsert basato su email o Contact ID, gestire i limiti API con batching e monitorare errori e costi. Ti mostrerò pattern neutri e collaudati per sincronizzazione dei contatti CRM in modo automatico, con esempi concreti su mapping delle proprietà dei contatti di HubSpot, deduplicazione e controlli di qualità dati. Obiettivo: darti un blueprint riutilizzabile che trasformi i fogli in un “staging” affidabile e connesso al CRM, così il tuo team marketing lavora sui dati e non sulle esportazioni.
[IMG: Panoramica di un workflow n8n con rami HubSpot→Sheets e Sheets→HubSpot, nodi di batching e nodi di controllo]
Architettura dell’integrazione: real‑time, schedulato, mono e bidirezionale
Per prima cosa definisci il “modello” di sincronizzazione:
- One‑way (HubSpot → Sheets): ideale per report, dashboard e revisione operativa. Il foglio contiene uno “specchio” dei contatti aggiornato, utile per data quality e analisi ad hoc.
- One‑way (Sheets → HubSpot): utile per import massivi, arricchimenti e campagne. Il foglio è l’area di staging dove pulisci, deduplichi e poi scrivi nel CRM.
- Two‑way (HubSpot ↔ Sheets): potente ma più complesso. Richiede regole chiare di “sorgente di verità”, timestamp (es. hs_lastmodifieddate) e un criterio di prevalenza in caso di conflitto.
Event‑driven vs schedulato:
- Real‑time: usa un trigger dal CRM per reagire a creazioni/aggiornamenti contatto (event‑driven). Ottimo per pipeline e notifiche, ma fai attenzione al rate limit API.
- Schedulato: cron ogni 5–15 minuti per “polling” o per sincronizzazioni batch. È prevedibile e più facile da governare con volumi alti.
Fogli Google come staging per data quality:
- Struttura Sheet con colonne stabili (email, firstname, lastname, phone, hsobjectid, hslastmodifieddate, source, lastsync).
- Aggiungi colonne helper per verifiche e qualità (validemail, phonee164, duplicate_flag).
Tip: anche se punti a un setup bidirezionale, inizia con flussi separati (HubSpot→Sheets e Sheets→HubSpot) per ridurre variabili. Una volta stabili, definisci la logica di risoluzione dei conflitti.
Preparazione: credenziali, schema e compliance
Gestione credenziali OAuth Google e HubSpot
- Crea le credenziali “Google Sheets OAuth2” e HubSpot OAuth/Private App con gli scope minimi necessari (least privilege).
- Salva le credenziali in n8n e testale con nodi singoli (lettura di uno Sheet, lettura di un contatto).
Schema del foglio e mapping delle proprietà dei contatti di HubSpot
- Definisci colonne allineate con le proprietà HubSpot più usate: email, firstname, lastname, phone, company, lifecyclestage, hsobjectid, hslastmodifieddate.
- Evita di cambiare i nomi delle colonne nel tempo; documenta i campi opzionali.
Conformità GDPR e protezione dei dati personali
- Minimizza PII nel foglio: conserva solo ciò che serve alla tua automazione.
- Applica retention: pulisci righe obsolete o spostale in un tab “archive”.
- Limita l’accesso al foglio (solo persone/servizi necessari) e abilita alert per modifiche anomale.
[IMG: Foglio Google con intestazioni standardizzate e colonna last_sync]
Flusso A (HubSpot → Sheets): esportare e aggiornare i contatti
Scopo: riflettere nel foglio le novità del CRM per analisi, QA e reporting.
Passi
1) Trigger o polling dal CRM
- Usa un trigger HubSpot (event‑driven) oppure un nodo di polling (“Get recently created/updated contacts”) per ottenere gli ultimi contatti modificati. Imposta un filtro temporale coerente o conserva l’ultimo timestamp processato per evitare duplicati.
2) Normalizzazione dei campi
- Inserisci un nodo “Code” leggero per pulire email/telefoni e allineare i tipi.
// Mode: Run Once For Each Item
const j = $json;
const normEmail = String(j.email || '').trim().toLowerCase();
const phone = String(j.phone || '').replace(/\D+/g, ''); // semplificazione
return {
json: {
email: normEmail,
firstname: j.firstname || '',
lastname: j.lastname || '',
phone,
company: j.company || '',
hs_object_id: j.hs_object_id || j.id || null,
hs_lastmodifieddate: j.hs_lastmodifieddate || null,
source: 'hubspot',
last_sync: new Date().toISOString()
}
};
3) Append su Google Sheets
- Usa il nodo Google Sheets con Append To Sheet per scrivere righe in coda. Con auto‑mapping, il nodo mappa i campi in base alle intestazioni dello Sheet.
Configurazione esatta (parametri supportati)
{
"parameters": {
"operation": "append",
"spreadsheetId": "1A2b3C4D5E6FgHiJkLMnoPQrstu",
"sheetName": "Contacts",
"dataMode": "autoMap",
"options": {
"valueInputMode": "USER_ENTERED"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "Google Sheets OAuth2"
}
}
}
4) Evitare duplicati di riga
- Se lo Sheet può contenere righe già presenti, aggiungi un passaggio di deduplicazione a valle (vedi sezione “Deduplicazione e conflitti”). In alternativa, usa un tab staging e un tab “master” dove unisci/aggiorni con un processo di pulizia.
[IMG: Nodo Google Sheets configurato su “Append To Sheet” con dataMode=autoMap]
Flusso B (Sheets → HubSpot): upsert basato su email o Contact ID
Scopo: usare il foglio come staging per creare o aggiornare contatti nel CRM.
Passi
1) Lettura dal foglio
- Usa Google Sheets per leggere righe (per esempio un range su “ContactsStaging”). Assicurati di avere almeno email o hsobject_id.
2) Normalizzazione e validazione
- Ripulisci campi essenziali con un nodo “Code” (email valida, telefono normalizzato) ed etichetta righe non valide per esclusione.
3) Batching per limiti API
- Inserisci “Split In Batches” (es. 20 item/batch) e un “Wait” di 1–3 secondi tra batch per rispettare i rate limit.
4) Upsert su HubSpot
- Per ogni riga valida: se hai hsobjectid, aggiorna direttamente; altrimenti cerca per email e crea/aggiorna in base al risultato.
- Mappa solo i campi necessari per ridurre rischi (firstname, lastname, email, phone, company).
5) Esito e logging
- Scrivi last_sync e un esito (ok/error + messaggio) su una colonna di ritorno; invia alert Slack/Email se errori > soglia.
Nota: il set di operazioni del nodo HubSpot include creazione/aggiornamento contatti; in alternativa, puoi usare “HTTP Request” con le API di HubSpot se ti serve una logica custom. Mantieni i retry limitati e rispetta i limiti di velocità del provider.
Mapping, normalizzazione e qualità dati
Normalizzazione campi email e telefono
- Email: sempre lowercase e trim; scarta righe senza “@”.
- Telefono: rimuovi caratteri non numerici e conserva solo valori completi; opzionalmente salva una versione E.164 in una seconda colonna.
Mapping delle proprietà dei contatti di HubSpot
- Mantieni un dizionario “Sheet → HubSpot”:
- email → email
- firstname → firstname
- lastname → lastname
- phone → phone
- company → company
- Evita proprietà custom finché non servono. Documenta ogni aggiunta.
Validazioni prima dell’invio al CRM
// Per-item: controlli minimi prima dell’upsert
const j = $json;
const emailOk = /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(j.email || '');
if (!emailOk) {
return { json: { ...j, valid: false, reason: 'Invalid email' } };
}
return { json: { ...j, valid: true } };
A valle, un IF separa righe valide da quelle da correggere (tab “errors” nello Sheet).
Deduplicazione dei contatti e risoluzione dei conflitti
Deduplicazione dei contatti e unione record
- Chiave consigliata: email. Se non unica, usa un compound key (email + domain) o gestisci una regola di “canonical”.
- Strategia “prefer latest”: in caso di duplicati, conserva la riga con lastsync più recente o con hslastmodifieddate più nuova.
Snippet di dedup
// All-items: dedup per email, preferisci il record con last_sync più recente
const rows = $input.all().map(i => i.json);
const byEmail = new Map();
for (const r of rows) {
const k = String(r.email || '').toLowerCase().trim();
if (!k) continue;
const prev = byEmail.get(k);
if (!prev) byEmail.set(k, r);
else {
const t1 = new Date(prev.last_sync || 0).getTime();
const t2 = new Date(r.last_sync || 0).getTime();
if (t2 >= t1) byEmail.set(k, r);
}
}
return Array.from(byEmail.values()).map(j => ({ json: j }));
Risoluzione conflitti (bidirezionale)
- Definisci “fonte autorevole” per ogni campo (es. email e company dal CRM, note operative dallo Sheet).
- Usa timestamp per risolvere differenze per lo stesso campo; se uguale, preferisci CRM per sicurezza.
- Logga i conflitti non risolvibili e invia un alert.
Limiti API, batching e controllo del flusso
Gestione dei limiti API e batching delle richieste
- “Split In Batches” con Batch Size 10–25 è un punto di partenza realistico.
- Inserisci un “Wait” di 1–3 s tra batch per ridurre i 429 (Too Many Requests).
- Misura il tempo medio per batch e adatta il Batch Size di conseguenza.
Controllo del flusso e resilienza
- Usa IF dopo ogni chiamata HubSpot per controllare lo status; su errori temporanei, fai 1–2 retry con backoff crescente (2s → 5s).
- Se troppi errori, interrompi e invia alert (Slack/Email) con il conteggio per batch.
[IMG: Pattern Split In Batches → HTTP/HubSpot → IF status → Wait → Execute Next Batch con uscita No Items a report finale]
Monitoraggio, costi e governance dell’integrazione
Log, alert e monitoraggio dei job di integrazione
- Abilita un workflow di “Error Trigger” per centralizzare gli errori di esecuzione.
- Traccia KPI: righe processate, create/aggiornate, errori per batch, durata media job.
- Invia un report giornaliero su Slack con summary (contatti sync, dedup, errori aperti).
Stima costi ed esecuzioni
- Ottimizza per ridurre esecuzioni “vuote”: in poll, processa solo le modifiche recenti; in append, evita doppioni lato Sheets con dedup.
- Consolida piccole modifiche in batch invece di run frequenti ad 1 item.
Orchestrazione dei workflow no‑code per RevOps
- Separa flussi per responsabilità (export, staging, upsert) e colligali con trigger/schedule.
- Documenta in README di progetto: campi, mapping, policy di conflitto, KPI e contatti “owner”.
Esempio completo: HubSpot → Sheets (export pulito) e Sheets → HubSpot (upsert)
A) Export dal CRM
- Trigger HubSpot o polling “recently updated”.
- Code (normalize) → Google Sheets (Append To Sheet, autoMap) → Dedup sheet → Report Slack.
Config di Append (esatta):
{
"parameters": {
"operation": "append",
"spreadsheetId": "1A2b3C4D5E6FgHiJkLMnoPQrstu",
"sheetName": "Contacts",
"dataMode": "autoMap",
"options": { "valueInputMode": "USER_ENTERED" }
},
"credentials": { "googleSheetsOAuth2Api": { "name": "Google Sheets OAuth2" } }
}
B) Upsert verso CRM
- Google Sheets (read) → Code (validazione, normalizzazione) → Split In Batches (20) → [HubSpot create/update] → Wait (2s) → Execute Next Batch → Esiti su Sheet (last_sync, status).
[IMG: Canvas con due rami separati, ognuno con i nodi principali e un pannello di report]
Quick Takeaways
- Progetta prima lo schema: colonne standard in Sheets e mapping minimale verso il CRM.
- Separa i flussi HubSpot→Sheets e Sheets→HubSpot; poi valuta il bidirezionale con regole di conflitto chiare.
- Normalizza email/telefoni e valida i record prima dell’upsert; usa i fogli come staging.
- Gestisci limiti con Split In Batches e piccoli Wait; monitora errori e tempi per batch.
- Usa Google Sheets “Append To Sheet” con dataMode=autoMap per velocizzare l’export.
- Riduci PII, applica least privilege e mantieni alert/report per la governance operativa.
Conclusione
Integrare hubspot google sheets n8n ti libera dal “CSV ping‑pong” e rende il dato più affidabile per campagne e analisi. Con una buona architettura (flussi separati, staging, regole di conflitto), normalizzazione a monte (email, phone), batching per rispettare i limiti API e un sistema di logging/alert, ottieni sincronizzazioni prevedibili e scalabili. Parti dall’export HubSpot→Sheets per creare un mirror aggiornato, aggiungi controlli di qualità e poi implementa l’upsert Sheets→HubSpot con Split In Batches, retry misurati e tracciamento dell’esito su colonne dedicate. Così il team marketing lavora su liste pulite, campagne più rapide e pipeline aggiornate senza interventi manuali. Metti in produzione gradualmente, misura gli indicatori (errori, tempo per batch, aggiornamenti effettivi) e ottimizza: la tua integrazione crescerà insieme ai tuoi obiettivi.
FAQ
1) Qual è il modo più semplice per iniziare l’integrazione tra HubSpot e Google Sheets con n8n?
Inizia con un flusso one‑way HubSpot → Sheets per creare un mirror dei contatti. Normalizza con un nodo Code e usa Google Sheets “Append To Sheet” con dataMode=autoMap. Poi aggiungi dedup e report.
2) Come faccio un upsert dei record basato su email o contact ID?
Leggi dallo Sheet, normalizza email/telefoni, usa Split In Batches e per ogni riga aggiorna se hai l’ID; altrimenti cerca per email e crea/aggiorna. Mantieni i retry limitati e logga l’esito in colonne di ritorno.
3) Come gestire i limiti API e batching delle richieste?
Imposta Split In Batches (es. 10–25), aggiungi un Wait di 1–3 s tra batch e monitora errori 429. Aumenta il Batch Size solo se non vedi errori o timeout.
4) Cosa mettere nelle colonne del foglio per una buona sincronizzazione?
Email, firstname, lastname, phone, company, hsobjectid, hslastmodifieddate, source, lastsync, più campi helper (validemail, duplicateflag). Mantieni le intestazioni stabili.
5) È meglio real‑time o schedulato?
Dipende dal caso: real‑time è utile per azioni immediate e notifiche; schedulato è più semplice da governare su volumi alti. Molti team usano entrambi: export in poll e upsert in batch.
Ci dai una mano?
Quale flusso implementerai per primo: HubSpot→Sheets per reporting o Sheets→HubSpot per upsert massivo? Condividi la tua scelta e questo articolo con il team: confrontiamo i pattern che funzionano meglio e costruiamo insieme integrazioni più solide!
Scopri la consulenza →

