控制 Google Ads 预算脚本

控制 Google Ads 预算脚本

基本上,这个脚本显着降低了超支的可能性,这有时一点也不酷。Google 最多可以花费两倍的广告系列预算,这可能太多了。这个脚本将确保你可以像你需要的那样节俭。

脚本是如何工作的?

该脚本会检查每个广告系列的支出和预算。您需要做的就是设置一个乘数阈值——如果支出大于预算乘以阈值,则该活动将被标记。您将收到一封电子邮件,其中列出了新标记的广告系列及其支出和预算。如果您愿意,您可以设置另一个阈值,这样如果支出超出预算太多,广告系列就会暂停。

该脚本还会检查广告系列的支出是否低于您的标记和暂停阈值,因此它可以取消标记和取消暂停它们。这意味着当它是新的一天并且还没有花费任何东西时,标签将被删除,并且脚本暂停的任何内容都将被重新激活。这也意味着,如果广告系列超出预算,但您增加了预算,标签和状态将反映新增加的预算。

我如何使用它?

  1. CampaignNameContains 和 campaignNameDoesNotContain 过滤脚本将查看的活动。例如,如果campaignNameContains 是[“Generic”, “Competitor”],那么只有名称包含“generic”或“competitor”的活动才会被标记或暂停。如果campaignNameDoesNotContain 是[“品牌”,“关键术语”],则名称中包含“品牌”或“关键术语”的任何广告系列都将被忽略(并且可以随心所欲地超支)。
    • 这不区分大小写。
    • 留空 [] 以包含所有广告系列。
    • 如果您需要在 CampaignNameContains 或 CampaignNameDoesNotContain 中添加双引号,请在其前添加反斜杠。
  2. 电子邮件是在活动被标记或暂停时将通过电子邮件发送的地址列表。
    • 请注意,即使正在预览脚本且未进行更改,也会发送电子邮件。
  3. 货币符号、千位分隔符和小数点标记用于格式化电子邮件中的预算和支出数字。
  4. labelThreshold 确定与预算相比,活动必须花费多少,脚本才能将其标记为超支。
    • 例如,如果您将 labelThreshold 设置为 1,则营销活动将被标记,如果支出等于预算,您将收到电子邮件。如果您将其设置为 1.2,那么如果支出是预算的 120%,则营销活动将被标记并发送电子邮件。
  5. labelName 是将应用于超支活动的标签名称。
  6. 如果您希望暂停超出预算的广告系列,请将 CampaignPauser 设置为 true。如果您不希望脚本暂停活动,无论他们花费多少(脚本仍会根据 labelThreshold 标记和发送电子邮件),请将其设置为 false。
  7. pauseThreshold 确定与预算相比,广告活动必须花费多少,脚本才能暂停它(如果 CampaignPauser 为真)。
    • 这与 labelThreshold 的工作原理相同:如果它是 1.2,则如果其支出是预算的 120%,则广告系列将暂停。
    • 这必须大于或等于 labelThreshold。该脚本需要对暂停的活动进行标记,以便在支出减少时知道要重新激活哪些活动。

预览脚本以确保它按预期工作(并检查日志以防出现任何警告)。然后设置一个时间表,使脚本每小时运行一次。

需要注意的几点
  • 该脚本仅适用于搜索和展示广告系列!它无助于视频、购物或通用应用广告系列。
  • 此脚本不能完全防止您超出预算。该脚本仅每小时运行一次,因此活动可以在两次运行之间超过支出阈值。支出数据有 15 到 20 分钟的滞后。
  • 预定脚本不会在整点运行,因此不会在新的一天开始时立即重新激活广告系列。相反,它们会在脚本在新的一天首次运行时重新激活,某个时间在午夜和凌晨 1:00 之间的某个时间无论如何大多数广告活动此时收到的流量很少 – 但如果您不是这种情况,您可能需要设置自动规则在午夜时分完全取消暂停。
  • 您可以将 labelThreshold 设置为小于 1。例如,如果将其设置为 0.9,则当活动达到其预算的 90% 时,您将收到一封电子邮件。
// ID: 9603512cc806b0a3cdbe3cbe8d1c8908
/**
 *
 * Campaign Budget Overspend Monitoring
 *
 * This script labels campaigns whose spend today is more than their daily
 * budgets. Optionally, it also pauses campaigns whose spend exceeds the
 * budget by too much. An email is then sent, listing the newly labelled
 * and paused campaigns.
 * When spend no longer exceeds budget, the campaigns are reactivated and
 * labels are removed.
 *
 * Version: 1.0
 * Google AdWords Script maintained on brainlabsdigital.com
 *
 */

// ////////////////////////////////////////////////////////////////////////////
// Options

var campaignNameContains = [];
// Use this if you only want to look at some campaigns.
// For example ["Generic"] would only look at campaigns with 'generic' in the name,
// while ["Generic", "Competitor"] would only look at campaigns with either
// 'generic' or 'competitor' in the name.
// Leave as [] to include all campaigns.

var campaignNameDoesNotContain = [];
// Use this if you want to exclude some campaigns.
// For example ["Brand"] would ignore any campaigns with 'brand' in the name,
// while ["Brand", "Key Terms"] would ignore any campaigns with 'brand' or
// 'key terms' in the name.
// Leave as [] to not exclude any campaigns.

var email = ['[email protected]'];
// The email address you want the hourly update to be sent to.
// If you'd like to send to multiple addresses then have them separated by commas,
// for example ["[email protected]", "[email protected]"]

var currencySymbol = '£';
// Used for formatting in the email.

var thousandsSeparator = ',';
// Numbers will be formatted with this as the thousands separator.
// eg If this is ",", 1000 will appear in the email as 1,000
// If this is ".", 1000 will appear in the email as 1.000
// If this is "" 1000 will appear as 1000.

var decimalMark = '.';
// Numbers will be formatted with this as the decimal mark
// eg if this is ".", one and a half will appear in the email as 1.5
// and if this is "," it will be 1,5

var labelThreshold = 1.0;
// This is multiplied by the campaign's daily budget to create a threshold.
// If the campaign spend is higher than the threshold, it will be labelled
// (and you will be emailed).
// For example if labelThreshold = 1.0 then campaigns are labelled when
// their spend is greater than or equal to their budget.

var labelName = 'Over Budget';
// The name of the label you want to apply to campaigns that have gone
// over budget.

var campaignPauser = false;
// Set this to true to pause campaigns if spend exceeds the pauseThreshold.
// Set to false if campaigns are to be kept enabled.

var pauseThreshold = 1.2;
// This is multiplied by the campaign's daily budget to create a threshold.
// If campaignPauser is true and the campaign spend is higher than this threshold,
// it will be paused (and you will be emailed).
// For example if pauseThreshold = 1.2 then campaigns are paused when
// their spend is greater than or equal to 120% of their budget.
// pauseThreshold MUST be greater than or equal to the labelThreshold, so that all
// campaigns that the script pauses are also labelled.


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Functions

function main() {
  checkInputs();

  // Get the campaign IDs (based on campaignNameDoesNotContain and campaignNameContains)
  var campaignData = getCampaignIds();

  var campaignsToAddLabel = [];
  var campaignsToRemoveLabel = [];
  var campaignsToPause = [];
  var campaignsToEnable = [];

  for (var campaignId in campaignData) {
    var currentCampaign = campaignData[campaignId];

    var budget = currentCampaign.Budget;
    var status = currentCampaign.CampaignStatus;
    var spend = currentCampaign.Spend;
    var label = currentCampaign.Labels;

    var pauseBudgetCap = pauseThreshold * budget;
    var labelBudgetCap = labelThreshold * budget;

    if (status == 'enabled' && label.indexOf('"' + labelName + '"') == -1) {
      if (spend >= labelBudgetCap) {
        campaignsToAddLabel.push(currentCampaign);
      }
    }
    if (status == 'enabled') {
      if (spend >= pauseBudgetCap) {
        campaignsToPause.push(currentCampaign);
      }
    }
    if (status == 'paused' && label.indexOf('"' + labelName + '"') != -1) {
      if (spend <= pauseBudgetCap) {
        campaignsToEnable.push(currentCampaign);
      }
    }
    if (status == 'enabled' && label.indexOf('"' + labelName + '"') != -1) {
      if (spend <= labelBudgetCap) {
        campaignsToRemoveLabel.push(currentCampaign);
      }
    }
  }

  // Change and update campaigns
  if (campaignsToEnable.length > 0 && campaignPauser === true) {
    Logger.log(campaignsToEnable.length + ' campaigns to enable');
    enableCampaigns(campaignsToEnable);
  }
  if (campaignsToRemoveLabel.length > 0) {
    Logger.log(campaignsToRemoveLabel.length + ' campaigns to unlabel');
    removeLabel(campaignsToRemoveLabel);
  }
  if (campaignsToAddLabel.length > 0) {
    Logger.log(campaignsToAddLabel.length + ' campaigns to label');
    addLabel(campaignsToAddLabel);
  }
  if (campaignsToPause.length > 0 && campaignPauser === true) {
    Logger.log(campaignsToPause.length + ' campaigns to pause');
    pauseCampaigns(campaignsToPause);
  }

  // Send an email, if actions were taken
  sendSummaryEmail(campaignsToAddLabel, campaignsToPause, campaignPauser, email);
}


// Check the inputs
function checkInputs() {
  if (!isValidNumber(labelThreshold)) {
    throw "labelThreshold '" + labelThreshold + "' is not a valid, positive number.";
  }
  if (labelThreshold > 2) {
    Logger.log("Warning: labelThreshold '" + labelThreshold + "' is greater than 2. As AdWords does not spend more than twice the budget, this threshold will not be reached.");
  }
  if (campaignPauser) {
    if (!isValidNumber(pauseThreshold)) {
      throw "pauseThreshold '" + pauseThreshold + "' is not a valid, positive number.";
    }
    if (pauseThreshold < labelThreshold) {
      throw "pauseThreshold '" + pauseThreshold + "' is less than labelThreshold '" + labelThreshold + "'. It should be greater than or equal to labelThreshold.";
    }
    if (pauseThreshold > 2) {
      Logger.log("Warning: pauseThreshold '" + pauseThreshold + "' is greater than 2. As AdWords does not spend more than twice the budget, this threshold will not be reached.");
    }
  }
}


// Checks the input is a number that's finite and greater than zero
function isValidNumber(number) {
  var isANumber = !isNaN(number) && isFinite(number);
  var isPositive = number > 0;
  return isANumber && isPositive;
}


// Get the IDs of campaigns which match the given options
function getCampaignIds() {
  var whereStatement = "WHERE CampaignStatus IN ['ENABLED','PAUSED'] ";
  var whereStatementsArray = [];
  var campData = {};

  for (var i = 0; i < campaignNameDoesNotContain.length; i++) {
    whereStatement += "AND CampaignName DOES_NOT_CONTAIN_IGNORE_CASE '" + campaignNameDoesNotContain[i].replace(/"/g, '\"') + "' ";
  }

  if (campaignNameContains.length == 0) {
    whereStatementsArray = [whereStatement];
  } else {
    for (var i = 0; i < campaignNameContains.length; i++) {
      whereStatementsArray.push(whereStatement + 'AND CampaignName CONTAINS_IGNORE_CASE "' + campaignNameContains[i].replace(/"/g, '\"') + '" ');
    }
  }

  for (var i = 0; i < whereStatementsArray.length; i++) {
    var report = AdWordsApp.report(
      'SELECT CampaignId, CampaignName, CampaignStatus, Amount, Labels, LabelIds, Cost '
      + 'FROM   CAMPAIGN_PERFORMANCE_REPORT '
      + whereStatementsArray[i]
      + "AND AdvertisingChannelType IN ['SEARCH', 'DISPLAY'] "
      + 'DURING TODAY'
    );

    var rows = report.rows();
    while (rows.hasNext()) {
      var row = rows.next();
      var budget = parseFloat(row.Amount.replace(/,/g, ''));
      var spend = parseFloat(row.Cost.replace(/,/g, ''));
      var campaignId = row.CampaignId;

      campData[campaignId] = {
        CampaignId: campaignId,
        CampaignName: row.CampaignName,
        CampaignStatus: row.CampaignStatus,
        Spend: spend,
        Budget: budget,
        Labels: row.Labels,
        LabelId: row.LabelIds
      };
    }
  }

  var campaignIds = Object.keys(campData);
  if (campaignIds.length == 0) {
    throw ('No campaigns found with the given settings.');
  }
  Logger.log(campaignIds.length + ' campaigns found');

  return campData;
}


// Create the label if it doesn't exist, and return its ID.
// (Returns a dummy ID if the label does not exist and this is a preview run,
// because we can't create or apply the label)
function getOrCreateLabelId(labelName) {
  var labels = AdWordsApp.labels().withCondition("Name = '" + labelName + "'").get();

  if (!labels.hasNext()) {
    AdWordsApp.createLabel(labelName);
    labels = AdWordsApp.labels().withCondition("Name = '" + labelName + "'").get();
  }

  if (AdWordsApp.getExecutionInfo().isPreview() && !labels.hasNext()) {
    var labelId = 0;
  } else {
    var labelId = labels.next().getId();
  }
  return labelId;
}


// Pause Campaigns
function pauseCampaigns(campaignData) {
  for (j = 0; j < campaignData.length; j++) {
    var campaignIterator = AdWordsApp.campaigns()
      .withCondition('CampaignId = ' + campaignData[j].CampaignId)
      .get();
    if (campaignIterator.hasNext()) {
      var campaign = campaignIterator.next();
      campaign.pause();
      campaignData[j].CampaignStatus = 'paused';
    }
  }
}


// Enable Campaigns that were paused
function enableCampaigns(campaignData) {
  for (j = 0; j < campaignData.length; j++) {
    var campaignIterator = AdWordsApp.campaigns()
      .withCondition('CampaignId = ' + campaignData[j].CampaignId)
      .get();
    if (campaignIterator.hasNext()) {
      var campaign = campaignIterator.next();
      campaign.enable();
      campaignData[j].CampaignStatus = 'enabled';
    }
  }
}


// Add Labels to campaigns
function addLabel(campaignData) {
  for (j = 0; j < campaignData.length; j++) {
    var campaign = AdWordsApp.campaigns()
      .withCondition('CampaignId = ' + campaignData[j].CampaignId).get().next();
    getOrCreateLabelId(labelName);
    campaign.applyLabel(labelName);
  }
}


// Remove Labels from campaigns
function removeLabel(campaignData) {
  for (j = 0; j < campaignData.length; j++) {
    var campaign = AdWordsApp.campaigns()
      .withCondition('CampaignId = ' + campaignData[j].CampaignId).get().next();
    campaign.removeLabel(labelName);
  }
}


// Combines information on labelled and paused campaigns and emails this
function sendSummaryEmail(campaignsToAddLabel, campaignsToPause, campaignPauser, email) {
  var localDate = Utilities.formatDate(new Date(), AdWordsApp.currentAccount().getTimeZone(), 'yyyy-MM-dd');
  var localTime = Utilities.formatDate(new Date(), AdWordsApp.currentAccount().getTimeZone(), 'HH:mm');

  // Assemble the email message
  var subject = AdWordsApp.currentAccount().getName() + ' - Budget Overspend Email';
  var message = '';
  message += makeChangeMessage(campaignsToAddLabel, 'labelled');
  if (campaignPauser) {
    message += makeChangeMessage(campaignsToPause, 'paused');
  }
  if (message == '') {
    Logger.log('No message to send.');
    return;
  }
  message = localDate + ' at ' + localTime + ' :' + message;
  MailApp.sendEmail({
    to: email.join(','),
    subject: subject,
    htmlBody: message
  });
  Logger.log('Message to ' + email.join(',') + ' sent.');
}


// Turns campaign data into an HTML table
function makeChangeMessage(campaignData, changed) {
  if (campaignData.length == 0) {
    return '';
  }
  var message = '<br><br>Campaigns that have been ' + changed + '<br><br>';
  var table = "<table border=1 style='border: 1px solid black; border-collapse: collapse;'>";
  table += '<tr><th>Campaign ID</th><th>Campaign Name</th><th>Status</th><th>Spend</th><th>Budget</th></tr>';
  for (var k = 0; k < campaignData.length; k++) {
    table += '<tr><td>' + campaignData[k].CampaignId + '</td><td>' + campaignData[k].CampaignName + '</td><td>'
      + campaignData[k].CampaignStatus + '</td><td>' + formatNumber(campaignData[k].Spend, true) + '</td><td>' + formatNumber(campaignData[k].Budget, true) + '</td>';
    table += '</tr>';
  }
  table += '</table>';
  message += table;
  return message;
}


// Formats a number with the specified thousand separator and decimal mark
// Adds the currency symbol and two decimal places if isCurrency is true
function formatNumber(number, isCurrency) {
  if (isCurrency) {
    var formattedNumber = number.toFixed(2);
    formattedNumber = formattedNumber.substr(0, formattedNumber.length - 3);
    formattedNumber = formattedNumber.split('').reverse().join('').replace(/(...)/g, '$1 ')
      .trim()
      .split('')
      .reverse()
      .join('')
      .replace(/ /g, thousandsSeparator);
    formattedNumber = currencySymbol + formattedNumber + decimalMark + number.toFixed(2).substr(-2);
  } else {
    var formattedNumber = number.toFixed(0).split('').reverse().join('')
      .replace(/(...)/g, '$1 ')
      .trim()
      .split('')
      .reverse()
      .join('')
      .replace(/ /g, thousandsSeparator);
  }
  return formattedNumber;
}

给TA打赏
共{{data.count}}人
人已打赏
广告投放

谷歌购物关键字出价脚本

2021-10-17 18:13:39

广告投放

精确匹配脚本

2021-10-17 18:18:33

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索