Paid Search (PPC)

We're giving away a free copy of our script that converts your AdWords keyword match type from Broad Match to Broad Match Modified. If you want to make your campaigns better targeted and save your money, then this script could do the trick.

The AdWords Broad Match feature is designed to save you time by matching a few keywords against the whole universe of related key phrases and give the ability to reach masses of keywords quickly and efficiently.

For example, using Broad Match for the keywords flower delivery will also display your ads for searches for related phrases like wedding flowers and English roses.

But Broad Match will can give unintended consequences. Broad Match for the keywords sell timeshare would also match the related keywords buy timeshare which of course is the exact opposite of the advertiser’s intention.

This is why we always recommend converting all Broad keywords to Broad Match Modified (BMM). BMM means that the words have to be in the search query, but in any order. This ensures the intent always stays roughly consistent.

AdWords Match Types for AdWords scripts

For more information read our guide on AdWords keyword match types

If you are in any doubt, we have written a guide to show you which keywords are triggering your ads.

In addition, given that Modified Broad is a typed format (as opposed to a drop down option), it’s much more common to get formatting errors. These can cause your queries to operate as if they are Broad Match, even if you didn’t intend them to.

AdWords Broad Match Formatting Errors: The Fix

There are three possibilities of formatting errors. The first two will cause problems in triggering as there are words AdWords isn’t expecting. They are a missing space – ‘+one+two +three’ or one or more additional spaces – ‘+one + two +three’. There is also the potential to miss a + out of a word. This will make AdWords think you want to use the broader modified Broad Match, sometimes called Anchored Broad Match.

In my experience, most PPC professionals tend not to use this format. Or if they do it is unnecessary e.g. +horse and +carriage +hire (Google will account for &s etc as close variants for all match types). Therefore this script makes the assumption that anything in this format is an accident.

Obviously, this isn’t always going to be the case, so if you know you use Anchored Broad Match you can still use the script in “report only mode”. In this mode, the script won’t make any changes, but just spits out a Google sheet with the things it thinks are errors and lets you correct any errors in your own time. See the How To Use section for details on how to activate this mode.

Now, this isn’t going to revolutionise any account and provide huge gains. However, these little efficiency increases stack up and can influence real improvement.

How To Use this AdWords Broad Match Modified Script

To use, first put the code into the scripts library in your AdWords account. If you’ve not done that before then check out this handy guide.

Once the script is in your library simply make a blank google sheet, then grab the link that allows a user to edit it and copy-paste it into the code on line 11 where it says “INSERT URL HERE”. If you’ve renamed the sheet, put the new sheet name in line 14 – the case is important here. Then just select whether you’d like the code to run in “report only mode” or not and you’re good to go.

Editable code segments

Change the text within the quotation marks to change the configuration

Finally, remember the golden rule of working with new scripts: always preview the script before running it. This makes sure you know what it’s going to do before it actually executes.

How The Script Works

The main principle behind the code’s operation is that it expects all keywords with a “+” to be formatted ‘+one +two +three’. If it is in that format there will always be one more “+” than “ ”, regardless of the number of words. Therefore, if there is anything other than a difference of one, there is an issue.

This issue can then be corrected by using a robust technique that will convert any phrase into the BMM format, using “_” as a space for clarity:

  • Start with some poor thing like:             ‘+one+two_+_three’
  • Convert all plusses into spaces:              ‘_one_two___three’
  • Remove any duplicate spaces:                ‘_one_two_three’
  • Convert all spaces into space-plus:        ‘_+one_+two_+three’
  • Remove the spare space on the front:   ‘+one_+two_+three’

All the code is heavily commented, so I would recommend anyone who has an interest in scripts but no experience writing their own to take a look at it to see how a simple script like this operates.

Conclusion

To sum up, this is a neat little script that can quickly check if you have any minor errors in your accounts. It is also useful as an example of an easy intro to scripts to give you an idea of how they operate and the kind of tasks that they can accomplish. If you have any questions feel free to leave them in the comments right here on the blog and I’ll get straight back to you,  or contact me on twitter @JonathanCatton.

With all the niceties aside let me present the code in question:

function main() {
  correctBroadMatchModified()
}

function correctBroadMatchModified() {
  
  //---------------------------------------------------------------------------------------------------------------------------//
  //Options Area/////////////////////////////////////////////////////////////////////////////////////////////////////////
  
  //Enter the URL of a google spreadsheet you'd like to export the changes to
  var SPREADSHEET_URL = "INSERT URL HERE";
  //Enter the name of the sheet you'd like to export the changes to. 
  //Case is important.
  var SHEET_NAME = "Sheet1"
  
  //Change the variable below to NO to turn off report only mode
  //or YES to turn it on.
  var reportOnlyMode = "YES"
  
  //Working Code Below. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  //-------------------------------------------------------------------------------------------------------------------------//
  

  //Selects active broad match keywords with +s
  var keywordSelector = AdWordsApp 
  .keywords()
  .withCondition("Status = ENABLED")
  .withCondition("AdGroupStatus = ENABLED")
  .withCondition("CampaignStatus = ENABLED")
  .withCondition("KeywordMatchType = BROAD")
  .forDateRange("ALL_TIME")
  .orderBy("Clicks DESC");

  
  var keywordIterator = keywordSelector.get(); 
  //gets the list of keywords from the selector
  var keywordList = []
    while (keywordIterator.hasNext()) {
      //selects a keyword
      var keyword = keywordIterator.next(); 
      //gets the text of the keyword
      var keywordText = keyword.getText(); 
      
      
      //Detection of BMM Error section
      //check to see if there is no + on the front
      var notStartsWithPlus = keywordText[0] !== "\+";
      //string without spaces
      var withoutSpaces = keywordText.replace(/ /g,"");
      //string without +s 
      var withoutPlus = keywordText.replace(/\+/g,"") 
      //keywordText.length-withoutPlus.length produces count
      //of plusses same thing with spaces
      //If formatted correctly there should be one more plus than space
      var missingPlus = (keywordText.length - withoutPlus.length)-(keywordText.length - withoutSpaces.length)
      
      //Starts with special case of not starting with a plus. 
      //It is a special case as it needs an extra step to fix 
      //than if the error is anything else
      if (notStartsWithPlus) {
        //gets keyword Match Type
        var matchType = keyword.getMatchType(); 
        //gets the keyword id
        var keywordId = keyword.getId(); 
        //gets the bidding details
        var keywordBidding = keyword.bidding(); 
        //gets the current Max CPC
        var keywordCPC = keywordBidding.getCpc(); 
        //gets the adgroup data which this keyword belongs to
        var adGroup = keyword.getAdGroup(); 
        //gets the id of the aforementioned adGroup
        var adGroupId = adGroup.getId(); 
        // gets the name of the adgroup
        var adGroupName = adGroup.getName(); 
        // gets the details of the campaign
        var campaign = adGroup.getCampaign(); 
        // gets the name of the campaign
        var campaignName = campaign.getName(); 
        
        //function to correct BMM
        var correctedBMM = fixBroadMatch(keywordText); 
        //Extra step to add + at the start as function doesn't deal with this.
        correctedBMM = "\+" + correctedBMM; 
        //outputs the keyword in an array
        keywordList.push([keywordText,matchType,correctedBMM,adGroupName,campaignName,adGroupId,keywordId]); 
        
        Logger.log("Original Keyword = " + keywordText);
        Logger.log("Corrected Keyword = " + correctedBMM);
        
        //Check for Report Only Mode
        if (reportOnlyMode != "YES") {
          //Pauses current faulty keyword
          keyword.pause()
          //Creates new keyword with correct formatting but same bid
          var newkeyword = adGroup.newKeywordBuilder()
          .withText(correctedBMM)
          .withCpc(keywordCPC)
          .build();
        }
        continue; //breaks out of the if case to prevent double triggering
        
        //General case triggered where the difference 
        //between spaces and plusses =/= 1
      } else if (missingPlus !== 1) {
        
        //gets the keyword Match Type
        var matchType = keyword.getMatchType(); 
        //gets the keyword id
        var keywordId = keyword.getId(); 
        //gets the bidding details
        var keywordBidding = keyword.bidding(); 
        //gets the current Max CPC
        var keywordCPC = keywordBidding.getCpc(); 
        //gets the adgroup data which this keyword belongs to
        var adGroup = keyword.getAdGroup(); 
        //gets the id of the aforementioned adGroup
        var adGroupId = adGroup.getId(); 
        // gets the name of the adgroup
        var adGroupName = adGroup.getName(); 
        // gets the details of the campaign
        var campaign = adGroup.getCampaign(); 
        // gets the name of the campaign
        var campaignName = campaign.getName(); 
        
        //Correct the broad match to be in the format '+word +word +word'
        var correctedBMM = fixBroadMatch(keywordText);
        //outputs the keyword in an array
        keywordList.push([keywordText,matchType,correctedBMM,adGroupName,campaignName,adGroupId,keywordId]); 
        
        Logger.log("Original Keyword = " + keywordText)
        Logger.log("Corrected Keyword = " + correctedBMM)
        
        //Check for Report Only Mode
        if (reportOnlyMode != "YES") {
          //Pause faulty keyword
          keyword.pause()
          //Build new keyword with correct format and same bid
          var newkeyword = adGroup.newKeywordBuilder()
          .withText(correctedBMM)
          .withCpc(keywordCPC)
          .build();
        }
        
      }
      
    }

  //Define headers of spreadsheet (Check ordering matches keyword list)
  var headers = ["Keyword", "Match Type", "Corrected Keyword","AdGroup", "Campaign", "AdGroup Id", "Keyword Id"]; 
  //activate the exporting to spreadsheet function
  writeToSpreadsheet(keywordList,headers,SPREADSHEET_URL,SHEET_NAME)
}


function fixBroadMatch(keywordText) {
  //turn all +s into spaces
  var allSpaces = keywordText.replace(/\+/g," "); 
  //delete all duplicate spaces (now looks like normal text but with space at front)
  var oneSpace = allSpaces.replace(/( )(?=\1)/gi,""); 
  //turn all spaces into a space plus (i.e. "_" --> "_+")
  var allSpacePlus = oneSpace.replace(/ /g," \+"); 
  //delete the first character if its a space.
  var correctedBMM = allSpacePlus.replace(/^ /,""); 
  return(correctedBMM)
}

//exporting to spreadsheet function
function writeToSpreadsheet(keywordList,headers,SPREADSHEET_URL2,SHEET_NAME2,B,errorCheck) {
  var spreadsheet;
  //Open previously created spreadsheet
  spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL2);
  //Select sheet to edit based on name provided
  var sheet = spreadsheet.getSheetByName(SHEET_NAME2);
  //Clear selected sheet
  sheet.clearContents();
  //Add Headers
  sheet.appendRow(headers);
  //Find last row currently in sheet (aka row 1 as the headers are in)
  var lastRow = sheet.getLastRow();
  //select the range sarting from below headers where keywordList.length provides
  //the number of rows needed and keywordList[0].length provides the columns needed
  //only if the list has values to avoid errors
  if (keywordList.length > 0) {
    var range = sheet.getRange(lastRow+1,1,keywordList.length,keywordList[0].length);
    range.setValues(keywordList); //set the range to equal the values extracted from adwords
    Logger.log("Report can be found at " + SPREADSHEET_URL2)
  } else {
    Logger.log("There were no keywords that required changing")
  }
}

One response to “Broad Match To Modified Broad Match AdWords Script”

  1. Matt says:

    Missing ) after condition. (line 183)

Leave a Reply

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