分类目录归档:PLA Script

PLA Script: GMC Checker

/**
 *
 * GMC Disapproval Checker
 *
 * This script checks your Google Merchant Centre for disapproved products. It will send you emails if the percentage of
 * disapproved products exceeds a specified threshold. You need to select the Shopping Content api in the Advanced Apis
 * section to run this script.
 *
 * Google AdWords Script maintained on brainlabsdigital.com
 *
 */
​
​
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Options
​
var merchantId = 123456789;
// Replace this with your Merchant Center ID.
​
var threshold = 0.01;
// Percentage of disapproved products you would like to be alerted by.
// Do NOT include the percentage sign in this variable.
​
var email = ["[email protected]", "[email protected]", "[email protected]"];
// Email addresses to send the disapproval alert to.
// If there is more than one email they should be comma separated
// - e.g. ["[email protected]", "[email protected]"]
​
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Filters
// These two variables store the product ID's that we want to filter by.
// The ID's need to be in string format e.g. productIdToInclude = ["123"];
var productIdToInclude = [];
var productIdToExclude = [];
​
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Functions
​
function main() {
​
  var pageToken;
  var maxResults = 250;
  // These variables are used to fetch all the products (maximum of 250) on a page
  // in the merchant centre. We can then iterate over the pages by using the next
  // page token which is given as part of the response to our request.
​
  var totalProducts = 0;
  var numberDisapprovedProducts = 0;
​
  do {
    // This is a quick check to see if the filters supplied are valid
    checkFiltersDontContradict(productIdToInclude, productIdToExclude);
​
    var productStatuses = ShoppingContent.Productstatuses.list(merchantId, {
      pageToken: pageToken,
      maxResults: maxResults
    });
​
    // If the 'approvalStatus' of our product is not 'approved' then we say it is disapproved.
    if (productStatuses.resources) {
      for (var i = 0; i < productStatuses.resources.length; i++) {
        product = productStatuses.resources[i];
        if (satisfiesAllFilters(product)) {
          totalProducts += 1;
          if (product['destinationStatuses'][0]['approvalStatus'] == 'disapproved') {
            numberDisapprovedProducts++;
          }
        }
      }
    } else {
      Logger.log('No more products in account ' + merchantId);
    }
    // We then pull our next PageToken from our response and use it to make a new request.
    // If there is no next PageToken then we exit our iteration.
    pageToken = productStatuses.nextPageToken;
  } while (pageToken);
​
  disapprovalPercentage = (numberDisapprovedProducts * 100) / totalProducts;
  Logger.log(numberDisapprovedProducts + ' of ' + totalProducts 
             + ' products in your account were disapproved - ' 
             + disapprovalPercentage.toFixed(2) + '%')
​
  // If our threshold is exceeded then we assemble an email with details of the alert and send it to our contact emails.
  if (disapprovalPercentage >= threshold) {
​
    var subject = merchantId + ' GMC Disapproval Alert Email';
    var message = numberDisapprovedProducts + ' of ' + totalProducts
        + ' products in your GMC (' + merchantId + ') were disapproved - '
        + disapprovalPercentage.toFixed(2) + '%' + '\n';
​
    MailApp.sendEmail(email.join(','), subject, message);
    Logger.log('Message to ' + email.join(',') + ' sent.');
  }
}
​
function checkFiltersDontContradict(productIdToInclude, productIdToExclude) {
    if (productIdToInclude.length && productIdToExclude.length) {
        for(var i in productIdToInclude) {
            if(productIdToExclude.indexOf(productIdToInclude[i]) > -1) {
                throw "Filters have shared values - can not include and exclude simultaneously";
            }
        }
    } else {
        return true;
    }
}
​
function satisfiesAllFilters(product) {
  return (satisfiesIdIncludeFilters(productIdToInclude, product) 
          && satisfiesIdExcludeFilters(productIdToExclude, product));
}
​
function satisfiesIdIncludeFilters(productIdToInclude, product) {
  if(productIdToInclude.length) {
    return (productIdToInclude.indexOf(product['productId']) != -1);
  }
  else {
    return true;
  }
}
​
function satisfiesIdExcludeFilters(productIdToExclude, product) {
  if(productIdToExclude.length) {
      return (productIdToExclude.indexOf(product['productId']) == -1);
  }
  else {
    return true;
  }
}

PLA Script: 自动创建SPG系列

// Copyright 2020. Increase BV. All Rights Reserved.
//
// Created By: Tibbe van Asten
// for Increase B.V.
//
// Created 15-04-2019
// Last update: 14-01-2020
//
// ABOUT THE SCRIPT
// All products in the productfeed are checked for existance in the
// Google Shopping campaigns. If new, they're added to the right campaign
//
////////////////////////////////////////////////////////////////////
​
var config = {
​
  LOG : true,
​
  // Connect Merchant Center. Add user to MC that runs this script.
  // Also enable Advanced API 'Shopping content'.
  MERCHANT_ID : "123456789",
​
  // Set a default bid. This will be used for adgroups and products
  DEFAULT_BID : 0.75,
​
  // Set the target Campaigns.
​
  TARGET_CAMPAIGN : "_SPG"
}
​
////////////////////////////////////////////////////////////////////
​
function main(){
​
  // First off, we collect all productdata from Merchant Center.
  // We also check all active adgroups
  var products = connectMerchant();
  var activeProducts = activeAdGroups();
​
  var addProducts = {};
​
  // All products of the feed will be checked
  for (var i = 0; i < products.length; i++) {
​
    // If the products-Id is already the name of an existing adgroup, we don't add it.
    // If the product is out of stock, we don't add it.
​
    if(activeProducts.indexOf(products[i]["customLabel0"]) < 0){
      var productId = products[i]["customLabel0"];
​
      if (addProducts[productId] == null) {
        addProducts[productId] = [];
        
      }
      addProducts[productId].push([productId]);
    }
​
  } // for statement
​
    if(config.LOG === true){
      Logger.log("Found " + Object.keys(addProducts).length + " to be added");
      Logger.log(" ");
    }
​
  // Adding all products not already in the campaigns
  for (var key in addProducts) {
​
    var campaignSelector = AdsApp
      .shoppingCampaigns()
      .withCondition("Status = ENABLED");
    
    if(config.TARGET_CAMPAIGN != ""){
      campaignSelector = campaignSelector.withCondition("Name CONTAINS '" + config.TARGET_CAMPAIGN + "'");
    }
    
    var campaignIterator = campaignSelector.get();
​
    while(campaignIterator.hasNext()){
      var campaign = campaignIterator.next();
​
      // Adding adgroup to Shopping campaign
      var shoppingAdGroup = campaign
        .newAdGroupBuilder()
        .withName(addProducts[key][0][0])
        .withCpc(config.DEFAULT_BID)
        .withStatus("ENABLED")
        .build()
        .getResult();
​
        if(config.LOG === true){
          Logger.log(shoppingAdGroup.getName() + " added to " + campaign.getName());
        }
​
      // Adding an ad to the new adgroup
      var ad = shoppingAdGroup
        .newAdBuilder()
        .build()
        .getResult();
​
      // Creating the root productgroup 'All Products' and select it
      shoppingAdGroup.createRootProductGroup();
      var root = shoppingAdGroup.rootProductGroup();
​
      // Creating a productgroup for this product
      root.newChild().customLabelBuilder()
        .withBid(config.DEFAULT_BID)
        .withType('CUSTOM_LABEL_0')
        .withValue(addProducts[key][0][0])
        .build();
​
      // Making sure all other products in this adgroup are excluded
      var children = root.children().get();
      while (children.hasNext()) {
        var child = children.next();
        if (child.isOtherCase()) {
          child.exclude();
        }
      } // childrenIterator
​
    } // campaignIterator
​
  } // addProductsIterator
​
} // function main()
​
////////////////////////////////////////////////////////////////////
​
function activeAdGroups(){
​
  var activeProducts = [];
​
  // We will check if an adGroup with this ID as name already exists
  var adGroupIterator = AdsApp
    .shoppingAdGroups()
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("Status != REMOVED")
    .get();
​
  while(adGroupIterator.hasNext()){
    var adGroup = adGroupIterator.next();
    activeProducts.push(adGroup.getName().split(" - ")[0]);
  } // adGroupIterator
​
  return activeProducts;
​
} // activeAdGroups
​
////////////////////////////////////////////////////////////////////
​
function connectMerchant(){
​
  if(config.MERCHANT == "123456789"){
    throw Error("Change the Merchant ID in the settings");
  }
​
  var pageToken;
  var pageNum = 1;
  var maxResults = 250;
  var products = [];
​
  do {
    var productList = ShoppingContent.Products.list(config.MERCHANT_ID, {
      pageToken: pageToken,
      maxResults: maxResults
    });
​
    if (productList.resources) {
      for (var i = 0; i < productList.resources.length; i++) {
​
        // We only add products from Merchant Center when in stock
        if(productList.resources[i]["availability"] == "in stock"){
          products.push(productList.resources[i]);
        }
        
      }
    }
​
    pageToken = productList.nextPageToken;
    pageNum++;
  } while (pageToken);
​
  return products;
​
} // function connectMerchant

PLA Script: 自动添加转化词到PLA_Best否定列表

function main() {
  
  //How do you want to call your negative keyword list?
  var targetList = 'PLA_Best'
​
var now = new Date();
var timezone = AdWordsApp.currentAccount().getTimeZone();
var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
//var last90Days = new Date(now.getTime() - 90 * MILLIS_PER_DAY);  
//var sqrStartDate = Utilities.formatDate(last90Days, timezone, 'yyyyMMdd')
var firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
var sqrStartDate = Utilities.formatDate(firstDay, timezone, 'yyyyMMdd');
var sqrEndDate = Utilities.formatDate(new Date(), timezone, "yyyyMMdd")
​
var CPA_Threshold_Micro = 50; 
var CPA_Threshold = CPA_Threshold_Micro*1000000;
  
  var brand = 'your brand name'
​
  Logger.log('Report start date: '+sqrStartDate)
  Logger.log('Report end date: '+sqrEndDate.replace(/-/g,''))
  
  //let's build the negKw list if not existing yet  
  if(AdsApp.negativeKeywordLists().withCondition('Name = "'+targetList+'"').get().totalNumEntities()==1)
  {Logger.log('Negative list called '+targetList+' already exists!')}
  //else create the lsit
  else {
    Logger.log('Negative list called '+targetList+' does not exist yet - building now!')
    AdsApp.newNegativeKeywordListBuilder().withName(targetList).build()}
   
  //let's run search query report
  //keep in mind that cost numbers from API are multiplied by 1,000,000 for some reason - that's why I am multiplying by 1,000,000
  var reportText =
     'SELECT Query,Clicks,Cost,Ctr,ConversionRate,CostPerConversion,Conversions,ConversionValue,AllConversions,CampaignId,AdGroupId ' +
     'FROM SEARCH_QUERY_PERFORMANCE_REPORT ' +
     'WHERE Impressions > 0 AND Clicks > 0 AND Conversions > 0 AND CostPerAllConversion < '+CPA_Threshold+' AND CampaignName CONTAINS_IGNORE_CASE "PLA_" + AND Query DOES_NOT_CONTAIN_IGNORE_CASE "'+brand+'" ' +
     'DURING '+sqrStartDate+','+sqrEndDate
  
  Logger.log('Running this SQT Report now: ' + reportText)
  
  var queries = AdsApp.report(reportText);
  
  Logger.log('I am done with running the SQT Report.')
  
  var rows = queries.rows()
  
  //let's create negative kws as exact match
  var negKwsToAdd = []
  while(rows.hasNext()){
    var eachRow=rows.next()
    //Logger.log(eachRow["Query"])
    negKwsToAdd.push('['+eachRow["Query"]+']')
  }
  
  //start checking only there are bad terms to process
  if(negKwsToAdd.length>0){
    Logger.log('These terms are eligible to be added as exact negs: '+negKwsToAdd+'\n'+
              'However, checking if they are not in the list already.'
            )  
  
    //let's start comparing existing neg KWs in the list vs neg KWs which you want to add base on the latest run of search query report 
    var existingNegKws = []
​
    var lists = AdsApp.negativeKeywordLists().withCondition('Name = "'+targetList+'"').get()
    while(lists.hasNext()){
      list = lists.next()
​
      var allCurrentNegKws = list.negativeKeywords().get()
      while (allCurrentNegKws.hasNext()){
        negKwInTheList = allCurrentNegKws.next()
        existingNegKws.push(negKwInTheList.getText())
      }
    }
​
    if(existingNegKws.length==0){
      Logger.log(targetList+' is empty at the moment.')}
      else {Logger.log('These negative keywords are already present in the list: '+existingNegKws)}
​
    var checkedNegKwsToAdd = []
    var i=0
    for(i=0;i<negKwsToAdd.length;i++){
      //here is the main trick for array comparison
      if(existingNegKws.indexOf(negKwsToAdd[i])>-1){
        Logger.log(negKwsToAdd[i]+' is already in '+targetList)}
        else {checkedNegKwsToAdd.push(negKwsToAdd[i])}
      }
  }
  else{Logger.log('No bad terms to process - lucky you!')}
  
  if(checkedNegKwsToAdd.length>0){  
    Logger.log('These neg kws will be added into '+targetList+' list:'+checkedNegKwsToAdd)}
    else {Logger.log('No new neg kws will be added into '+targetList+'. All the eligibile KWs are already there!')}
​
​
    //Let's add the negative kewords into the target list
    if(checkedNegKwsToAdd.length>0){  
      var lists = AdsApp.negativeKeywordLists().withCondition('Name = "'+targetList+'"').get()
      while(lists.hasNext()){
        var list = lists.next()
        list.addNegativeKeywords(checkedNegKwsToAdd)
        Logger.log(checkedNegKwsToAdd+' added as neg KWs into '+targetList)
      }
    }
  }

PLA Script: 购买转化产品2X出价

function main() {
  
  var productGroups = AdsApp.productGroups()
  .withCondition("CampaignName IN ['S_PLA_US_XX', 'S_PLA_UK_XX']")
  .withCondition('AdGroupStatus = ENABLED')
  .withCondition("ProductGroup DOES_NOT_CONTAIN ' *'")
  .withCondition("Cost < 100")
  .withCondition("MaxCpc < 1")
  .withCondition("Conversions > 0")
  .forDateRange("ALL_TIME")
  .get();
  while (productGroups.hasNext()) {
    var productGroup = productGroups.next();
    productGroup.setMaxCpc(1);
  }
}

PLA Script: 加购转化产品1.5X出价

function main() {
  
  var productGroups = AdsApp.productGroups()
  .withCondition("CampaignName IN ['S_PLA_US_XX', 'S_PLA_UK_XX']")
  .withCondition('AdGroupStatus = ENABLED')
  .withCondition("ProductGroup DOES_NOT_CONTAIN ' *'")
  .withCondition("Cost < 100")
  .withCondition("MaxCpc < 0.75")
  .withCondition("AllConversions > 0")
  .forDateRange("ALL_TIME")
  .get();
  while (productGroups.hasNext()) {
    var productGroup = productGroups.next();
    productGroup.setMaxCpc(0.75);
  }
}