Guide

Aggregare Dati: Combinare Informazioni da Diverse API in un Unico Report

Quando i dati arrivano da molte fonti (advertising, CRM, billing, supporto), il valore nasce dalla capacità di unirli in modo coerente. Con aggregazione dati con n8n puoi costruire pipeline ETL/ELT low‑code che estraggono da API eterogenee, normalizzano i payload JSON, eseguono join e deduplica dei record e pubblicano un unico report per marketing e vendite. In questa guida pratica costruirai un’architettura riutilizzabile: dall’ingest tramite HTTP Request con paginazione e autenticazione, alla normalizzazione dei dati JSON e mapping dello schema dati, fino alla scrittura su Google Sheets o DB. Vedrai pattern reali per join e dedup (anche tra array annidati), rate limiting e backoff, e calcolo KPI con Code/Function. Obiettivo: passare da screenshot manuali a report quotidiani affidabili che combinano più API, riducendo errori e tempo uomo. Perfetta per marketer che desiderano orchestrare integrazione API con n8n senza scrivere un backend complesso, mantenendo controllo su performance, costi e governance.

📚 Nuovo a n8n? Parti dalla guida completa: cos’è n8n e come funziona.

[IMG: Panoramica flusso: HTTP Request (API A/B/C) → Set/Code (normalize) → Item Lists (split) → Merge (join) → Code (KPI) → Google Sheets/DB (report)]


Architettura ETL/ELT low‑code con n8n: principi e design

Per unire dati multi‑API serve uno schema e un flusso chiari:

  • Estrai (E): usa HTTP Request per interrogare ogni sorgente (ads, CRM, fatturazione), gestendo query, header, autenticazione e rate limit.
  • Trasforma (T): normalizzazione dei dati JSON e mapping dello schema dati per uniformare campi (es. campaignId, date, spend, leads, revenue).
  • Carica (L): scrivi il risultato in un’unica tabella (Google Sheets, Airtable o DB) e alimenta dashboard BI.

Componenti tipici

  • HTTP Request, Item Lists (splitIntoItems), Set (keepOnlySet), Code/Function (functionCode), Merge (mergeByKey), Split In Batches (batchSize), IF/Switch per routing condizionale, Google Sheets (append).
  • Scelta ELT vs ETL: ELT spinge i dati quasi raw a un DB/warehouse e trasforma a valle; ETL normalizza già in n8n. Per marketer, ETL low‑code spesso è più veloce da mettere in produzione.

Linee guida

  • Progetta upfront lo schema “reportReady”: campi coerenti tra sorgenti, tipizzazioni, chiavi di join, granularità temporale (giorno/settimana).
  • Inserisci metadati: source, fetchTimestamp, version per audit e tracciabilità.
  • Versiona i workflow: una modifica al mapping non deve “rompere” i report esistenti.

[IMG: Schema logico: API raw → Normalize → Join → KPI → Report]


Ingest da API multiple: HTTP Request, credenziali e paginazione

Il nodo “n8n-nodes-base.httpRequest” è il cavallo di battaglia per integrazione API con n8n. Parametri chiave (esatti) da configurare nel JSON del nodo:

  • url
  • method
  • responseFormat
  • jsonParameters
  • queryParametersUi
  • headerParametersUi
  • bodyParametersUi o bodyParametersJson (se invii payload JSON)
  • options (es. bodyContentType: “json”)
  • credentials (se usi auth gestite)

Esempio GET con query e header

{
  "name": "Fetch Ads",
  "type": "n8n-nodes-base.httpRequest",
  "typeVersion": 1,
  "parameters": {
    "url": "https://api.example-ads.com/v1/spend",
    "method": "GET",
    "responseFormat": "json",
    "queryParametersUi": {
      "parameter": [
        { "name": "date", "value": "={{ $json.reportDate }}" },
        { "name": "page", "value": "={{ $json.page || 1 }}" },
        { "name": "limit", "value": "100" }
      ]
    },
    "headerParametersUi": {
      "parameter": [
        { "name": "Authorization", "value": "Bearer {{ $json.apiToken }}" }
      ]
    },
    "jsonParameters": true,
    "options": { "bodyContentType": "json" }
  }
}

Gestione paginazione delle API

  • Non esiste un parametro “pagination” dedicato: implementa loop variando “page” (o “cursor”) via queryParametersUi.
  • Pattern consigliato:
  1. Set iniziale con page=1.

  2. HTTP Request → If “items.length > 0”.

  3. Item Lists (splitIntoItems) per elaborare i record.

  4. Merge/Append in una lista cumulativa o scrittura batch.

  5. Incrementa page e ripeti finché la risposta è vuota.

Idempotenza e resilienza

  • Passa un “fetchId” (es. data + sorgente) per evitare duplicati in scrittura.
  • Se l’API supporta etag o since/updated_after, preferiscili a page/offset per job incrementali.

[IMG: Loop paginazione: Set(page=1) → HTTP → IF (hasItems) → split → aggregate/append → page++ → loop]


Normalizzazione dei dati JSON e mapping dello schema

Prima di unire le fonti, porta ogni payload a uno schema coerente.

Set node come “mapper visivo”

  • Parametri chiave:
  • keepOnlySet: true per mantenere solo i campi mappati.
  • values: definisci i nuovi campi, tipizzati.
  • removeFields: opzionale per eliminare campi indesiderati.

Esempio Set (mapping minimo)

{
  "name": "Normalize Ads Row",
  "type": "n8n-nodes-base.set",
  "typeVersion": 3,
  "parameters": {
    "keepOnlySet": true,
    "values": {
      "string": [
        { "name": "source", "value": "example-ads" },
        { "name": "campaignId", "value": "={{ $json.campaign_id }}" },
        { "name": "date", "value": "={{ $json.date }}" }
      ],
      "number": [
        { "name": "spend", "value": "={{ +$json.spend_cents/100 }}" },
        { "name": "clicks", "value": "={{ +$json.clicks }}" }
      ]
    }
  }
}

Code node per trasformazioni custom

  • functionCode utile per normalizzare formati, calcolare campi derivati, validare valori:
// Run Once For Each Item
const row = $json;
row.cpc = row.clicks ? +(row.spend / row.clicks).toFixed(2) : 0;
row.fetchTimestamp = $now; // timestamp corrente
return [{ json: row }];

Best practice di normalizzazione dei dati JSON

  • Tipizza subito numeri e date (evita stringhe ambigue).
  • Uniforma i nomi dei campi tra fonti (campaignId, date, spend, leads, revenue).
  • Aggiungi “source” per tracciare la provenienza e facilitare debug/join.

[IMG: Set (keepOnlySet) → Code (derive fields) con anteprima campi normalizzati]


Join e deduplica dei record tra fonti

Per unire più dataset (es. Ads + CRM + Billing):

  • Allinea la granularità: per data e campaignId (o altra chiave).
  • Esegui join e deduplica dei record con i nodi Item Lists e Merge.

Item Lists per preparare i dataset

  • splitIntoItems: trasforma un array di record in item singoli per elaborazioni per‑riga.
{
  "name": "Split CRM Leads",
  "type": "n8n-nodes-base.itemLists",
  "typeVersion": 1,
  "parameters": {
    "operation": "splitIntoItems",
    "property": "results"
  }
}
  • aggregateItems: ricompone più item in un singolo array quando necessario.

Merge node per join

  • mergeByKey con propertyName per unire per chiave (es. campaignId+date).
{
  "name": "Join Ads + CRM",
  "type": "n8n-nodes-base.merge",
  "typeVersion": 1,
  "parameters": {
    "mode": "mergeByKey",
    "propertyName": "joinKey",
    "outputDataFrom": "both"
  }
}

Suggerimento: crea “joinKey” prima del Merge (es. “{{ $json.campaignId }}|{{ $json.date }}”).

Deduplica

  • In caso di duplicati (es. CRM con più lead sulla stessa chiave), consolida con Code:
// Run Once For All Items: deduplica per joinKey sommando metriche
const map = new Map();
for (const item of items) {
  const r = item.json;
  const k = r.joinKey;
  const acc = map.get(k) || { ...r, leads: 0, revenue: 0 };
  acc.leads += +r.leads || 0;
  acc.revenue += +r.revenue || 0;
  map.set(k, acc);
}
return Array.from(map.values()).map(v => ({ json: v }));

[IMG: Normalize (A/B/C) → Set(joinKey) → Merge by Key → Code(dedup/sum) → Report]


Calcolo KPI e arricchimento: dal dataset al report

Dopo il join, calcola KPI utili per marketing:

  • CPC = spend / clicks
  • CPL = spend / leads
  • ROAS = revenue / spend
  • Conversion rate = leads / clicks

Esempio Code (calcolo KPI)

// Run Once For Each Item
const r = $json;
const safe = (n) => (isFinite(n) && !isNaN(n)) ? n : 0;
r.cpc = safe(r.spend) && safe(r.clicks) ? +(r.spend / r.clicks).toFixed(2) : 0;
r.cpl = safe(r.spend) && safe(r.leads) ? +(r.spend / r.leads).toFixed(2) : 0;
r.roas = safe(r.spend) ? +(safe(r.revenue) / r.spend).toFixed(2) : 0;
return [{ json: r }];

Regole e segmentazione

  • Usa Switch per segmentare per canale/paese:
{
  "name": "Segment By Channel",
  "type": "n8n-nodes-base.switch",
  "typeVersion": 1,
  "parameters": {
    "dataType": "string",
    "value1": "={{ $json.source }}",
    "rules": { "rules": [
      { "operation": "equal", "value2": "example-ads" },
      { "operation": "equal", "value2": "example-crm" }
    ] },
    "fallbackOutput": 2
  }
}
  • IF per filtri qualità dati (es. escludi linee senza date/campaignId):
{
  "name": "Has Required Fields",
  "type": "n8n-nodes-base.if",
  "typeVersion": 2,
  "parameters": {
    "conditions": {
      "string": [
        {
          "value1": "={{ $json.campaignId }}",
          "operation": "isEmpty"
        }
      ]
    },
    "combineOperation": "and"
  }
}

(Usa operatori coerenti con la tua versione; in alternativa verifica con Code e droppa l’item.)

[IMG: Code(KPI) → Switch(segment) → IF(filter) → Append]


Scrittura del report: Google Sheets, Airtable o DB

Google Sheets: append automatico

{
  "name": "Append Report",
  "type": "n8n-nodes-base.googleSheets",
  "typeVersion": 4,
  "parameters": {
    "operation": "append",
    "spreadsheetId": "1A2b3C4D5E6FgHiJkLMnoPQrstu",
    "sheetName": "Campaign_Report",
    "dataMode": "autoMap",
    "options": { "valueInputMode": "USER_ENTERED" }
  },
  "credentials": {
    "googleSheetsOAuth2Api": { "name": "Google Sheets OAuth2" }
  }
}

Alternative

  • Airtable: tabella con schema “reportReady”.
  • DB: più robusto per storici (MySQL/Postgres) e BI. In questo caso, valuta ELT: carica raw e trasforma con viste/materialized views.

Consigli pratici

  • Mappa le colonne con header coerenti: date, campaignId, source, spend, clicks, leads, revenue, cpc, cpl, roas.
  • Appendi solo i record del giorno/periodo corrente; per ricalcoli completi (backfill) esegui job separati.

[IMG: Foglio “Campaign_Report” con colonne mappate automaticamente]


Rate limiting, backoff e performance

Rate limiting e backoff

  • Throttling per API “sensibili”: usa Split In Batches con batchSize per limitare le chiamate simultanee.
{
  "name": "Batch Loop",
  "type": "n8n-nodes-base.splitInBatches",
  "typeVersion": 1,
  "parameters": { "batchSize": 10 }
}
  • Tra un batch e l’altro, inserisci una breve pausa (Code o nodo di attesa) e riprendi il loop finché ci sono items.
  • In caso di errori/429, implementa backoff crescente (2s → 5s → 10s) e ritenta.

Gestione paginazione efficiente

  • Interrompi il loop quando la risposta non ritorna più elementi.
  • Usa parametri “updated_after” quando disponibili per job incrementali.

Ottimizzazioni

  • Riduci i campi al minimo prima di Merge/Sheets (Set keepOnlySet).
  • Esegui calcoli KPI “Run Once For Each Item” per ridurre la memoria.
  • Evita log ridondanti: conserva solo il necessario per audit.

[IMG: SplitInBatches(10) → HTTP → (retry/backoff) → Append/Join → next batch]


Esempio end‑to‑end: report giornaliero Ads + CRM + Billing

Obiettivo: unire spend (Ads), leads (CRM), revenue (Billing) per campaignId e date.

Step‑by‑step

  1. Inizializza
  • Set: reportDate = oggi, page=1, apiToken da credenziali (o variabili).
  • [IMG: Nodo Set iniziale con costanti job]
  1. Ingest Ads
  • HTTP Request (GET) con queryParametersUi (date, page, limit), headerParametersUi (Authorization).
  • Loop paginato fino a esaurimento.
  • Item Lists splitIntoItems su “data” (array di righe).
  • Set keepOnlySet: source, campaignId, date, spend, clicks.
  1. Ingest CRM
  • HTTP Request su endpoint leads per date.
  • splitIntoItems, Set => source=crm, campaignId, date, leads.
  • Deduplica per campaignId/date con Code (somma leads).
  1. Ingest Billing
  • HTTP Request su fatture pagate per date.
  • splitIntoItems, Set => source=billing, campaignId, date, revenue.
  • Deduplica revenue per campaignId/date.
  1. Join
  • Per ogni dataset, crea joinKey = “{{ $json.campaignId }}|{{ $json.date }}”.
  • Merge by Key (Ads + CRM), poi Merge by Key (risultato + Billing) con:
{
  "parameters": {
    "mode": "mergeByKey",
    "propertyName": "joinKey",
    "outputDataFrom": "both"
  }
}
  1. KPI e filtri
  • Code: calcola cpc, cpl, roas.
  • IF/Switch: filtra righe incomplete o segmenta per mercato.
  1. Report
  • Google Sheets (append) su Campaign_Report con dataMode: autoMap.
  • Aggiungi fetchTimestamp = $now per audit.
  1. Osservabilità
  • Log sintetico: righe processate, sorgenti chiamate, durata job.
  • Notifica Slack finale con conteggi record.

[IMG: Canvas completo con nodi principali e rami di join]


Osservabilità, governance e versioning

  • Logging: salva contatori per source (righe lette/scritte), errori per endpoint, tempo totale job.
  • Alert: Slack in caso di errori ripetuti o risposte 5xx.
  • Versioning: duplica workflow per nuove versioni; annota in header foglio la “schema_version”.
  • Sicurezza: credenziali delle API nelle “credentials” n8n, variabili d’ambiente per segreti; limita permessi in scrittura.

Scalabilità

  • Quando crescono le fonti, replica il pattern: una fase di ingest/normalize per source, poi join per chiave, KPI e scrittura.
  • Passa da Sheets a DB quando i volumi aumentano, mantenendo lo stesso schema concettuale.

[IMG: Dashboard KPI di job con record processati e time per fase]


Quick Takeaways

  • Progetta uno schema “reportReady” e usa Set/Code per normalizzare le fonti prima del join.
  • Implementa la gestione paginazione delle API con loop su page/limit via queryParametersUi.
  • Esegui join con Merge (mode: mergeByKey, propertyName: joinKey) e deduplica con Code aggregando metriche.
  • Applica rate limiting e backoff con Split In Batches (batchSize) e retry controllati su errori/429.
  • Pubblica il report con Google Sheets (append) o DB e aggiungi KPI (CPC, CPL, ROAS) in Code.
  • Monitora: logging sintetico, alert Slack, versioning del workflow per modifiche sicure.

Conclusione

L’aggregazione dati con n8n ti permette di creare un layer di integrazione API low‑code rapido da rilasciare e semplice da mantenere. Con pochi nodi chiave — HTTP Request, Set, Item Lists, Merge, Code e Google Sheets — trasformi payload diversi in un report unico e coerente. La chiave è progettare lo schema a monte, normalizzare presto e unire con chiavi stabili, aggiungendo KPI utili per decisioni quotidiane. Con rate limiting, paginazione e deduplica riduci errori e costi, mentre logging e versioning assicurano governance. Inizia con due sorgenti e poche metriche core, poi estendi a nuove API e breakdown (canali, paesi, segmenti). In poche iterazioni avrai un’unica vista affidabile di spend, lead e ricavi, pronta per BI e pianificazione. Se vuoi fare il salto di qualità nella produttività marketing, imposta oggi il primo workflow: domani non tornerai più agli export manuali.


FAQ

  1. Come gestisco più pagine di un’API in n8n?

Usa queryParametersUi per passare page/limit e implementa un loop: incrementa “page” finché la risposta non ritorna più record. Puoi orchestrare il ciclo con IF e Set, e processare i risultati con Item Lists (splitIntoItems).

  1. Come unisco dati di diverse fonti in un’unica riga?

Crea una joinKey (es. campaignId|date) con Set/Code e usa il Merge node con mode: “mergeByKey”, propertyName: “joinKey”, outputDataFrom: “both”. Prima del join, assicurati la normalizzazione dei dati JSON.

  1. Come evito duplicati dopo il join?

Applica join e deduplica dei record con un Code “Run Once For All Items” aggregando per joinKey (somma leads/revenue). In alternativa, pulisci i duplicati a monte in ciascuna fonte.

  1. Come rispetto i limiti delle API durante l’ingest?

Usa Split In Batches con batchSize adeguato, inserisci pause tra i batch e implementa rate limiting e backoff: in caso di 429/5xx, ritenta con delay progressivo e limita la concorrenza.

  1. È meglio scrivere su Google Sheets o su un database?

Per volumi piccoli e prototipi, Google Sheets con operation: “append” e dataMode: “autoMap” è rapido. Per storici e query avanzate, passa a un DB (MySQL/Postgres) mantenendo lo stesso mapping dello schema dati.


Ci dai una mano?

Quale combinazione di API vuoi unire per prima (Ads + CRM, CRM + Billing, altro)? Raccontaci il tuo caso e condividi questo articolo con il team: confrontiamo setup e pattern per costruire insieme report più completi e affidabili!

Articoli correlati

Vuoi automazioni AI su misura per la tua azienda?
Scopri la consulenza →

Partiamo da un processo che oggi vi costa ore

Su WhatsApp risponde una persona, di solito in giornata. Se preferisci scrivere con calma, c’è il modulo qui sotto.

Scrivici su WhatsApp

Raccontaci cosa vuoi automatizzare

Ti rispondiamo noi, di solito in giornata.

Raccontaci cosa vi fa perdere tempo

Due righe bastano. Vi diciamo se si automatizza, come, e quanto costa. Se non conviene, lo diciamo.