Perché quello che ti insegnano sul CPL non basta
C'è un filosofo, Schopenhauer, che parlava del velo di Maya. Tu credi di vedere la realtà, e invece vedi un'ombra proiettata su una parete. La scambi per la cosa vera. Nel marketing quel velo ha un nome preciso, e si chiama CPL. Costo per lead. Quanto paghi per ogni contatto che ti lascia il nome e la mail. È il primo numero che ti insegnano a guardare, il primo che ogni piattaforma ti mette davanti agli occhi, grande, colorato. Più è basso, più sembra che tu stia vincendo. Funziona, questo ragionamento, finché tutti i contatti valgono uguale. Nel B2B, nei servizi, in tutto quello che un cliente compra e ricompra negli anni, i contatti non valgono mai uguale.
Ti faccio vedere la scena che mi capita davanti quasi ogni settimana. Due campagne sullo stesso pubblico, stessa immagine, stessa struttura. La prima raccoglie 200 contatti a 18 euro l'uno. La seconda ne raccoglie 80 a 35 euro l'uno. L'imprenditore apre la sua dashboard, ci mette il dito sopra, e dice la cosa che diresti anche tu: "questa la spegniamo, costa il doppio". Sembra ovvio. È il velo.
Poi prendo i contatti che Meta ha raccolto e li incollo accanto ai clienti che hanno davvero firmato nel gestionale. Ed ecco cosa c'era dietro l'ombra sulla parete. La prima campagna, quella "buona", portava gente che scaricava il PDF gratuito e svaniva. La seconda, quella da spegnere, portava gente che prenotava la call e firmava in 22 casi su 100. Quanto costava un cliente vero sulla prima? Tendeva all'infinito, perché di clienti veri quasi non ne usciva nessuno. Sulla seconda: 159 euro. Abbiamo girato il budget al contrario. Tre mesi dopo, il fatturato ricorrente di quel canale (MRR, cioè i soldi che entrano ogni mese in modo prevedibile) era cresciuto del 37%.
CPL basso non significa campagna buona. CPL alto non significa campagna cattiva. Il CPL da solo è una metrica di vanità, un like travestito da numero serio, finché nessuno va a guardare chi ha firmato. Matteo Coloru
Il framework operativo, passo per passo
Pensa a quando cucini un piatto serio. Il segreto non è il momento in cui accendi il fuoco. È la mise en place: tagliare, pesare, mettere ogni ingrediente al suo posto prima ancora di iniziare. L'80% del risultato si decide lì, nella preparazione, quando ancora non sta cuocendo niente. Questo metodo funziona uguale. Tre passi, e i primi due sono mise en place. Niente magia, niente squadra di ingegneri. Ti servono due tabelle, una domanda da fare al database, e un'oretta la prima volta per montare tutto. Poi gira da solo.
Step 1, identity stitching prima di tutto
"Identity stitching" è una di quelle parole che fanno sembrare difficile una cosa semplice. Tradotta: fare in modo che la stessa persona si chiami nello stesso identico modo dappertutto. Pensa a un cliente che si chiama Mario. Su Meta lascia la mail Mario.Rossi@Gmail.com, sul tuo gestionale entra come mario.rossi@gmail.com, e da qualche parte qualcuno l'ha scritto con uno spazio in fondo. Per te è la stessa persona. Per il computer sono tre Mario diversi. E se sono tre persone diverse, non li potrai mai mettere uno accanto all'altro.
Il rimedio è una regola sola, applicata sempre uguale: prima di salvare una mail, tutto minuscolo, via gli spazi davanti e dietro, via i caratteri strani. In codice è una riga sola, email.toLowerCase().trim(), e va messa in tre punti: dove Meta registra il contatto, dove il modulo della tua pagina lo raccoglie, dove il gestionale crea la scheda cliente. Tre punti, la stessa pulizia in tutti e tre. È la mise en place del dato: noiosa, invisibile, e decide tutto il resto.
Quanti contatti si ritrovano: la soglia che cambia tutto
Il "match rate" è la quota di contatti che riesci a ritrovare di là, nel gestionale. Senza la pulizia di prima, scende sotto il 60%. Vuol dire che 4 contatti su 10 si perdono per strada, e ogni decisione che prendi dopo nasce da un campione storto. Con la pulizia fatta bene sali al 95%. Tra il 60 e il 95 non c'è un dettaglio estetico. C'è la differenza tra fidarti dei tuoi numeri e spegnere, a occhi chiusi, proprio le campagne che ti portano i clienti.
Step 2, LEFT JOIN sulla tabella lead di Meta
Adesso la domanda da fare al database. La spezzo in tre pezzi, così ognuno fa una cosa sola e si capisce. Il primo pezzo prende i contatti di Meta e gli passa la pulizia (minuscolo, via gli spazi). Il secondo fa lo stesso con i clienti del gestionale, tenendo solo quelli toccati nel periodo che stai guardando. Il terzo mette le due liste una accanto all'altra appaiandole sulla mail pulita, le raggruppa per campagna, e tira fuori sette numeri per ognuna. Ti dico cosa sono questi sette numeri, perché sono quelli che decidono dove vanno i tuoi soldi il lunedì dopo.
I sette numeri:
- Contatti totali: quanti nomi ti ha portato quella campagna.
- Quanto hai speso per quella campagna.
- Contatti fantasma: quelli che Meta ha raccolto ma nel gestionale non sono mai arrivati. Se sono più del 30%, hai una falla nel tracciamento e te ne devi accorgere subito.
- Clienti che hanno firmato (nel gestionale la trattativa è segnata come vinta,
deal stage = 'won'). - Fatturato che quei clienti ti hanno portato.
- Quanto ti è costato ogni cliente vero (la spesa divisa per i clienti firmati; uso
SAFE_DIVIDE, una divisione "sicura" che non manda in tilt il conto quando i clienti sono zero). - Quanti contatti diventano clienti (clienti firmati diviso contatti totali; sotto il 5% nel B2B suona il campanello).
Qui c'è una scelta che pesa, e va spiegata. Quando incolli due liste, hai due modi. Uno tiene tutti i contatti di Meta, anche i fantasma che nel gestionale non si trovano (in gergo, LEFT JOIN). L'altro tiene solo quelli che combaciano in tutte e due le liste e butta via il resto (INNER JOIN). Io tengo tutti. Voglio vedere anche i fantasma, perché quei fantasma sono un'informazione: o si è rotto qualcosa nel tracciamento, o erano contatti spazzatura che il gestionale ha buttato come spam. In tutti e due i casi voglio sapere quali campagne li sfornano e in che quantità, perché sono campagne da controllare prima ancora di pensare a metterci più soldi.
L'errore che vedo fare di continuo a chi è alle prime armi è usare quello che butta via i fantasma per i report di marketing. Cosa succede? Tutti i contatti spariti dal gestionale spariscono anche dal conto. Il costo per cliente diventa bellissimo, perché la spazzatura è evaporata. Bellissimo finché, un mese dopo, qualcuno in riunione chiede: "ma se i contatti veri erano pochi, perché su quella campagna abbiamo buttato così tanto?". A quel punto la verità salta fuori. E il budget è già bruciato.
Step 3, leggere il risultato come fa un growth
La tabella che esce non si legge partendo dal costo del contatto. Si legge partendo dal fatturato, dalla riga che porta più soldi giù in fondo al conto. Dentro ogni riga guardi due cose: quanto costa un cliente vero, e quanti contatti diventano clienti. Quei due numeri ti dicono dove spingere e dove frenare. Tutto il resto è rumore.
Tre regole pratiche che applico subito, riga per riga:
- Se un cliente ti costa più di un terzo di quello che ti lascia in tutta la sua vita (costo per cliente sopra LTV medio diviso 3), quella campagna ti mangia il margine: la spegni o le rifai daccapo l'immagine e il messaggio.
- Se diventa cliente meno del 5% dei contatti nel B2B (meno del 2% se vendi diretto al consumatore), stai pescando gente sbagliata: guardi a chi stai parlando prima di metterci più budget.
- Se più del 30% dei contatti sono fantasma e nel gestionale non si trovano, hai una falla nel tracciamento: la chiudi prima di decidere qualunque altra cosa, perché finché perde acqua ogni conto è zoppo.
Tre regole, tre soglie, tre decisioni. Scordati le dashboard piene di grafici che nessuno guarda. Basta un foglio Google con dentro il risultato e tre formule che colorano le righe da sole. Verde, spingi. Giallo, tieni d'occhio. Rosso, spegni. Lo fai il lunedì alle 8, prima della call delle 9. E alla call cambia tutto. Smetti di dire "allora, vediamo i numeri" e dici "spegniamo questi due, su questo raddoppiamo, quest'altro lo teniamo sotto osservazione". Stesso cliente, stessi dati. Un altro peso.
Esempio applicato a un caso reale
Un'azienda che vende software per le risorse umane, mondo B2B. Tre campagne sullo stesso pubblico freddo, stessa immagine, tre messaggi diversi: una puntava sul far risparmiare tempo, una sul mettersi in regola con le norme, una sul crescere. Periodo: 60 giorni, marzo e aprile 2026. Sul piatto, 14.700 euro.
Quello che diceva Meta. Campagna 1 (risparmio di tempo): 165 contatti, 22 euro l'uno. Campagna 2 (regole): 89 contatti, 31 euro l'uno. Campagna 3 (crescita): 121 contatti, 26 euro l'uno. Lettura a colpo d'occhio: la 1 vince, la 2 perde. L'imprenditore voleva spegnere la 2 e raddoppiare sulla 1. Logico. Sbagliato.
Quello che è uscito dopo aver incollato i contatti accanto ai clienti veri (il gestionale era HubSpot, allineato ogni 15 minuti con Make):
| Campagna | Lead | CPL | Clienti | Lead→Client | Cost / Client |
|---|---|---|---|---|---|
| 1 · Efficiency | 165 | 22 € | 4 | 2,4% | 907 € |
| 2 · Compliance | 89 | 31 € | 11 | 12,4% | 251 € |
| 3 · Growth | 121 | 26 € | 6 | 5,0% | 524 € |
Guarda l'ultima colonna e poi torna su a quello che voleva fare l'imprenditore. La campagna 2, quella da spegnere, era la più redditizia di tutte, e di parecchio. La campagna 1, quella su cui voleva raddoppiare, raccoglieva curiosi che si fermavano al PDF e buonanotte. Abbiamo triplicato il budget sulla 2 e spento la 1. Tre mesi dopo, il fatturato per ogni euro speso su Meta era passato da 2,8 a 4,1. Nessuna immagine nuova, nessun trucco. Solo aver guardato il numero giusto invece dell'ombra sulla parete.
Errori comuni e come evitarli
JOIN su email non normalizzate
Da qui nasce il 30% dei contatti che si perdono. La stessa mail scritta con una maiuscola diversa, o con uno spazio dimenticato in fondo, per il database sono due persone diverse. Tu vedi Mario, lui vede due Mario. La pulizia prima di appaiare (tutto minuscolo, via gli spazi) non è facoltativa. Su BigQuery la scrivi LOWER(TRIM(email)), su Postgres uguale, su MySQL pure. Tre parole di codice in più. Il 30% dei tuoi contatti che torna a casa.
Confondere INNER e LEFT JOIN
Se il tuo report tiene solo i contatti che combaciano e butta i fantasma (INNER JOIN), succede una cosa subdola. Tutti i contatti spariti dal gestionale spariscono anche dal conto. In apparenza: costo per cliente da sogno, la spazzatura è evaporata. In realtà: stai decidendo su una fetta filtrata di dati, e non sai nemmeno con che regola è stata filtrata. La scelta sicura per il marketing è tenere tutti i contatti di Meta, fantasma compresi.
Duplicati silenziosi
Se nel gestionale la stessa persona ha tre schede (una trattativa aperta, una persa, una vinta), quando appai le liste quel contatto viene contato tre volte. Il segnale che qualcosa non torna: dopo aver incollato le liste hai più contatti di quanti ne avesse Meta all'inizio. Impossibile, eppure è lì. La soluzione è togliere i doppioni prima di appaiare, tenendo solo la scheda più recente di ogni persona, con ROW_NUMBER() OVER (PARTITION BY email_norm ORDER BY closed_at DESC).
SAFE_DIVIDE dimenticato
Una campagna con zero clienti firmati e una divisione spend / clients_won ti chiede di dividere per zero. A scuola era proibito, e anche qui. Su BigQuery la domanda si rompe, su Postgres dà errore, su MySQL ti restituisce un vuoto silenzioso senza dirti niente (il peggiore dei tre, perché non te ne accorgi). La divisione sicura, quella che al posto dello schianto mette uno zero, ti salva. Una riga di codice in più, contro ore passate a cercare dove sta il guasto.
Filtri WHERE dopo il LEFT JOIN
Questo è il più infido. Hai fatto tutto giusto, hai tenuto i fantasma, e poi in fondo aggiungi un filtro tipo WHERE c.deal_stage = 'won' per vedere solo chi ha firmato. Senza saperlo, hai appena buttato via tutti i fantasma che volevi tenere, perché il filtro li scarta in automatico. Hai trasformato la scelta sicura in quella pericolosa con una riga sola. Per evitarlo, sposti il filtro dentro la regola di appaiamento (la clausola ON), oppure conti i firmati con COUNTIF(c.deal_stage = 'won') senza scartare niente prima. La regola da portarti a casa è una: dopo aver appaiato le liste, ogni filtro che metti può rimangiarsi il lavoro fatto. Controlla sempre quanti contatti ti restano in mano prima e dopo. Se il numero crolla, sai dove guardare.
Domande frequenti su SQL JOIN per il marketing
Perché il CPL non basta per giudicare una campagna B2B?
Il CPL misura quanto costa generare un lead, non quanto vale. Nel B2B i lead hanno qualità molto diversa: alcuni firmano, altri spariscono dopo aver scaricato un PDF. Il numero che conta è il costo per cliente acquisito, che si calcola solo unendo i dati di Meta Ads con i dati del CRM via SQL JOIN. Senza quel JOIN, il CPL è una vanity metric che racconta metà della storia.
Cosa significa identity stitching nel marketing?
Il processo di assicurarsi che la stessa persona compaia con la stessa identità in tutti i sistemi: stessa email, normalizzata identicamente (lowercase, trim), dal pixel di tracking al form al CRM. Senza identity stitching, il match rate tra Meta Ads e CRM scende sotto il 60% e ogni analisi successiva è basata su un campione storto.
Quando usare LEFT JOIN invece di INNER JOIN nei report marketing?
LEFT JOIN è il default sicuro. Mantiene tutti i lead generati da Meta Ads, anche quelli non presenti nel CRM. I lead orfani sono di per sé un'informazione preziosa: indicano problemi di tracking o lead spazzatura. INNER JOIN esclude automaticamente i lead non matchati, facendo sembrare il CAC più basso e nascondendo i problemi di qualità.
Quanto tempo serve per impostare il primo JOIN tra Meta Ads e CRM?
Il setup tecnico richiede 4-6 ore la prima volta: export Meta Ads via Supermetrics o API in BigQuery (1h), sync CRM via Zapier o Make (1-2h), scrittura della query con CTE e SAFE_DIVIDE (1h), validazione e check del match rate (1-2h). Una volta impostato, gira automaticamente ogni notte.
Cosa fare se il match rate tra Meta e CRM è sotto il 60%?
Prima di analizzare le campagne va sistemato il setup di tracking. I controlli da fare in ordine: la normalizzazione delle email lato Meta CAPI (lowercase + trim), la stessa lato form, la stessa lato CRM. Senza fixare questo passaggio, ogni analisi è zoppa e va rimandata.
Quale strumento usare per scrivere queste query in produzione?
BigQuery è il default per chi gestisce dati di marketing: 5 dollari per TB scansionato, ma per i volumi tipici di un'agenzia o PMI si vive nel free tier. Per scrivere query interattivamente, DBeaver è gratuito. Hex è a pagamento (99 dollari al mese) ma vale i suoi soldi in team grazie a notebook collaborativi e schedulazione integrata.


