שיפור קמפיינים בגוגל באמצעות כללים, ניסויים וסקריפטים

כללים ניסויים וסקריפטים - איך אפשר לשפר את הקמפיינים שלכם בגוגל באופן אוטומי באמצעות סקריפטים?

בכנס Update Upgrade 2019 אבישי פרוינד נתן הרצאה על איך נוכל לשפר את הקמפיינים שלנו בגוגל באופן אוטומטי. באמצעות כללים, ניסויים וסקריפטים נוכל למקסם את התוצאות שלנו. כל הפרטים בהמשך.

כללים אוטומטיים

נקרא גם חוקים / פעולות גורפות, מטרתם לבצע פעולות מסוימות באופן אוטומטי, בתקופת זמן שהגדרנו, נניח פעם ביום / בשבוע / יום בחודש.

דוגמאות:

כאשר עלות הקמפיין הגיעה החודש ל-6000 ₪, עצור פרסום

לשלוח מייל כל בוקר עם ביטוי חיפוש שיש לו ציון איכות נמוך מ-3.

אז איך נבצע זאת?

– להכנס לרמת קמפיינים / קבוצות / מילות מפתח

– לסמן את הרצוי (קמפיין, קבוצת מודעות, ביטויי מפתח – ניתן לבחור אחד או יותר)

– ללחוץ על "עוד" (שלושת הנקודות):

– ללחוץ על יצירת כלל אוטומטי:

דוגמא ראשונה

– כל יום בשש בבוקר יופעל הכלל – אם קמפיין X הוציא 6,000 ש"ח עד היום -> נעצור את הקמפיין.

מה בחרנו?

– בחרנו השהיית קמפיין

– ניתן לבחור איזה קמפיין שנרצה

– נקבע את התנאי

– נקבע את תדירות הפעולה ואת תקופת הייחוס

דוגמא שניה

– לשלוח מייל כל בוקר עם כל ביטויי המפתח שיש להם ציון איכות נמוך מ-3.

– נכנס למילות המפתח.

– נבחר בשליחת מייל.


ניסויים

– כיום גוגל משחרר לנו שלל הצעות לניהול החשבון.

– כדי לעבור מאסטרטגיה לאסטרטגיה יש להיכנס בתפריט:

"קמפיין", משם ל"הגדרות", משם ל"הצעת המחיר שלך":

 

איך מפעילים ניסוי?

קודם כל יוצרים טיוטה, לאחר מכן מגדירים את הניסוי, ואז את ההחלטה:

שלב א':

– בתחתית התפריט יש לבחור בטיוטות וניסויים

– במסך שהתקבל יש להוסיף טיוטה חדשה

– לתת שם לטיוטה ולשמור:

– בתפריט למטה תופיע הטיוטה.

– יש לבחור (לעמוד עליה), ולבחור שוב טיוטות וניסויים.

– לבחור ניסוי חדש.

 

שלב ב' – יצירת הניסוי:

– כעת נמלא את הפרטים.

– במקור אסטרטגיית הקמפיין הייתה עלות ידנית לקליק, אני רוצה לבחון מעבר לאסטרטגיה יעד להמרה.

– הניסוי יתבצע על חצי מהתנועה.

– הניסוי יערך כשבועיים (5/2 עד ל22/3).

– יש לשמור.

– יש לחבר הקמפיין

– הניסוי החל:

הערות:

– ניתן לעצור את הניסוי בכל עת.

– אם הניסוי הצליח ולא רוצים לחכות ניתן להחיל את הנסוי.


סקריפטים

מה זה סקריפט בעצם?

– סקריפט הינו קטע קוד שמבצע פעולה אוטומטית, יש הרבה סקריפטים שניתן להוריד מהאינטרנט.

– הסקריפט נמצא על גבי שרתי גוגל.

– הסקריפט יכול לפעול על חשבון, או על כל ה-MCC שלכם

התקנת סקריפט ברמת חשבון

 

הסקריפט הראשון:

– הסקריפט מנטר מודעות פעילות ובודק את הססטוס שלהם, במידה והלינק שבור – שולח דו"ח + אפשרות לעצירה מיידית.

– שם הסקריפט: (R) Ads Final URL Monitor (Pause + Report).

– שני פרמטרים: 

1. מייל אליו יישלח הדו"ח

2. האם לעצור מודעות או לא (רק דו"ח)

– סקריפט ברמת חשבון.

הערה: בשלב מסוים תתבקשו לאשר הרשאות.

 

ניתן להעתיק את הסקריפט מפה:


var EMAIL = '[email protected]';
var PAUSE = false;

function main(){  
  var htmlService = HTMLBuilderService();
  
  var ads = AdWordsApp.ads()
  .withCondition('CampaignStatus = ENABLED')
  .withCondition('AdGroupStatus = ENABLED')
  .withCondition('Status = ENABLED')
  .withCondition('Type NOT_IN [CALL_ONLY_AD]') // IMAGE_AD, MOBILE_AD, MOBILE_IMAGE_AD, PRODUCT_AD, RICH_MEDIA_AD, TEMPLATE_AD, TEXT_AD, CALL_ONLY_AD
  .withLimit(4)
  .get();
  
  Logger.log('%s ads found.', ads.totalNumEntities());
  
  var matches = 0;  
  while(ads.hasNext()){
    var ad = ads.next();      
    var adURL = ad.urls().getFinalUrl();
    var adHeader = ad.getHeadline();
    var adType = ad.getType();
    
    Logger.log('ad: %s (%s)', adHeader, adType);
    
    var statusCode = -1;
    try{
      var response = UrlFetchApp.fetch(adURL, { muteHttpExceptions: true });
      statusCode = response.getResponseCode();      
      Logger.log('[status %s] %s', statusCode, adURL);      
    }
    catch(e){
      Logger.log('[exception %s] %s', e.message, adURL);      
    }
    
    // OK
    if(statusCode == 200 || statusCode == -1) 
      continue;    
    
    var adgroup = ad.getAdGroup();
    var adgroupName = adgroup.getName();
    
    Logger.log('adgroup: %s', adgroupName);
    Logger.log('%s [%s]', adURL, statusCode);    
    
    matches++;
    
    htmlService.add(
      '

statusCode: ' + statusCode +'

' + '
adGroup: ' + adgroupName +'
' + '

adURL: ' + adURL + '

' ); if(PAUSE) { Logger.log('ad paused'); ad.pause(); } } if(matches > 0){ MailApp.sendEmail(EMAIL, 'Ad Monitor', '', { htmlBody: htmlService.get() }); } } var HTMLBuilderService = function(){ var _html = ''; return { add: function(content){ _html += content; }, get: function(){ return _html; } }; }

תנו שם לסקריפט, תנו הרשאות, והדביקו את הסקריפט:

תרשמו את המייל שלכם והאם לעצור או לא לעצור:

תלחצו על הסקריפטים, תבחרו את התדירות של ההפעלת הסקריפט

אתם יכולים לראות בהיסטורית הסקריפטים, מתי הסקריפט פעל ואיזה פעולה הוא עשה:

סקריפט שני – דיווח חודשי:

– שם הסקריפט: (R) Account Daily Stats + Charts – Current Month)

– מטרת הסקריפט: ליצור אקסל יפה ובו גרפים.

– הסקריפט מייצר קובץ גוגל שיט בתוך הדרייב.

– בראש הסקריפט שם הקובץ שאתם מעוניינים.

– אם לא קיים קובץ, הסקריפט מייצר באופן אוטומטי, אם קיים קובץ, הסקריפט מעדכן.

– הסקריפט ברמת חשבון.

 

ניתן להעתיק את הסקריפט מפה:


var SPREADSHEET = 'AccountDailyStats';

function main() {  
  var sheetService = SpreadsheetLoader.loadSheetService(SPREADSHEET);
  if(!sheetService) // create the sheet 
    sheetService = SpreadsheetLoader.createSheetService(SPREADSHEET);
  
  sheetService.clear();
  
  Logger.log('Loading "%s" Account Statistics ...', AdWordsApp.currentAccount().getName());
  var report = AdWordsApp.report(
     'SELECT Date, Impressions, Clicks, ConversionRate, Cost ' +
     'FROM   ACCOUNT_PERFORMANCE_REPORT ' +
     'DURING THIS_MONTH');
  
  report.exportToSheet(sheetService.sheet);
  sheetService.sort(1);
  
  SetTotals(sheetService);    
  
  if(!sheetService.hasCharts)
    DrawChart(sheetService);  
  
  Logger.log('Done!');
}

function SetTotals(sheetService){
  
  // TOTALS (using formulas)
  Logger.log('Setting formulas ...');
  
  var lastRowIndex = sheetService.getLastRowIndex();  
  var totalRowIndex = (parseInt(lastRowIndex) + 1).toString();
  
  sheetService.setCellSumFormula('B2:B'.concat(lastRowIndex), 'B'.concat(totalRowIndex));
  sheetService.setCellSumFormula('C2:C'.concat(lastRowIndex), 'C'.concat(totalRowIndex));
  sheetService.setCellAvgFormula('D2:D'.concat(lastRowIndex), 'D'.concat(totalRowIndex));
  sheetService.setCellSumFormula('E2:E'.concat(lastRowIndex), 'E'.concat(totalRowIndex));
  sheetService.setDataUI('A'.concat(totalRowIndex, ':E', totalRowIndex), '#F5F6F9', '#000000', 20, 'center');   
}

function DrawChart(sheetService){
  Logger.log('Drawing Chart ... ');
     
  var lastRowIndex = sheetService.getLastRowIndex();
  
  // arrRanges, vAxisDataLeft, vAxisDataRight, width, height, rowPosition, columnPosition, chartTitle 
  // vAxisData: { title, ticks, color, legend }
  sheetService.addLineChartDualY(
    ['A2:A'.concat(lastRowIndex), 'B2:B'.concat(lastRowIndex), 'C2:C'.concat(lastRowIndex)],
    { 
      title: 'impressions',
      color:'#4572A7', 
      legend:'impressions'
    },
    { 
      title: 'clicks',       
      color:'#AA4643', 
      legend:'clicks'
    },   
    700, 160, 3, 7, // chart location - row 3, column 7
    'impressions vs clicks'
  ); 
  
  sheetService.addLineChartDualY(
    ['A2:A'.concat(lastRowIndex), 'D2:D'.concat(lastRowIndex), 'C2:C'.concat(lastRowIndex)],
    { 
      title: 'conv.Rate',
      color:'#4572A7', 
      legend:'conv.Rate'
    },
    { 
      title: 'clicks',       
      color:'#AA4643', 
      legend:'clicks'
    },  
    700, 160, 11, 7, // chart location - row 10, column 7
    'conv.Rate vs clicks'
  ); 
  
  sheetService.addLineChartDualY(
    ['A2:A'.concat(lastRowIndex), 'E2:E'.concat(lastRowIndex), 'C2:C'.concat(lastRowIndex)],
    { 
      title: 'cost',
      color:'#4572A7', 
      legend:'cost'
    },
    { 
      title: 'clicks',       
      color:'#AA4643', 
      legend:'clicks'
    },
    700, 160, 19, 7, // chart location - row 17, column 7
    'cost vs clicks'
  ); 
}

/* SPREADSHEET SERVICE */
var SpreadSheetService = function(spreadSheet) {
  var _spreadSheet = spreadSheet;
  var _sheets = [];

  (function(){
    var sheetServices = [];
    var temp_sheets = spreadSheet.getSheets();
    for(var i= 0; i < temp_sheets.length; i++)
      _sheets.push(new SheetService(temp_sheets[i]));   
  })();   
  
  return {      
    sheets: _sheets,
    getActiveSheet: function(){
      return SheetService(_spreadSheet.getActiveSheet());
    },
    getSheetByName: function(sheetName) { 
         for(var i= 0; i < _sheets.length; i++)
            if(_sheets[i].sheetName == sheetName)
              return _sheets[i];
          return '';
    },
    addNewSheet: function(sheetName){
        var new_sheet = SheetService(_spreadSheet.insertSheet(sheetName));
        _sheets.push(new_sheet)
        return new_sheet;         
    },
    isSheetExists: function(sheetName){
        return this.getSheetByName(sheetName) != '';
    }, 
    getURL: function(){
      return _spreadSheet.getUrl();
    },
	getId: function(){
      return _spreadSheet.getId();
    }  
  }; 
}

/* SHEET SERVICE */
var SheetService = function(sheet) { 
  var _sheet = sheet;
  
  var setFormat = function(strRange, format){
    var range = _sheet.getRange(strRange);
    range.setNumberFormat(format);  
  }
  
  var buildLineChart = function(arrRanges, series, vAxes, width, height, rowPosition, columnPosition, chartTitle){        
       var chartBuilder = _sheet.newChart();
              
       for (var i in arrRanges)         
         chartBuilder.addRange(_sheet.getRange(arrRanges[i]));       
       
       chartBuilder
       .setChartType(Charts.ChartType.LINE)  // chart type - line        
       .setPosition(rowPosition, columnPosition, 0, 0)  // chart location row X column Y       
                            
       .setOption('animation.duration', 500) // animation                 
       .setOption('width', width)        
       .setOption('height', height)                                    
       .setOption('legend', { position: 'bottom', alignment: 'center' })                 
       .setOption('hAxis.textPosition', 'none') // hide hAxis labels (options: out, in, none)     
       .setOption('series', series)  // parameter       
       .setOption('vAxes', vAxes) // parameter              
       
       if(chartTitle)
         chartBuilder.setOption('title', chartTitle); 

       _sheet.insertChart(chartBuilder.build());
  }
  
  return {   
    sheet: _sheet,
     hasSheet: _sheet != null,
     sheetName: _sheet ? _sheet.getName() : '',
     getLastRowIndex: function(){ return _sheet.getLastRow();}, 
     getLastColumnIndex: function(){ return _sheet.getLastColumn();}, 
     getValue: function(rowPosition, columnPosition){ 
       return _sheet.getRange(rowPosition, columnPosition).getValue();
     }, 
     getValues: function(){
       return _sheet.getDataRange().getValues();
     }, 
     getRowValues:function(rowPosition){       
       return _sheet.getRange(rowPosition, 1, 1, this.getLastColumnIndex()).getValues();
     },
     getRowIndex: function(columnPosition, key){
       var rows = _sheet.getDataRange().getValues();
 
       // row index is 0 based but range is 1 based
       for(row in rows)
         if(rows[row][columnPosition - 1] == key)
           return parseInt(row) + 1;
       return -1;  
     },
     getRowIndexBy2Columns: function(columnAPosition, keyA, columnBPosition, keyB){ 
       var rows = _sheet.getDataRange().getValues();
 
       // row index is 0 based but range is 1 based
       for(row in rows)
         if(rows[row][columnAPosition - 1] == keyA && rows[row][columnBPosition - 1] == keyB)
           return parseInt(row) + 1;
       return -1;  
     },
     getColumnValues: function(startRowPosition, columnPosition){
        // getRange(row, column, numRows, numColumns)
        return _sheet.getRange(startRowPosition, columnPosition, _sheet.getLastRow() - 1, 1).getValues();
     }, 
     addRow: function(arrValues){ 
       //_sheet.appendRow(arrValues);
       this.addRowAtIndex(arrValues, _sheet.getLastRow() + 1);
     },
     addRowAtIndex: function(arrValues, rowPosition){               
        rowPosition = rowPosition || _sheet.getLastRow() + 1;
        var range = _sheet.getRange(rowPosition, 1, 1, arrValues.length);
        range.setValues([arrValues]);
     },
     addLineChart: function(arrRanges /* range format: 'B15:B24' */, vAxisData /* { title, ticks, lines[]{color, legend}  } */, width, height, rowPosition, columnPosition, chartTitle){  
       var series = [];
       for (var i in vAxisData.lines)         
         series.push({ 
           color: vAxisData.lines[i].color, 
           labelInLegend : vAxisData.lines[i].legend,
           pointShape: 'square',
           pointSize: 4,
           targetAxisIndex: 0 // only one vAxis (index 0)
         });
       
       var minValue = 0;
       if(vAxisData.ticks) // custom vAxis values      
         // set minimum value to be the minimum tick value
         minValue = Math.min.apply(null, vAxisData.ticks).toFixed(0);
       
       var vAxis = { 
         ticks: vAxisData.ticks, // null for default
         title: vAxisData.title,
         minValue: minValue, 
         viewWindow: { min: minValue }
       };

       var vAxes = [];
       vAxes.push(vAxis); // only one vAxis (index 0)
       
       buildLineChart(arrRanges, series, vAxes, width, height, rowPosition, columnPosition, chartTitle);
     },
     addLineChartDualY: function(arrRanges /* range format: 'B15:B24' */, vAxisDataLeft /* { title, ticks, color, legend } */, vAxisDataRight, width, height, rowPosition, columnPosition, chartTitle){  
       var series = [];
       
       series.push({ 
           color: vAxisDataLeft.color, 
           labelInLegend : vAxisDataLeft.legend,
           pointShape: 'square',
           pointSize: 4,
           targetAxisIndex: 0 // vAxis (index 0)
       });
             
       series.push({ 
           color: vAxisDataRight.color, 
           labelInLegend : vAxisDataRight.legend,
           pointShape: 'square',
           pointSize: 4,
           targetAxisIndex: 1 // vAxis (index 1)
       });
       
       var minValueLeft = 0;
       if(vAxisDataLeft.ticks) // custom vAxis values      
         // set minimum value to be the minimum tick value
         minValueLeft = Math.min.apply(null, vAxisDataLeft.ticks).toFixed(0);
       
       var vAxisLeft = { 
         ticks: vAxisDataLeft.ticks, // null for default
         title: vAxisDataLeft.title,
         minValue: minValueLeft, 
         viewWindow: { min: minValueLeft }
       };
       
       var minValueRight = 0;
       if(vAxisDataRight.ticks) // custom vAxis values      
         // set minimum value to be the minimum tick value
         minValueRight = Math.min.apply(null, vAxisDataRight.ticks).toFixed(0);
       
       var vAxisRight = { 
         ticks: vAxisDataRight.ticks, // null for default
         title: vAxisDataRight.title,
         minValue: minValueRight, 
         viewWindow: { min: minValueRight }
       };

       var vAxes = [];
       vAxes.push(vAxisLeft); // vAxis (index 0)
       vAxes.push(vAxisRight); // vAxis (index 1)
       
       buildLineChart(arrRanges, series, vAxes, width, height, rowPosition, columnPosition, chartTitle);
     },
     addImageFromURL: function(url, rowPosition, columnPosition, top, left){ 
       top = top || 0;
       left = left || 0;
       
       _sheet.insertImage(url, rowPosition, columnPosition, left, top);
     },   
     deleteRow: function(rowPosition){
       _sheet.deleteRow(rowPosition);
     },  
     sort: function(columnPosition){
       _sheet.sort(columnPosition);
     },
     hasCharts:  _sheet.getCharts().length > 0,
     findColumnValuesByFilter: function(columnPosition, filterValue, filterColumnPosition){
       /* 
          get column values filtered by other column
          
          e.g: findColumnValuesByFilter(2, '100', 1)          
          all B column values that the value in A column equals to '100'
       */

       var result = [];       
       var rows = _sheet.getDataRange().getValues();
 
       for(row in rows)
         if(rows[row][filterColumnPosition - 1] == filterValue)
           result.push(rows[row][columnPosition]);
       return result;  
     }, 
     clear: function(charts, format, contents){
       charts = charts || false;
       format = format || false;
       contents = contents || true;
       
       if(!charts) return; 
       
       // clear all charts
       _sheet.clear({ formatOnly: format, contentsOnly: contents });        
       var charts = _sheet.getCharts();
       for (var i in charts)
         _sheet.removeChart(charts[i]);
     },          
     setValue: function(rowPosition, columnPosition, value){ 
       _sheet.getRange(rowPosition, columnPosition).setValue(value);
     },     
     setRangeValue: function(strRange, value){ 
       // e.g: setCurrencyFormat('A1'); // set cell
       _sheet.getRange(strRange).setValue(value);
     },
     setDataUI: function(strRange, backgroundColor, foreColor, fontSize, align){
       var range = _sheet.getRange(strRange);
       if(backgroundColor)
           range.setBackground(backgroundColor);
       if(foreColor)
           range.setFontColor(foreColor);
       if(fontSize)
           range.setFontSize(fontSize);
       if(align)
         range.setHorizontalAlignment(align);
     }, 
     setNumberFormat: function(strRange){
       setFormat(strRange, '0');       
     },
     setDecimalFormat: function(strRange){
       setFormat(strRange, '0.00');
     },
     setCurrencyFormat: function(strRange){
       // e.g: setCurrencyFormat('A1'); // set cell
       // e.g: setCurrencyFormat('A1:A10'); // set range
       
       setFormat(strRange, '$0.00');
     },
     setCellSumFormula: function(strRange, strCell){
       // e.g: setCellSumFormula('A1:A10', 'B1'); 
       // set SUM value of cells A1 to A10 to cell B1
       
       var cell = _sheet.getRange(strCell);
       cell.setFormula('=SUM(' + strRange + ')');
     },
     setCellAvgFormula: function(strRange, strCell){
       // e.g: setCellSumFormula('A1:A10', 'B1'); 
       // set AVG value of cells A1 to A10 to cell B1
       
       var cell = _sheet.getRange(strCell);
       cell.setFormula('=AVERAGE(' + strRange + ')');
     }       
   }; 
}

/* SPREADSHEET LOADER */
var SpreadsheetLoader = {
  createSpreadSheet: function(spreadSheetName, folderName){
    Logger.log('CREATING %s ... ', spreadSheetName);
    var spreadsheet = SpreadsheetApp.create(spreadSheetName); // create new file         
    
    if(!folderName || folderName == '') 
      return spreadsheet; // folder not specified  - return spreadsheet
     
    // save in specific folder 
    
    for(var i=0;i<500000; i++); // delay

    var root_folder = DriveApp.getRootFolder();     
    var folder_iterator = root_folder.getFoldersByName(folderName);
    var folderExists = folder_iterator.hasNext();
    
    if(!folderExists) // no such folder - return the spreadsheet
    {
      Logger.log('%s NOT EXISTS!', folderName);
      return spreadsheet;
    }
    
    var folder = root_folder.getFoldersByName(folderName).next();
    var file = root_folder.getFilesByName(spreadSheetName).next();
    folder.addFile(file);
    root_folder.removeFile(file);

    return SpreadsheetApp.openById(file.getId());    
  }, 
  loadSpreadSheet: function(spreadSheetName, folderName){
	if(spreadSheetName == '') {
      Logger.log('EMPTY NAME!');
      return null;
    }

    var root_folder = DriveApp.getRootFolder();
    var folder = root_folder; // default 
    if(folderName && folderName != '')
    {
      var folder_iterator = root_folder.getFoldersByName(folderName);
      var folderExists = folder_iterator.hasNext();
      
      if(folderExists)
      {
        Logger.log('FOLDER %s', folderName);
        folder = root_folder.getFoldersByName(folderName).next();
      }
    }
    
    var file_iterator = folder.getFilesByName(spreadSheetName);
    var fileExists = file_iterator.hasNext();
    
    if(!fileExists){
      Logger.log('%s NOT EXISTS!', spreadSheetName);
      return null;
    }
    
    // file exists - load it
    Logger.log('LOADING %s ... ', spreadSheetName);
    var file = file_iterator.next();
    return SpreadsheetApp.openById(file.getId());    
  }, 
  loadSpreadSheetById: function(spreadSheet_id){
    if(spreadSheet_id == '') {
      Logger.log('EMPTY ID!');
      return null;
    }
    
    var file = DriveApp.getFileById(spreadSheet_id);
    if(!file || file.isTrashed()){
      Logger.log('%s NOT EXISTS!', spreadSheet_id);
      return null;
    }
    
    // file exists - load it
    Logger.log('LOADING %s ... ', spreadSheet_id);
    return SpreadsheetApp.openById(file.getId());    
  },  
  loadSheetService: function(spreadSheetName, folderName){
    var spreadsheet = this.loadSpreadSheet(spreadSheetName, folderName);
    if(!spreadsheet) return null;
    return SheetService(spreadsheet.getActiveSheet());
  }, 
  loadSheetServiceById: function(spreadSheet_id){
    var spreadsheet = this.loadSpreadSheetById(spreadSheet_id);
    if(!spreadsheet) return null;
    return SheetService(spreadsheet.getActiveSheet());
  },  
  loadSpreadSheetService: function(spreadSheetName, folderName){
    var spreadsheet = this.loadSpreadSheet(spreadSheetName, folderName);
    if(!spreadsheet) return null;
    return SpreadSheetService(spreadsheet);
  },
  loadSpreadSheetServiceById: function(spreadSheet_id){
    var spreadsheet = this.loadSpreadSheetById(spreadSheet_id);
    if(!spreadsheet) return null;
    return SpreadSheetService(spreadsheet);
  },
  createSheetService: function(spreadSheetName, folderName){
    var spreadsheet = this.createSpreadSheet(spreadSheetName, folderName);
    if(!spreadsheet) return null;
    return SheetService(spreadsheet.getActiveSheet());
  },
  createSpreadSheetService: function(spreadSheetName, folderName){
    var spreadsheet = this.createSpreadSheet(spreadSheetName, folderName);
    if(!spreadsheet) return null;
    return SpreadSheetService(spreadsheet);
  }
}
    

 

סקריפט שלישי – טיפול במודעות לא ממירות:

– שם הסקריפט: R) Pause Non Converting or High Cost Ads)

– מטרת הסקריפט: לעצור מודעות שלא ממירות או בעלות המרה גבוהה.

– סקריפט ברמת חשבון.

 

ניתן להעתיק את הסקריפט מפה:


    var PERIOD = 'ALL_TIME'; // ALL_TIME, LAST_30_DAYS

function main() {
  HandleNonConvertingAds();
  HandleConvertingAds();
}

function HandleNonConvertingAds(){ 
  Logger.log('## Non Converting Ads ##')
  var ads = AdWordsApp.ads()
     .withCondition('ConvertedClicks = 0')
     .withCondition('Status = ENABLED')
     .withCondition('Cost > 0')  
     .forDateRange(PERIOD)
     .orderBy('Cost ASC')
     .get();
  
  while (ads.hasNext()) {
    var ad = ads.next();
    var adGroup = ad.getAdGroup();
    var adGroupCPA = GetAdGroupCPA(adGroup);
    var adCost = ad.getStatsFor(PERIOD).getCost();
    
    Logger.log('ad: %s -> cost %s', ad.getHeadline(), adCost);
    Logger.log('adGroup %s -> CPA %s', adGroup.getName(), adGroupCPA);
        
    if(adGroupCPA == null || adCost < adGroupCPA * 2) // no changes require
      continue;
    
    // adCost is too high - pause the ad 
    if(!AdWordsApp.getExecutionInfo().isPreview())
      ad.pause();
    Logger.log('PAUSE THE AD!');
  }
}

function GetAdGroupCPA(adGroup){
  var stats = adGroup.getStatsFor(PERIOD);
  var conversions = stats.getConvertedClicks();
  return conversions == 0 ? 0 : (stats.getCost() / conversions); // calculate the ad "CPA" - cost per converted
}

function HandleConvertingAds(){ 
  Logger.log('## Converting Ads ##')
  var ads = AdWordsApp.ads()
     .withCondition('ConvertedClicks > 0')
     .withCondition('Status = ENABLED')
     .withCondition('Cost > 0')  
     .forDateRange(PERIOD)
     .orderBy('ConvertedClicks DESC')
     .get();
  
  while (ads.hasNext()) {
    var ad = ads.next();
    var adGroup = ad.getAdGroup();
    var adGroupCPA = GetAdGroupCPA(adGroup);
    var stats = ad.getStatsFor(PERIOD);
    var adCPA = stats.getCost() / stats.getConvertedClicks(); // calculate the ad "CPA" - cost per converted
    
    Logger.log('ad: %s -> Conversions %s, CPA %s', ad.getHeadline(), stats.getConvertedClicks(), adCPA)
    Logger.log('adGroup %s -> CPA %s', adGroup.getName(), adGroupCPA);
        
    if(adGroupCPA == null || adCPA < adGroupCPA * 4) // no changes require
      continue;
    
    // adCost is too high - pause the ad 
    if(!AdWordsApp.getExecutionInfo().isPreview())
      ad.pause();
    Logger.log('PAUSE THE AD!');
  }
}
    

סקריפט רביעי – מילות מפתח חבויות:

– שם הסקריפט: (R) queries 2 keywords – mcc (set)

– מטרת הסקריפט: לקחת מילות מפתח שיבצעו המרה בפועל אך לא מופיעות בפועל.

– הסבר: ביטוח המפתח המקורי היה ביטוי בפרייז או BMM.

– סקריפט ברמת MCC.

 

ניתן להעתיק את הסקריפט מפה:


function main() {
  var accounts = MccApp.accounts().get();

  while (accounts.hasNext()) {
    var account = accounts.next();
    var accountName = account.getName() ? account.getName() : '--';
    Logger.log('account #%s %s', account.getCustomerId(), accountName);

    MccApp.select(account); 
    execute();    
  }
}

function execute() {
  var report = AdWordsApp.report(
   'SELECT Query,Clicks,ConvertedClicks,AverageCpc ' +
   'FROM SEARCH_QUERY_PERFORMANCE_REPORT ' +
   'WHERE ConvertedClicks > 0 ' + 
   'DURING 20000101,' + dateFormat(new Date()));
 
  var rows = report.rows();  
  while(rows.hasNext()) {
    var row = rows.next();
    
    var clicks = row['Clicks'];
    var conversions = row['ConvertedClicks'];

    var query = row['Query'];
    //Logger.log(query + ' ' + clicks);
    var found_in_my_keywords = AdWordsApp.keywords().withCondition('Text CONTAINS "' + query + '"').get().hasNext();
    if(found_in_my_keywords)
    {
      Logger.log('"' + query + '" found in my keywords');
      continue;
    }
    
    var adGroup = AdWordsApp.adGroups().get().next();
    var maxcpc = row['AverageCpc'];
    
    if(!AdWordsApp.getExecutionInfo().isPreview())
      adGroup.createKeyword(query, maxcpc);
    Logger.log('"' + query + '" added as keyword with maxcpc ' + maxcpc)
  }
}

function dateFormat(date){
  var year = date.getFullYear().toString();
  var month = date.getMonth().toString();
  var day = date.getDate().toString();
  
  if(month.length == 1) month = '0' + month; // return yyyyMMdd
  if(day.length == 1) day = '0' + day;
  
  return year + month + day;
}
    

דוגמאות נוספות

– אתר מסחר אלקטרוני, ניטור המודעות הפעילות ועצירת המודעה כאשר המכירה הסתיימה – קריאת נתונים מתוך הHTML

– ניהול קמפיין מלא על בסיס פיד (אקסל או XML או גייסון) החל מיצירת המודעה חדשה כאשר מוצר חדש לדוגמא: "רק היום המוצר X בהנחה", הפסקת המודעה כאשר אין במלאי, עדכון מחיר בתוך המודעה

– ניהול תקציב כדי שתגיע בדיוק לתקציב שהוגדר, לא פחות ולא יותר.

– הזרקה של נתונים לתוך מודעות

– מערכת התרעות לבעיות בקמפיינים

סיכום

מטרת הכללים הניסויים והסקריפטים הם לעזור לנו לנהל את החשבון בצורה אוטומטית ולייצר תהליכי עבודה שישפרו לנו את הביצועים, אני ממליץ לכל אחד להשתמש בכללים בשביל פעולות אוטומטיות, בניסויים בשביל לנסות דברים חדשים בלי לפגוע בביצועים, ובסקריפטים בשביל מקרים שאין כללים מתאימים
 

אבישי פרוינד

  • מנהל ובעלים של לוגוס שיווק באינטרנט
  • מומחה לשיווק, פרסום וקידום ברשת
  • מייעץ ומלווה גופים מוסדיים וגורמים פרטיים בכל הקשור למדיום האינטרנטי
  • מקצוען מוסמך ע"י גוגל Google Advertising Professional
  • מרצה בכיר באוניברסיטאות ומכללות העוסק בהוראת השיווק באינטרנט וטכנולוגיות WEB
  • משמש כמומחה מטעם בית המשפט לתחום הפרסום והשיווק.
  • מוסמך במנהל עסקים MBA ביה"ס לניהול של הפקולטה להנדסה, אוניברסיטת בן גוריון, באר שבע