Ti piacerebbe etichettare i prodotti in modo automatico in base alle loro performance?

Magari poter definire il periodo di tempo in cui fare analisi in base al prodotto?
Ecco uno script che fa proprio al caso tuo. Il Labelizer v4 di mia invenzione. Anche se devo dare credito sia al buon Mike Rhodes che al buon floris de schrijver perchè sono partito dai loro script per creare il mio.
Lo script è molto semplice da usare.
Ti basta fare 3 operazioni:
- copiare il template dello sheet e inserire l’url nello script
- inserire i dati richiesti (clic, roas, giorni di analisi e numero dell’etichetta) nel foglio “inserimento dati”
- caricare questo sheet come feed supplementare in merchant.
Avrai a disposizione una tabella aggiornata, nel foglio “dati etichette prodotto” che divide i prodotti nelle seguenti cluster:
- Zero clic = i prodotti che pur ricevendo impression non hanno ancora avuto un clic
- Zero conversioni = i prodotti che non hanno avuto alcuna conversione
- Costoso = i prodotti che hanno ricevuto almeno 100 clic (o il numero che avete impostato) e che hanno un ROAS inferiore all’obiettivo
- Reddittizio = i prodotti che hanno ricevuto almeno 100 clic (o il numero che avete impostato) e che hanno un ROAS superiore all’obiettivo
- Partito Bene = i prodotti che hanno ricevuto meno di 100 clic ma hanno un ROAS superiore all’obiettivo
- Partito Male = i prodotti che hanno ricevuto meno di 100 clic ma hanno un ROAS superiore all’obiettivo
Sempre nello stesso sheet di Google trovate un ulteriore foglio chiamato “Prodotti” con il dettaglio per ogni singolo prodotto”.
La cosa interessante è il periodo di tempo che è variabile. Sei libero di decidere il periodo di tempo (ultimi 7, ultimi 30, ultimi 60, ultimi 90…) per calcolare le performance dei vari prodotti.
Altra cosa che puoi scegliere è l’etichetta che vuoi valorizzare in merchant. Anche il ROAS obiettivo è variabile e ti permette distinguere i prodotti in redditizzi vs costosi e in partivo bene vs paratito male.
Alcune considerazioni pratiche.
Non togliere i prodotti a zero conversioni. Andresti a togliere tutti i test che fa l’algoritmo.
Crea una campagna per i reddittizzi solo se ha un buon numero di conversioni e un buon numero di prodotti.
Non è indispensabile separare i prodotti in campagne diverse. Puoi anche usare l’etichetta solo pere sapere per ogni gruppo di prodotti (o gruppo di schede) come si stanno comportando i prodotti e avere un veloce dettaglio.
/**
* 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);
}
}