Labelizer v4 — prodotti con periodo di tempo variabile
Ho aggiornato il Labelizer: ora puoi scegliere il periodo di analisi (7, 30, 60, 90 giorni) e classificare automaticamente i tuoi prodotti in 6 cluster di performance.
Cos'è il Labelizer?
Il Labelizer è uno strumento che uso per etichettare automaticamente i prodotti in base alle loro performance nelle campagne Shopping e Performance Max.
Con questa quarta versione ho aggiunto la possibilità di scegliere il periodo di analisi: puoi analizzare gli ultimi 7, 30, 60 o 90 giorni in base alle tue esigenze.
Come classifica i prodotti
Lo script divide i prodotti in sei categorie:
| Cluster | Criterio |
|---|---|
| Zero clic | Impressioni ma nessun click |
| Zero conversioni | Click ma nessuna conversione |
| Costoso | 100+ click con ROAS sotto obiettivo |
| Redditizio | 100+ click con ROAS sopra obiettivo |
| Partito bene | Meno di 100 click, ROAS sopra obiettivo |
| Partito male | Meno di 100 click, ROAS sotto obiettivo |
Come si usa, in tre passaggi
Tre passaggi:
- Copia il template dello sheet (link disponibile su richiesta)
- Compila il foglio "inserimento dati" con il periodo, l'etichetta da valorizzare e il tuo ROAS obiettivo
- Carica il file come feed supplementare in Merchant Center
Il Labelizer non elimina né modifica i prodotti — aggiunge solo un'etichetta personalizzata che puoi usare per strutturare le tue campagne.
Cosa fare con le etichette una volta assegnate
Alcune indicazioni pratiche:
- Zero clic: verifica titoli e immagini dei prodotti. Spesso il problema è nella scheda, non nella campagna.
- Zero conversioni: non eliminarli subito. Potrebbero essere prodotti che l'algoritmo sta ancora esplorando.
- Costosi: candidati all'esclusione o a una campagna separata con bid più bassi.
- Redditizi: prodotti da scalare. Considera di spostarli in una campagna dedicata con più budget.
Creare campagne separate ha senso solo quando hai volumi significativi di conversioni. Con pochi dati, la segmentazione spezza il segnale e peggiora le performance.
Il codice dello script
/**
* Script per etichettare in modo automatico i prodotti in base alla performance con periodo di tempo variabile. Potete tornare indietro del numero di giorni che volete.
*
* Autore Giuseppe Scollo. Per maggiori informazioni visitare Giuseppescollo.it
*
* Istruzioni
* 1) Copiare questo template e inserire l'URL in riga 14: https://docs.google.com/spreadsheets/d/1GJyuVM0JhPz5A3YM9ALWUKi4nFYtl6XD2rguDO9f7UY/copy
* 2) Compilare il foglio "inserimento dati", scegliendo il numero di clic minimo per valutare un prodotto, il roas obiettivo, l'etichetta personalizzata e il numero di giorni da analizzare
* 3) Caricare lo sheet come feed supplementare e aggiungere la regola in merchant per i prodotti che non presentano un valore.
*/
function main() {
// URL di default dello sheet, può essere modificato come richiesto
const SHEET_URL = '';
const TAB = 'Prodotti';
// Apertura del foglio di lavoro e recupero del valore days
let ss;
let DAYS_LOOKBACK = 30; // Valore predefinito in caso di errore
try {
ss = SpreadsheetApp.openByUrl(SHEET_URL);
// Recupero del valore dal range nominato "days"
const daysRange = ss.getRangeByName("days");
if (daysRange) {
const daysValue = daysRange.getValue();
if (!isNaN(daysValue) && daysValue > 0) {
DAYS_LOOKBACK = daysValue;
Logger.log(`Recuperato valore DAYS_LOOKBACK da range nominato "days": ${DAYS_LOOKBACK}`);
} else {
Logger.log("Valore DAYS_LOOKBACK non valido nel range nominato 'days', utilizzo valore predefinito: 90");
}
} else {
Logger.log("Range nominato 'days' non trovato, utilizzo valore predefinito: 90");
}
} catch (e) {
Logger.log("Errore durante il recupero del valore DAYS_LOOKBACK: " + e);
// Il valore predefinito è già impostato, quindi continuiamo con l'esecuzione
}
// Funzione per creare un intervallo di date dinamico
function getDateRange(numDays) {
let endDate = new Date(); // assume today is fine
let startDate = new Date();
startDate.setDate(endDate.getDate() - numDays);
let timezone = AdsApp.currentAccount().getTimeZone(); // use the account timezone
let formattedStartDate = Utilities.formatDate(startDate, timezone, 'yyyyMMdd'); // format date in a way that google allows
let formattedEndDate = Utilities.formatDate(endDate, timezone, 'yyyyMMdd');
return ` segments.date BETWEEN "${formattedStartDate}" AND "${formattedEndDate}" `; // create a string we can insert into the SQL
}
// Query per ottenere i dati dei prodotti con intervallo di date dinamico
const QUERY = `
SELECT
segments.product_title,
segments.product_item_id,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value
FROM shopping_performance_view
WHERE ${getDateRange(DAYS_LOOKBACK)}
`;
try {
// Apertura del foglio di lavoro
let ss = SpreadsheetApp.openByUrl(SHEET_URL);
let sheet = ss.getSheetByName(TAB);
// Creazione del foglio se non esiste
if (!sheet) {
Logger.log("Foglio '" + TAB + "' non trovato. Creazione di un nuovo foglio...");
sheet = ss.insertSheet(TAB);
} else {
// Rimuovo eventuali filtri esistenti prima di pulire il foglio
try {
const filter = sheet.getFilter();
if (filter) {
filter.remove();
}
} catch (filterError) {
Logger.log("Nessun filtro trovato o impossibile rimuovere: " + filterError);
}
// Pulizia del foglio esistente prima di aggiungere nuovi dati
sheet.clear();
Logger.log("Foglio '" + TAB + "' ripulito per i nuovi dati.");
}
// Aggiornamento dell'intestazione con l'intervallo di date
let endDate = new Date();
let startDate = new Date();
startDate.setDate(endDate.getDate() - DAYS_LOOKBACK);
let timezone = AdsApp.currentAccount().getTimeZone();
let formattedStartDate = Utilities.formatDate(startDate, timezone, 'dd/MM/yyyy');
let formattedEndDate = Utilities.formatDate(endDate, timezone, 'dd/MM/yyyy');
Logger.log(`Esportazione dati dal ${formattedStartDate} al ${formattedEndDate}`);
// Esecuzione della query
let report = AdsApp.report(QUERY);
// Inizializzazione dell'array per i dati elaborati
let data = [];
let rowCount = 0;
// Elaborazione dati
let rows = report.rows();
while (rows.hasNext()) {
const row = rows.next();
rowCount++;
if (rowCount === 1) {
Logger.log("Struttura primo risultato:");
Logger.log(JSON.stringify(row));
}
// Accesso ai dati nel formato corretto
const productTitle = row['segments.product_title'] || 'N/A';
const productId = row['segments.product_item_id'] || 'N/A';
const impressions = Number(row['metrics.impressions']) || 0;
const clicks = Number(row['metrics.clicks']) || 0;
const costMicros = Number(row['metrics.cost_micros']) || 0;
const conversions = Number(row['metrics.conversions']) || 0;
const convValue = Number(row['metrics.conversions_value']) || 0;
// Calcolo metriche derivate
const cost = costMicros / 1000000;
const ctr = impressions > 0 ? (clicks / impressions) : 0;
const cpc = clicks > 0 ? cost / clicks : 0;
const convRate = clicks > 0 ? (conversions / clicks) : 0;
const cpa = conversions > 0 ? cost / conversions : 0;
const roas = cost > 0 ? convValue / cost : 0;
data.push([
productTitle,
productId,
impressions,
clicks,
ctr,
cost,
cpc,
conversions,
convRate,
cpa,
convValue,
roas
]);
}
Logger.log(`Totale prodotti trovati: ${rowCount}`);
// Scrittura dati
if (data.length > 0) {
// Aggiungiamo l'intervallo di date come prima riga
sheet.getRange(1, 1).setValue(`Dati prodotti dal ${formattedStartDate} al ${formattedEndDate}`);
sheet.getRange(1, 1, 1, 12).merge();
sheet.getRange(1, 1).setFontWeight('bold').setHorizontalAlignment('center');
const headers = [
'Titolo Prodotto',
'ID Prodotto',
'Impressioni',
'Click',
'CTR (%)',
'Costo (€)',
'CPC (€)',
'Conversioni',
'Tasso Conv. (%)',
'Costo/Conv. (€)',
'Valore Conv. (€)',
'ROAS'
];
sheet.getRange(2, 1, 1, headers.length).setValues([headers]);
sheet.getRange(3, 1, data.length, headers.length).setValues(data);
// Formattazione numeri
if (data.length > 0) {
// Formato numerico per metriche intere
sheet.getRange(3, 3, data.length, 2).setNumberFormat('#,##0'); // Impressioni, Click
sheet.getRange(3, 8, data.length, 1).setNumberFormat('#,##0.00'); // Conversioni
// Formato percentuale
sheet.getRange(3, 5, data.length, 1).setNumberFormat('0.00%'); // CTR
sheet.getRange(3, 9, data.length, 1).setNumberFormat('0.00%'); // Tasso Conv.
// Formato valuta per costi
sheet.getRange(3, 6, data.length, 1).setNumberFormat('€#,##0.00'); // Costo
sheet.getRange(3, 7, data.length, 1).setNumberFormat('€#,##0.00'); // CPC
sheet.getRange(3, 10, data.length, 1).setNumberFormat('€#,##0.00'); // Costo/Conv
sheet.getRange(3, 11, data.length, 1).setNumberFormat('€#,##0.00'); // Valore Conv.
// Formato ROAS
sheet.getRange(3, 12, data.length, 1).setNumberFormat('0.00');
// Formattazione intestazione
sheet.getRange(2, 1, 1, headers.length)
.setBackground('#4285F4')
.setFontColor('white')
.setFontWeight('bold');
// Auto-dimensionamento delle colonne per leggibilità
sheet.autoResizeColumns(1, headers.length);
// Congelamento delle righe di intestazione
sheet.setFrozenRows(2);
// Aggiunta di filtri con controllo preventivo
try {
sheet.getRange(2, 1, 1, headers.length).createFilter();
} catch (filterError) {
Logger.log("Impossibile creare un filtro, probabile che ne esista già uno: " + filterError);
}
}
Logger.log("Dati elaborati e formattati con successo");
} else {
sheet.getRange(1, 1).setValue(`Nessun dato di prodotto trovato dal ${formattedStartDate} al ${formattedEndDate}`);
Logger.log("Nessun dato trovato");
}
} catch (e) {
Logger.log("Errore durante l'esecuzione:");
Logger.log(e);
Logger.log("Stack trace:");
Logger.log(e.stack);
}
}
Scrivimi se vuoi accedere al template o hai domande sul setup. Trovi anche la raccolta completa dei miei script.
Domande frequenti
Cos'è il Labelizer?
Uno script che etichetta automaticamente i prodotti in base alle loro performance nelle campagne Shopping e Performance Max, dividendoli in sei cluster che incrociano volume di clic e ROAS rispetto all'obiettivo.
Come ottengo il template del foglio Google?
Il template da usare con lo script lo trovi nel codice stesso, al punto 1 delle istruzioni in cima.
Che periodo di analisi posso scegliere?
7, 30, 60 o 90 giorni. È la novità di questa quarta versione: prima il periodo era fisso.
Il Labelizer modifica o elimina i prodotti?
No, non tocca nulla: aggiunge solo un'etichetta personalizzata che poi usi per strutturare le campagne.
Cosa faccio con i prodotti a zero conversioni?
Non eliminarli subito: potrebbero essere prodotti che l'algoritmo sta ancora esplorando. Sui prodotti a zero clic, invece, si guardano titolo e immagine: spesso il problema è nella scheda, non nella campagna.