This script takes your existing ad content, then mixes up the headlines and descriptions to create new ad variants. It’s perfect for testing which ad variants work best.

Very often the best test is simply trying out elements in different orders, headline 2 might actually work best in the headline 1 position. Taking inspiration from the MVT testing you get from A/B testing tools, this enables just that.

Setup

  1. Enter your campaign names as a comma separated list where specified
  2. You may want certain text, such as a price, always appearing in Headline 1. If that’s the case, enter the text in between the quotes
  3. Done. You can either schedule this to run weekly for regularly refreshed ads, or hit the Run button when you’re feeling particularly lazy
var campaignNames = ["Campaign A"]; //comma separated e.g. ["campaign1", "campaign2"]
var headlineFilter = "Sale"; //Headline 1 filter: new ads must include this text in headline 1, otherwise don't create them. Text, e.g. "Sale"

function main() {
addAds();
}

function addAds(){
  
for(var campaignName_i in campaignNames){
    
var campaignName = campaignNames[campaignName_i];
var adGroupIterator = AdWordsApp.adGroups().withCondition("Status = ENABLED").withCondition("CampaignName = '"+campaignName+"'").get();
  
  while (adGroupIterator.hasNext()) {    
    var adGroup = adGroupIterator.next();
    var headline1 = [];
    var headline2 = [];
    var path1 = [];
    var path2 = [];
    var description = [];
    var url = [];
    var full_ad = [];
    

    var adIterator = adGroup.ads().	withCondition("Status = ENABLED").get();
    while(adIterator.hasNext()){
      var ad = adIterator.next();
      
       headline1.push(ad.getHeadlinePart1());
       headline2.push(ad.getHeadlinePart2());
       path1.push(ad.getPath1());
       path2.push(ad.getPath2());
       description.push(ad.getDescription());
       url.push(ad.urls().getFinalUrl());
       full_ad.push(String(headline1[headline1.length-1]+headline2[headline1.length-1]+path1[headline1.length-1]+path2[headline1.length-1]+description[headline1.length-1]));
      
    }
  
    Logger.log("current live ads:");
    for(var current_live_i in full_ad){
      Logger.log(full_ad[current_live_i]); 
    }
    //loop through ads, create every possible variant, check if they already exist first then go live!
    

    var no_ads = description.length;
    var loop_no = 0;
    var new_ads = [];
    Logger.log("No of ads: " + no_ads);
    //loop through current ads
    //create every possible variant
    //if !exist, then create
    
    if(no_ads == 1){
      Logger.log("only 1 ad, swap headlines");
      
      var description_new = description[0];//0, 1, 2...
      var headline2_new = headline2[0];//0, 1, 2...
      var path1_new = path1[0];
      var path2_new = path2[0];
      var headline1_new = headline2[0];
      var headline2_new = headline1[0];
      
      var url_new = url[0];//not included in full_ad variable
      var full_ad_new = headline1_new+headline2_new+path1_new+path2_new+description_new;
    
   
         adGroup.newAd().expandedTextAdBuilder()
        .withHeadlinePart1(headline1_new)
        .withHeadlinePart2(headline2_new)
        .withDescription(description_new)
        .withPath1(path1_new)
        .withPath2(path2_new)
        .withFinalUrl(url_new)
        .build();
      new_ads.push(full_ad_new);
      
    }else{
    
    
    for(var ad_text in full_ad){
      
      for(var i = 0;i<4;i++){
        loop_no++;
        
        if(i==0){
          
      Logger.log("start by mixing the descriptions up");
      var headline1_new = headline1[ad_text];//0, 1, 2...
      var headline2_new = headline2[ad_text];//0, 1, 2...
      var path1_new = path1[ad_text];
      var path2_new = path2[ad_text];
      Logger.log(parseInt(ad_text));
      if(ad_text==parseFloat(no_ads-1)){
        Logger.log("reached last ad, go back to beginning");
        var description_new = description[0];
      }else{
        var description_new = description[parseInt(ad_text)+1];
      }
      Logger.log(parseInt(ad_text)+1);
      
      var url_new = url[ad_text];//not included in full_ad variable
      var full_ad_new = headline1_new+headline2_new+path1_new+path2_new+description_new;
      Logger.log("current ad: "+full_ad[ad_text]);
      Logger.log("new possible ad: "+full_ad_new);
          
        }else if(i == 1){
          Logger.log("then mix headline 1 up");
          
          var description_new = description[ad_text];//0, 1, 2...
      var headline2_new = headline2[ad_text];//0, 1, 2...
      var path1_new = path1[ad_text];
      var path2_new = path2[ad_text];
      Logger.log(parseInt(ad_text));
      if(ad_text==parseFloat(no_ads-1)){
        Logger.log("reached last ad, go back to beginning");
        var headline1_new = headline1[0];
      }else{
        var headline1_new = headline1[parseInt(ad_text)+1];
      }
      
      Logger.log(parseInt(ad_text)+1);
      
      var url_new = url[ad_text];//not included in full_ad variable
      var full_ad_new = headline1_new+headline2_new+path1_new+path2_new+description_new;
      Logger.log("current ad: "+full_ad[ad_text]);
      Logger.log("new possible ad: "+full_ad_new);
      //avoid both headlines being the same
          if(headline1_new == headline2_new){
          Logger.log("headlines are the same, breaking...");
            break;
          }
        }else if(i == 2){
          Logger.log("then mix headline 2 up");
          
          var description_new = description[ad_text];//0, 1, 2...
      var headline1_new = headline1[ad_text];//0, 1, 2...
      var path1_new = path1[ad_text];
      var path2_new = path2[ad_text];
      Logger.log(parseInt(ad_text));
      if(ad_text==parseFloat(no_ads-1)){
        Logger.log("reached last ad, go back to beginning");
        var headline2_new = headline2[0];
      }else{
        var headline2_new = headline2[parseInt(ad_text)+1];
      }
      
      Logger.log(parseInt(ad_text)+1);
      
      var url_new = url[ad_text];//not included in full_ad variable
      var full_ad_new = headline1_new+headline2_new+path1_new+path2_new+description_new;
      Logger.log("current ad: "+full_ad[ad_text]);
      Logger.log("new possible ad: "+full_ad_new);
      //avoid both headlines being the same
          if(headline1_new == headline2_new){
          Logger.log("headlines are the same, breaking...");
            break;
          }
        }else if(i == 3){
          Logger.log("then mix headline 1 and 2 up");
          
          var description_new = description[ad_text];//0, 1, 2...
      var headline1_new = headline2[ad_text];//0, 1, 2...
      var path1_new = path1[ad_text];
      var path2_new = path2[ad_text];
      Logger.log(parseInt(ad_text));
      if(ad_text==parseFloat(no_ads-1)){
        Logger.log("reached last ad, go back to beginning");
        var headline2_new = headline1[0];
      }else{
        var headline2_new = headline1[parseInt(ad_text)+1];
      }
      
      Logger.log(parseInt(ad_text)+1);
      
      var url_new = url[ad_text];//not included in full_ad variable
      var full_ad_new = headline1_new+headline2_new+path1_new+path2_new+description_new;
      Logger.log("current ad: "+full_ad[ad_text]);
      Logger.log("new possible ad: "+full_ad_new);
      //avoid both headlines being the same
          if(headline1_new == headline2_new){
          Logger.log("headlines are the same, breaking...");
            break;
          }
        }else if(i == 4){
          Logger.log("then mix headline 2 and 1 up");
          
          var description_new = description[ad_text];//0, 1, 2...
      var headline2_new = headline1[ad_text];//0, 1, 2...
      var path1_new = path1[ad_text];
      var path2_new = path2[ad_text];
      Logger.log(parseInt(ad_text));
      if(ad_text==parseFloat(no_ads-1)){
        Logger.log("reached last ad, go back to beginning");
        var headline1_new = headline2[0];
      }else{
        var headline1_new = headline2[parseInt(ad_text)+1];
      }
      
      Logger.log(parseInt(ad_text)+1);
      
      var url_new = url[ad_text];//not included in full_ad variable
      var full_ad_new = headline1_new+headline2_new+path1_new+path2_new+description_new;
      Logger.log("current ad: "+full_ad[ad_text]);
      Logger.log("new possible ad: "+full_ad_new);
      //avoid both headlines being the same
          if(headline1_new == headline2_new){
          Logger.log("headlines are the same, breaking...");
            break;
          }
        }
    
    
    //check for duplicates
    //build new ads
  var match = false;
    for(var current_ad_i in full_ad){
             
        if(full_ad[current_ad_i] == full_ad_new){
        
        Logger.log("duplicate ad, don't create");
        match = true;
        break;
          
        }
      
    }
    
    if(!match){
      
         Logger.log("not a duplicate, creating ad...");
      
      //check ad hasn't already been generated within the script
      if(new_ads.indexOf(full_ad_new)<0){ Logger.log("ad does not exist, add"); if((headlineFilter == "") || (headline1_new.indexOf(headlineFilter)>=0 || headline2_new.indexOf(headlineFilter)>=0 )){
        Logger.log("passed final headline checks, create ad");
         adGroup.newAd().expandedTextAdBuilder()
        .withHeadlinePart1(headline1_new)
        .withHeadlinePart2(headline2_new)
        .withDescription(description_new)
        .withPath1(path1_new)
        .withPath2(path2_new)
        .withFinalUrl(url_new)
        .build();
      new_ads.push(full_ad_new);
        }
      }
        
        
      
    }
        
   
      
   }
    

    }
      
    }
 
    
  }
    
  Logger.log("all new ads: ");
  for(var n in new_ads){
   Logger.log(new_ads[n]); 
  }
    
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *