Labelizer v4 prodotti con periodo di tempo variabile

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

labelizer product v4

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);
  }
} 

Lascia una risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *