SteerAds
Google AdsTutorielOptimisation

IA Parole chiave negative: discovery e clustering

L'analisi manuale di un search query report manca dal 60 all'80% dei negativi nascosti. Ecco una pipeline IA riproducibile: embeddings OpenAI o sentence-transformers, clustering DBSCAN, scoring intent + cost wasted, export CSV per Google Ads Editor. Repo Python open-source in bonus.

Andrew
AndrewSmart Bidding & Automation Lead
ยทยทยท9 min di lettura

Sugli account osservati nei benchmark Google Ads pubblici, l'analisi manuale di un search query report manca dal 60 all'80% dei negativi nascosti dopo 30 minuti di eyeballing da parte di un PPC manager esperto. E il costo di questo miss e misurabile: dal 14 al 28% dello spend mensile finisce in query non pertinenti che nessuno vedra nel top 50 degli SQR (documentazione ufficiale Google Ads sui negativi). E tipicamente la leva trascurata che penalizza il rapporto CPA / Quality Score di un account maturo.

Ecco la diagnostica: un umano che scansiona un SQR fa pattern matching visivo sulle prime 200-500 righe ordinate per cost. Manca (1) le query della coda lunga che pesano solo da 3 a 8 EUR ciascuna ma che cumulate rappresentano dal 18 al 26% dello spend, (2) le variazioni semantiche raggruppabili ('recensione', 'review', 'opinione', 'testimonianza', 'feedback' = stesso intent), e (3) i cluster di query fuori-intent commerciale (lavoro, formazione gratuita, definizione, prezzo basso low-end) che l'algoritmo Smart Bidding non identifica se il tracking conversione e a valore fisso.

Questa guida fornisce la pipeline IA riproducibile: estrazione GAQL del SQR, embeddings (OpenAI o sentence-transformers), clustering DBSCAN, scoring intent + cost wasted, export CSV per Google Ads Editor. Tutto il codice e in Python, funziona in locale, e il repo pubblico github.com/steerads/google-ads-negatives-ai contiene un Dockerfile e un workflow n8n d'esempio. Per le fondamenta match type che condizionano questa pipeline, consultate la nostra guida match types 2026. Il nostro calcolatore di spreco budget stima gli EUR bruciati/mese per broad senza negativi o bounce LP eccessivo.

Il problema: dal 60 all'80% dei negativi nascosti nell'analisi manuale

L'analisi manuale di un search query report (SQR) e uno dei task piu dispendiosi in termini di tempo per il PPC manager. Su un account medio (da 5.000 a 15.000 query / 30 giorni), bisogna contare da 45 minuti a 2 ore per fare un passaggio corretto. E anche con questo tempo investito, il tasso di rilevamento dei negativi pertinenti resta strutturalmente limitato dalla fatica cognitiva e dall'ordinamento per cost decrescente.

Tre angoli ciechi sistematici nell'analisi manuale:

  1. La coda lunga e invisibile. Le prime 50 query ordinate per cost concentrano dal 35 al 50% dello spend. Il PPC manager le vede. Ma le 4.950 query restanti โ€” ciascuna da 1 a 8 EUR โ€” concentrano dal 50 al 65% dello spend totale e restano inesplorate. E in questa coda che si nascondono i pattern ricorrenti non pertinenti.
  2. Il pattern matching visivo manca le variazioni semantiche. Un umano identifica 'recensione' come candidato negativo. Ma 'review', 'opinione', 'testimonianza', 'feedback' condividono lo stesso intent e appaiono in query diverse. Senza embedding, impossibile raggruppare.
  3. Nessuno scoring del cost wasted. Una query a 25 EUR cost / 0 conversioni su 30 giorni e piu impattante di una query a 4 EUR cost / 0 conversioni โ€” anche se la seconda appare 6 volte piu spesso. L'umano ordina per alfabeto o cost bruto, raramente per cost wasted (cost / conversioni).
Insight โ€” rapporto negativi / spend :

Sugli account osservati nei benchmark Google Ads pubblici, il rapporto di spend recuperabile via clustering IA dei negativi converge verso una soglia molto riproducibile: dal 12 al 22% dello spend mensile dopo 60 giorni di pipeline attiva. Su un budget di 30.000 EUR/mese, sono tra 3.600 e 6.600 EUR di spend recuperato ogni mese โ€” non verso i concorrenti, ma reinettato nelle query che convertono. Il ROI vs tempo PPC manager risparmiato e superiore a 25x per la maggioranza degli account trattati.

La pipeline IA descritta qui sostituisce il passaggio manuale con un workflow riproducibile. La prima esecuzione richiede da 30 a 45 minuti (setup + run + review). Le esecuzioni successive richiedono da 5 a 15 minuti (review del sample unicamente). Per la base di audit che deve precedere questa automazione, leggete la nostra checklist di audit Google Ads.

Pipeline IA in 5 step: dal query report alla lista negativi

La pipeline completa concatena 5 step deterministici, ciascuno testabile in isolamento. Architettura volutamente semplice, nessuna dipendenza ML pesante oltre scikit-learn e sentence-transformers / openai. L'output finale e un CSV direttamente importabile in Google Ads Editor.

Pre-processing delle search query: lo step che si salta troppo spesso

Prima di embeddare qualsiasi cosa, il pre-processing del SQR condiziona dal 30 al 50% della qualita finale del clustering. Quattro trasformazioni da applicare sistematicamente. Primo step: normalizzazione Unicode e case. I SQR Google Ads contengono spesso duplicati fantasma: 'Preventivo Assicurazione', 'preventivo assicurazione', 'preventivo assicurazione' (doppio spazio), 'preventivo-assicurazione' appaiono come 4 query distinte mentre rappresentano la stessa cosa. Applicare unicodedata.normalize('NFKC', s).strip().lower() piu una regex \s+ -> ' ' riunisce questi duplicati in una riga unica con cost e clicks aggregati. Su un account FR medio, questo step riduce il volume di query dall'8 al 14% senza perdita di informazione.

Secondo step: deduplicazione intelligente. Oltre alla normalizzazione semplice, la deduplicazione deve trattare le varianti morfologiche (singolare/plurale, maschile/femminile, accenti) secondo il bisogno. Per il clustering, mantenere le varianti grezze e generalmente piu utile (l'embedding le raggruppera meccanicamente), ma per l'export negativo finale, deduplicare sul representative_query del cluster evita di proporre 5 volte lo stesso negativo. Terzo step: filtraggio delle query one-shot a basso cost. Una query che appare una sola volta su 30 giorni con 1,20 EUR di cost non merita embedding (e puro rumore). Filtrare a monte su clicks >= 1 AND cost >= 1 evita di inquinare il clustering con il 25-40% di rumore irriducibile.

Quarto step: rilevamento PII e termini sensibili. Alcune query contengono numeri di telefono, email, o nomi propri di utenti (digitati per errore nella barra di ricerca invece dell'URL). Queste query non hanno alcun interesse di analisi e il loro trattamento via OpenAI porrebbe problemi GDPR. Filtrare a monte via regex e non inviare MAI a un'API esterna. Sui dati Google Ads aggregati 2025-2026, questo tipo di query rappresenta dallo 0,3 all'1,2% del SQR โ€” basso in volume ma critico in compliance.

[Google Ads API / CSV export]
    |
    v  Step 1 โ€” estrazione SQR (GAQL o CSV)
[search_terms.csv : query, clicks, cost, conv]
    |
    v  Step 2 โ€” embeddings (OpenAI o ST)
[embeddings.npy : matrice 384/1536 dim]
    |
    v  Step 3 โ€” clustering DBSCAN o HDBSCAN
[queries_clustered.csv : query, cluster_id]
    |
    v  Step 4 โ€” scoring intent + cost wasted
[clusters_scored.csv : cluster, waste_score, intent_score]
    |
    v  Step 5 โ€” filtraggio + match type + export
[negatives_export.csv : pronto per Google Ads Editor]

Ecco lo scheletro Python del runner principale. Il codice completo (con gestione errori, log, parametri CLI) e nel repo pubblico.

# main.py โ€” pipeline completa in 5 step
import pandas as pd
import numpy as np
from embeddings import embed_queries
from clustering import cluster_dbscan
from scoring import score_clusters
from export import export_negatives_csv

def main(sqr_path: str, output_path: str, backend: str = "sentence-transformers"):
    # Step 1 โ€” caricamento SQR
    df = pd.read_csv(sqr_path)
    df = df[df["clicks"] >= 1]  # filtrare le query senza clic
    print(f"Loaded {len(df)} queries")

    # Step 2 โ€” embeddings
    embeddings = embed_queries(df["search_term"].tolist(), backend=backend)
    print(f"Embeddings shape: {embeddings.shape}")

    # Step 3 โ€” clustering
    df["cluster_id"] = cluster_dbscan(embeddings, eps=0.15, min_samples=5)
    n_clusters = df["cluster_id"].nunique() - (1 if -1 in df["cluster_id"].values else 0)
    print(f"Found {n_clusters} clusters")

    # Step 4 โ€” scoring
    clusters_scored = score_clusters(df, whitelist_path="whitelist.txt")

    # Step 5 โ€” export
    export_negatives_csv(clusters_scored, output_path,
                         min_cluster_size=3, min_waste_score=30)
    print(f"Exported negatives to {output_path}")

if __name__ == "__main__":
    main(
        sqr_path="data/search_terms.csv",
        output_path="output/negatives_export.csv",
        backend="sentence-transformers",  # o "openai"
    )

Ogni step produce un artefatto persistente (CSV o .npy). Questo facilita il debug: se il clustering produce troppo rumore, si puo iterare sullo step 3 senza rilanciare gli embeddings (costosi in API call). Cf. la nostra guida automazione Google Ads API Python per il setup OAuth e l'estrazione GAQL dettagliata.

Embeddings: OpenAI text-embedding-3 vs sentence-transformers

L'embedding e lo step critico. Una query vettorizzata permette di misurare la similarita semantica tra 'preventivo assicurazione auto' e 'tariffa assicurazione veicolo' โ€” anche se zero parole in comune. Senza embedding, il clustering ricade sul matching di token e manca il 70% dei raggruppamenti pertinenti.

Due backend pertinenti nel 2026: OpenAI text-embedding-3-small (hosted, 1536 dim, a pagamento) e sentence-transformers all-MiniLM-L6-v2 o multilingual-e5-base (locale, 384 o 768 dim, gratuito). La scelta dipende dal volume e dalla sensibilita dei dati.

Variante OpenAI โ€” production-ready, batch ottimizzato:

# embeddings.py โ€” backend OpenAI
from openai import OpenAI
import numpy as np
import os

def embed_queries_openai(queries: list[str], batch_size: int = 100) -> np.ndarray:
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
    all_embeddings = []

    for i in range(0, len(queries), batch_size):
        batch = queries[i : i + batch_size]
        response = client.embeddings.create(
            model="text-embedding-3-small",
            input=batch,
            encoding_format="float",
        )
        embeddings = [item.embedding for item in response.data]
        all_embeddings.extend(embeddings)

    return np.array(all_embeddings, dtype=np.float32)

Variante sentence-transformers โ€” locale, zero costi:

# embeddings.py โ€” backend locale sentence-transformers
from sentence_transformers import SentenceTransformer
import numpy as np

def embed_queries_st(queries: list[str], model_name: str = "all-MiniLM-L6-v2") -> np.ndarray:
    model = SentenceTransformer(model_name)
    embeddings = model.encode(
        queries,
        batch_size=64,
        show_progress_bar=True,
        normalize_embeddings=True,  # importante per cosine
    )
    return embeddings.astype(np.float32)


def embed_queries(queries: list[str], backend: str = "sentence-transformers") -> np.ndarray:
    if backend == "openai":
        return embed_queries_openai(queries)
    elif backend == "sentence-transformers":
        return embed_queries_st(queries, model_name="paraphrase-multilingual-MiniLM-L12-v2")
    else:
        raise ValueError(f"Unknown backend: {backend}")

Riferimento sul campo: su un account FR e-commerce di 8.000 query, il delta di qualita cluster tra OpenAI ed e5-base resta intorno al 6-9% in precisione (misura: nb negativi validi / nb proposte). In MiniLM v1 anglosassone, il delta sale al 12-18% โ€” da cui la scelta paraphrase-multilingual-MiniLM-L12-v2 per il FR. Per un account 100% francofono, e il miglior compromesso costo / qualita. Documentazione ufficiale OpenAI embeddings.

text-embedding-3-large vs text-embedding-3-small: quando il large vale il sovracosto? Tre casi concreti in cui text-embedding-3-large (3072 dim, 0,13 USD / 1M token, cioe 6,5x piu costoso di small) giustifica l'investimento. Caso 1: intent fine su settori tecnici specializzati (medico, giuridico, ingegneria) dove la sfumatura tra 'avvocato fiscalista' e 'avvocato fiscale' cambia lo scoring intent. Il large cattura dal 4 al 7% di precisione supplementare misurabile sulla coorte di validazione. Caso 2: multilingue misto (FR + EN + ES nello stesso account) dove la robustezza cross-lingua del large evita di splittare la pipeline in tre passaggi distinti. Caso 3: volume molto elevato (50.000+ query al mese) dove il costo marginale aggiuntivo resta sotto 1 EUR per run e senza impatto significativo sul P&L. Al di fuori di questi tre casi, text-embedding-3-small resta il buon default per un account FR mid-market.

Analisi di costo API OpenAI su un caso reale. Per un account che tratta 8.000 query di 4-8 parole ogni settimana (in media 32 token per query, quindi 256.000 token per run), il costo del run in small e di 256.000 / 1.000.000 x 0,02 USD = 0,005 USD. Su 52 run annuali, cioe circa 0,27 USD per account per anno. In large, il costo diventa 256.000 / 1.000.000 x 0,13 USD = 0,033 USD per run, cioe circa 1,72 USD annuali. In entrambi i casi, il costo API OpenAI e marginale rispetto al tempo PPC manager risparmiato. La trappola classica: far girare senza batching (1 query per chiamata invece di 100 per batch), il che moltiplica il costo per 8-12 a causa della ripetizione dei costi fissi per richiesta. Sempre batchare almeno a 50-100 query per chiamata.

Clustering DBSCAN: perche non K-means

K-means e l'algoritmo di clustering piu conosciuto, ma e la scelta sbagliata per le search query Google Ads. Tre ragioni tecniche:

  1. K-means esige di fissare K in anticipo. Quanti cluster di query non pertinenti esistono nel vostro account? Nessuno lo sa prima dell'analisi. K-means forza a indovinare โ€” e un K sbagliato produce sia cluster troppo ampi (stessi intent mescolati) sia troppo fini (sovra-frammentazione).
  2. K-means assegna tutti i punti a un cluster. Eppure dal 30 al 50% delle query sono rumore (query uniche senza equivalente). DBSCAN le identifica come rumore (cluster -1) invece di forzarle in un cluster fittizio. Risultato: cluster piu netti.
  3. K-means assume cluster sferici di stessa densita. I cluster di query non pertinenti hanno densita molto variabili (un cluster 'gratuito' molto denso + un cluster 'confronto concorrente' diffuso). DBSCAN gestisce questa varianza, K-means no.

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) prende due parametri: eps (raggio di vicinato) e min_samples (nb min di punti per formare un cluster). Identifica le zone dense nello spazio degli embeddings e raggruppa i punti vicini.

# clustering.py โ€” DBSCAN
from sklearn.cluster import DBSCAN
import numpy as np

def cluster_dbscan(embeddings: np.ndarray, eps: float = 0.15, min_samples: int = 5) -> np.ndarray:
    # Cosine distance per embeddings normalizzati
    clustering = DBSCAN(
        eps=eps,
        min_samples=min_samples,
        metric="cosine",
        n_jobs=-1,
    )
    labels = clustering.fit_predict(embeddings)
    return labels


def cluster_hdbscan(embeddings: np.ndarray, min_cluster_size: int = 5) -> np.ndarray:
    import hdbscan
    clustering = hdbscan.HDBSCAN(
        min_cluster_size=min_cluster_size,
        metric="euclidean",  # HDBSCAN non supporta cosine direttamente
        cluster_selection_method="eom",
    )
    labels = clustering.fit_predict(embeddings)
    return labels

Calibrazione del parametro eps: e la soglia di similarita coseno sotto la quale due query sono considerate come vicine. Piu eps e piccolo, piu i cluster sono fini. Riferimento sul campo: iniziare a eps=0.15. Se piu del 70% delle query esce come rumore (cluster -1), salire a 0.20. Se i cluster sono troppo ampi (cluster 'servizio' che mescola B2B e B2C), scendere a 0.12.

HDBSCAN come alternativa, se DBSCAN produce cluster mal calibrati. HDBSCAN auto-rileva la densita locale e non ha bisogno di eps. Piu robusto su dataset eterogenei ma piu lento e piu complesso da debuggare.

Tip โ€” visualizzare i cluster prima di assegnare punteggi :

Prima di passare allo scoring, visualizzate i cluster ottenuti con UMAP in 2D. umap-learn riduce gli embeddings da 384 dim a 2 dim per uno scatter plot leggibile. Vedete istantaneamente se il clustering e pulito (cluster netti e separati) o rumoroso (cluster che si sovrappongono). Se rumoroso, aggiustate eps prima di continuare. 5 minuti investiti evitano 30 minuti di scoring inutile.

Validazione dei cluster: tre metriche oltre il visivo UMAP

La visualizzazione UMAP e utile ma soggettiva. Per validare quantitativamente la qualita del clustering, tre metriche oggettive da calcolare sistematicamente prima di passare allo scoring. Metrica 1: silhouette score. Implementata in sklearn.metrics.silhouette_score, questa metrica misura quanto ogni punto e piu vicino al proprio cluster che agli altri cluster. Score tra -1 (catastrofico) e +1 (perfetto). Un silhouette superiore a 0,3 sul dataset completo indica un clustering sfruttabile; sotto 0,15, bisogna ri-tunare eps. Sugli account osservati nei benchmark Google Ads pubblici, un account FR e-commerce mid-size raggiunge tipicamente da 0,32 a 0,48 di silhouette in sentence-transformers e da 0,38 a 0,55 in OpenAI text-embedding-3-small.

Metrica 2: percentuale di rumore. Contare il rapporto (labels == -1).mean(). Un buon clustering DBSCAN su SQR Google Ads dovrebbe avere tra il 25 e il 45% di rumore (query non assegnate a un cluster). Sotto il 25%, eps e troppo ampio e i cluster sono sovra-fusi. Sopra il 60%, eps e troppo stretto e la maggioranza delle query viene rifiutata. Questa metrica e gratuita da calcolare e serve da guardrail per evitare configurazioni degenerative.

Metrica 3: dimensione mediana dei cluster. Calcolare np.median([size for _, size in clusters_size]). Un clustering sfruttabile produce cluster di dimensione mediana tra 4 e 12 query. Sopra 20, i cluster sono troppo ampi e mescolano intent diversi. Sotto 4, sono troppo fini e lo scoring diventa instabile. Se la dimensione mediana e fuori da questa finestra, aggiustare min_samples (DBSCAN) o min_cluster_size (HDBSCAN) prima di continuare la pipeline. Nelle iterazioni di produzione, monitorare queste tre metriche e loggare la loro deriva permette di rilevare le regressioni silenziose della pipeline (un cambiamento di API embedding, un drift nelle query sorgente) prima che i negativi proposti ne siano impattati.

Scoring: pertinenza intent + cost wasted

Una volta le query clusterizzate, bisogna assegnare un punteggio a ogni cluster per decidere quali sono candidati negativi. Lo scoring combina due dimensioni: (1) il cost wasted (quanto spend e stato bruciato senza conversione) e (2) l'intent score (quanto il cluster e lontano dal vostro intent commerciale target).

Cost wasted e banale da calcolare: somma del cost / max(somma conversioni, 0.1) per cluster. Piu il rapporto e alto, piu il cluster e candidato negativo.

Intent score e piu sottile. Si confronta la similarita coseno media del cluster con una whitelist di keyword target (le vostre keyword brand + prodotti di punta + intenzioni d'acquisto forti). Se la similarita media del cluster con la whitelist e superiore a 0.65, e probabilmente un cluster pertinente (da NON escludere). Se inferiore a 0.30, e un cluster lontano dall'intent commerciale = candidato negativo forte.

# scoring.py โ€” scoring intent + cost wasted
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

def score_clusters(df: pd.DataFrame, whitelist_path: str) -> pd.DataFrame:
    # Caricare whitelist (1 keyword per riga)
    with open(whitelist_path) as f:
        whitelist_keywords = [line.strip() for line in f if line.strip()]

    # Embeddare la whitelist
    from embeddings import embed_queries
    whitelist_emb = embed_queries(whitelist_keywords, backend="sentence-transformers")

    # Aggregare per cluster
    cluster_stats = []

    for cluster_id, group in df.groupby("cluster_id"):
        if cluster_id == -1:
            continue  # ignorare il rumore

        cost = group["cost"].sum()
        conv = group["conversions"].sum()
        clicks = group["clicks"].sum()
        size = len(group)

        # waste_score : costo per conversione (0.1 floor per evitare divisione per 0)
        waste_score = cost / max(conv, 0.1)

        # intent_score : similarita coseno media con whitelist
        cluster_emb = np.stack(group["embedding"].values)
        sim_matrix = cosine_similarity(cluster_emb, whitelist_emb)
        intent_score = float(sim_matrix.max(axis=1).mean())

        # esempio rappresentativo (query piu centrale del cluster)
        centroid = cluster_emb.mean(axis=0)
        distances = np.linalg.norm(cluster_emb - centroid, axis=1)
        representative_idx = distances.argmin()
        representative_query = group.iloc[representative_idx]["search_term"]

        cluster_stats.append({
            "cluster_id": cluster_id,
            "size": size,
            "cost": round(cost, 2),
            "conversions": round(conv, 2),
            "clicks": clicks,
            "waste_score": round(waste_score, 2),
            "intent_score": round(intent_score, 3),
            "representative_query": representative_query,
            "negative_candidate": waste_score > 30 and intent_score < 0.30,
        })

    result = pd.DataFrame(cluster_stats)
    return result.sort_values("waste_score", ascending=False)

Lettura della tabella di output: si ordina per waste_score decrescente, poi si filtra su intent_score < 0.30 E size >= 3. Questo trio identifica i cluster che (1) bruciano spend, (2) sono lontani dall'intent commerciale, e (3) hanno abbastanza query per valere un negativo (non un one-shot).

Riferimento delle soglie:

  • waste_score >= 30 (almeno 30 EUR di cost senza conversione) โ€” corrisponde alla soglia di pertinenza sulla maggioranza degli account.
  • intent_score < 0.30 (similarita coseno con whitelist sotto il 30%) โ€” sopra, rischio di falso negativo.
  • size >= 3 (almeno 3 query nel cluster) โ€” sotto 3, e rumore o coda lunga, trattare caso per caso.

Queste soglie sono punti di partenza. Aggiustate secondo i vostri ritorni di sample manuale dopo 2-3 iterazioni.

Export CSV pronto per Google Ads Editor

L'output finale deve essere direttamente importabile in Google Ads Editor โ€” altrimenti perdete 30 minuti a riformattare manualmente. Formato atteso: CSV UTF-8, colonne specifiche, match type chiaro, azione esplicita ("Add" per aggiunta).

# export.py โ€” generazione CSV Google Ads Editor
import pandas as pd

def export_negatives_csv(
    clusters_scored: pd.DataFrame,
    output_path: str,
    min_cluster_size: int = 3,
    min_waste_score: float = 30,
    max_intent_score: float = 0.30,
) -> None:
    # Filtrare i cluster candidati
    candidates = clusters_scored[
        (clusters_scored["size"] >= min_cluster_size)
        & (clusters_scored["waste_score"] >= min_waste_score)
        & (clusters_scored["intent_score"] < max_intent_score)
    ]

    rows = []
    for _, cluster in candidates.iterrows():
        # Determinare match type secondo la dispersione del cluster
        # (da parametrizzare piu finemente in prod : qui semplificazione)
        match_type = "Phrase match" if cluster["size"] <= 8 else "Broad match"

        rows.append({
            "Action": "Add",
            "Campaign": "ALL",  # o cluster["campaign"] se disponibile
            "Ad group": "",  # vuoto = livello campagna
            "Keyword": cluster["representative_query"],
            "Match type": match_type,
            "Status": "Enabled",
            "Comment": f"AI cluster #{cluster['cluster_id']} | "
                       f"size={cluster['size']} | "
                       f"waste={cluster['waste_score']} EUR | "
                       f"intent={cluster['intent_score']}",
        })

    out_df = pd.DataFrame(rows)
    out_df.to_csv(output_path, index=False, encoding="utf-8")
    print(f"Wrote {len(out_df)} negative candidates to {output_path}")

Procedura di importazione in Google Ads Editor: Google Ads Editor > File > Import > From CSV. Lo strumento rileva le colonne, valida il formato match type, e propone un diff visuale prima del push. Revisionare il diff (sample 30-50 righe), validare, poi Post Changes. Per la documentazione ufficiale Google Ads Editor, consultate support.google.com/google-ads/answer/2475106.

Match type โ€” euristica sul campo:

  • Phrase match per i cluster molto omogenei (size 3-8 query, espressioni corte e simili). Match preciso, basso rischio di blocking accidentale di una query pertinente.
  • Broad match per i concetti ampi (size superiore a 15, query varie intorno allo stesso intent). Piu ampio, ma non dimenticare di monitorare dopo il push per rilevare blocking eccessivi.
  • Exact match raramente pertinente come negativo IA โ€” si trattano piuttosto concetti che query esatte.
Warning โ€” review obbligatoria prima dell'upload :

Non uploadare MAI il CSV direttamente senza review umana al primo run. Sample 30-50 righe casuali, verificare che nessun termine brand / prodotto di punta / keyword target appaia, validare il match type. Se piu del 10% del sample e falso positivo, aggiustare le soglie (min_waste_score piu alto, max_intent_score piu basso) e ri-runnare. Una volta pipeline validata su 2-3 iterazioni (tasso di errore sotto il 5%), automatizzabile in modalita auto.

ROI tipico: quanto spend si recupera

Domanda pratica: quanto rende questa pipeline IA vs l'analisi manuale? Risposta in numeri sul campo, misurata sugli account osservati nei benchmark Google Ads pubblici.

Lettura: la pipeline IA non e magica sulla precisione (un umano attento fa altrettanto bene). Il suo vantaggio e sul recall โ€” identifica dal 75 all'88% dei negativi pertinenti vs dal 20 al 35% per un umano in 30 minuti. E il tempo PPC manager passa da 30 min a 5-15 min per esecuzione dopo il setup iniziale. Il vero guadagno e cumulativo: su 12 mesi, sono da 4 a 6 ore di PPC manager risparmiate E dal 12 al 22% di spend meglio utilizzato.

Riferimento numerico: su un account di 30.000 EUR/mese, recuperare il 15% dello spend = 4.500 EUR/mese reindirizzati verso le query che convertono. A iso-CPA, sono 4.500 / CPA conversioni supplementari in bottom-funnel ogni mese. Su 12 mesi, sono tipicamente tra 230 e 380 conversioni addizionali, senza aumento di budget. Il ROI vs investimento iniziale (45 min di setup + chiave API embeddings) e superiore a 50x.

Il rapporto chiave: recall diviso per tempo investito. Per l'analisi manuale 2h, il rapporto e circa 0,25 (50% di recall / 2h). Per la pipeline IA, il rapporto e circa 6 (80% di recall / 0,2h dopo setup). E 24x piu efficiente sulla metrica che conta davvero โ€” quanto spend wasted si identifica per ora di PPC manager investita. E questo rapporto migliora ancora nel corso delle esecuzioni: alla 5a iterazione, il sample manuale si riduce a 15-25 negativi da revisionare (vs 60-80 al primo run), perche i pattern ricorrenti sono assorbiti dai cluster precedenti.

Misurazione pratica su 60 giorni: gli account che attivano la pipeline in modalita settimanale convergono verso uno steady-state dove la maggioranza dei nuovi negativi proviene da pattern nuovi (concorrenti che salgono, query stagionali, evoluzioni semantiche dell'audience). La pipeline rileva queste novita in meno di 7 giorni dalla comparsa, vs 30-60 giorni in monitoraggio manuale โ€” cioe una finestra di 23-53 giorni risparmiata di spend wasted su ogni pattern emergente. E il vero vantaggio dell'automazione embedding-based: la velocita di reazione, non solo il recall puntuale.

Il nostro motore di auto-ottimizzazione integra questa pipeline in modalita gestita: estrazione GAQL automatica, embeddings hosted, clustering DBSCAN, scoring + filtraggio, e proposte settimanali validabili in 1 clic. Per gli account che vogliono industrializzare senza programmare. Consultate anche la nostra guida 10 script Google Ads per l'automazione lato script nativi, e la nostra guida n8n + Google Ads per schedulare la pipeline in workflow self-hosted. Le complementarieta tra questi tre angoli โ€” pipeline IA, script nativi, n8n self-hosted โ€” sono dettagliate nella nostra collezione di prompt ChatGPT Google Ads.

Errori comuni da evitare nell'industrializzazione

Cinque errori tornano ricorrenti nella messa in produzione di pipeline IA negativi Google Ads. Ciascuno crea sia falsi negativi (negativi mal mirati che bloccano traffico pertinente), sia falsi positivi (negativi mancati). Diagnostica e correzione diretta.

1. Lanciare la pipeline senza whitelist brand e prodotti target. Diagnostica: la pipeline propone negativi che contengono i vostri termini brand o i nomi dei vostri prodotti di punta, perche questi sono mal differenziati semanticamente dalle query non pertinenti. Correzione: mantenere una whitelist whitelist.txt con come minimo le varianti brand (parole semplici + composte), 10-20 nomi di prodotti target, e i termini commerciali forti. Questa whitelist serve allo scoring intent (intent_score) e blocca l'export di qualsiasi cluster il cui representative_query matcha parzialmente la whitelist.

2. Confondere exact match e phrase match nell'export negativo. Diagnostica: esportare un cluster in exact match sul representative_query blocca unicamente la query esatta (10-15% del cluster), lasciando l'85-90% del cost wasted continuare. Correzione: usare phrase match come default per i cluster coerenti, e broad match per i concetti ampi. Testare prima del push interrogando il Keyword Planner sul negativo proposto: se il volume stimato e superiore a 5x il volume del cluster d'origine, il match type e troppo ampio.

3. Lanciare la pipeline troppo frequentemente e generare rumore. Diagnostica: una pipeline daily produce decine di proposte al giorno, di cui il 60-70% sono riformulazioni delle proposte precedenti. La fatica di validazione spinge il team a validare tutto senza review. Correzione: lanciare settimanalmente (lunedi mattina), non daily. La finestra di 7 giorni stabilizza i pattern ed evita decisioni premature su query one-shot. Per account ad altissima frequenza di evoluzione (forte stagionalita), passare a bi-settimanale al massimo, mai quotidiano.

4. Ignorare i cluster di piccola dimensione ma alto waste. Diagnostica: il filtro min_cluster_size: 3 esclude sistematicamente i cluster di 1-2 query che possono portare un waste elevato (una query a 80 EUR senza conversione, per esempio). Questi pattern isolati passano sotto il radar della pipeline. Correzione: aggiungere un secondo passaggio che propone le query individuali sopra waste_score = 60 indipendentemente dalla loro appartenenza a un cluster. Queste proposte individuali sono piu rischiose da auto-validare, quindi revisionare manualmente prima dell'export.

5. Non misurare la performance post-applicazione. Diagnostica: i negativi vengono uploadati, la pipeline gira in autopilot, ma nessuno verifica se il CPA e il ROAS migliorano realmente. Correzione: tracciare un indicatore di salute della pipeline: delta_cpa_30j_post_negativi (variazione CPA nei 30 giorni dopo il push di N negativi). Se la variazione e nulla o negativa, i negativi proposti erano marginali. Aggiustare le soglie min_waste_score e max_intent_score per mirare a cluster a impatto piu netto. Sugli account osservati nei benchmark Google Ads pubblici, il miglioramento misurabile appare tipicamente nelle prime 3-5 iterazioni poi si stabilizza.

Per gli account che vogliono industrializzare senza far girare la pipeline da soli, il nostro modulo Auto-ottimizzazione fa girare la pipeline embeddings + clustering ogni settimana sul vostro account, propone i negativi candidati validati via UI, e applica dopo review. Connessione OAuth in 2 minuti, prima analisi in 5 minuti. Repo pubblico github.com/steerads/google-ads-negatives-ai disponibile per chi preferisce il self-hosting, con Dockerfile e workflow n8n d'esempio.

Fonti

Fonti ufficiali consultate per questa guida:

FAQ

Bisogna necessariamente usare OpenAI o si puo restare 100% open-source?

Si puo restare 100% open-source. sentence-transformers (modello all-MiniLM-L6-v2 o multilingual-e5-base) gira in locale su CPU, senza chiave API ne costi, con una qualita sufficiente per clusterizzare search query. La differenza osservabile vs OpenAI text-embedding-3-small: -8 a -14% di precisione sui cluster fini (separare 'preventivo' commerciale vs 'preventivo' giuridico), ma +zero euro di costo API. Per account che trattano meno di 5.000 query/mese, sentence-transformers e sufficiente. Oltre, o se trattate multilingue con accenti, text-embedding-3-small ha un miglior rapporto qualita/sforzo. La pipeline supporta entrambi i backend tramite una variabile d'ambiente.

Quale volume minimo di search query perche il clustering sia affidabile?

Soglia pratica: 500 query minimo sulla finestra di analisi (tipicamente 30 giorni). Sotto, DBSCAN non ha abbastanza densita per identificare cluster stabili e la maggioranza delle query esce come rumore. Sweet spot: da 2.000 a 10.000 query su 30 giorni. Oltre 10.000, suddividete per campagna per evitare di mescolare intent troppo diversi (B2B + B2C nello stesso clustering = rumore). Se il vostro account fa meno di 500 query/30g, estendete la finestra a 60 o 90 giorni.

DBSCAN o HDBSCAN: quale scegliere nella pratica?

HDBSCAN e generalmente superiore per le search query Google Ads: gestisce cluster di densita variabile, cosa che corrisponde alla realta (un cluster 'gratuito' molto denso + un cluster 'concorrente' diffuso). DBSCAN esige di fissare un parametro eps unico per tutto il dataset, il che forza dei compromessi. Tuttavia, DBSCAN resta piu semplice da parametrizzare e piu rapido su piccoli volumi (meno di 5.000 query). Raccomandazione: iniziare con DBSCAN con eps intorno a 0,15 e min_samples di 5, poi passare a HDBSCAN se i cluster sembrano mal calibrati. La pipeline supporta entrambi tramite una variabile di configurazione.

Come valutare la qualita dei negativi proposti dalla pipeline prima di uploadarli?

Tre check obbligatori prima di qualsiasi upload Google Ads Editor. (1) Sample manuale: revisionare da 30 a 50 negativi casuali, puntare a un tasso di validazione superiore al 90%. (2) Whitelist: verificare che nessun termine brand, prodotto di punta o keyword target appaia nella lista (lo script deve avere una whitelist in input). (3) Match type: verificare che il match type esportato corrisponda bene all'intenzione (phrase match per le espressioni esatte, broad match per i concetti). Se meno del 90% di validazione al sample manuale, aggiustare le soglie dello scoring (cost_min, cluster_size_min) invece di uploadare cosi com'e. Iterare 2-3 volte prima di puntare alla modalita auto.

Si puo automatizzare questa pipeline in esecuzione settimanale su n8n o Cloud Run?

Si, ed e l'obiettivo finale per industrializzare. La pipeline Python gira in meno di 3 minuti su 5.000 query (CPU locale) o in meno di 60 secondi via OpenAI batch embeddings + DBSCAN GPU. Potete schedularla in cron su Cloud Run, Lambda, o in workflow n8n. Pattern raccomandato: esecuzione settimanale (lunedi mattina), output in un Google Sheet condiviso, validazione umana del sample, upload via Google Ads Editor (o via Google Ads API direttamente se la fiducia nella pipeline e elevata). Il repo github.com/steerads/google-ads-negatives-ai include un Dockerfile e un esempio di workflow n8n.

Ready to optimize your campaigns?

Start a free audit in 2 minutes and discover the ROI potential of your accounts.

Start my free audit

Free audit โ€” no credit card required

Keep reading