Keyword Match Type Validator

Controleer automatisch op problemen met zoekwoordtypen.

Start nu!
Keyword Match Type Validator
Keyword Get started!

Een zeer populaire manier om een Google Ads account te structureren, is door zoekwoorden in te delen op basis van zoekwoordtype in verschillende campagnes en/of advertentiegroepen. Je kan hetzelfde zoekwoord met verschillende zoekwoordtypen hebben in een andere campagne of advertentiegroep.

Als je een account op deze manier structureert, is het belangrijk om de juiste uitsluitingen te doen; exacte zoekwoorden kunnen in campagnes voor breed zoeken terechtkomen of andersom.

Dit script zorgt ervoor dat de zoekwoordtypen voor je zoekwoorden overeenkomen met het zoektype dat je bepaalt in de naamgeving van campagnes of advertentiegroepen. Als een bonus wordt ook gecontroleerd of zoekwoorden correct zijn opgemaakt voor de specifieke zoektypen (geen losse '+' tekens). 

Happy scripting!

 

INSTRUCTIES VOOR INSTALLATIE:

Maak je geen zorgen als je dit nog nooit eerder hebt gedaan. Je hebt geen programmeervaardigheden nodig. Het is zo simpel als kopiëren en plakken.
Volg deze instructies over hoe je Google Ads-scripts installeert.

In het script kan je het volgene instellen

  • SPREADSHEET_URL: Voeg een lege spreadsheet toe.
  • EMAIL_ADDRESS: Vul een e-mailadres in om de rapportage op te ontvangen.
  • CAMPAIGN_LABEL: Gebruik een label om campagnes te selecteren.
  • EXACT_MATCH_IDENTIFIER: Tekst in campagnenamen of advertentiegroep namen om exact match aan te geven.
  • BROAD_MATCH_IDENTIFIER: Tekst in campagnenamen of advertentiegroep namen om broad match aan te geven.
  • BROAD_MODIFIED_MATCH_IDENTIFIER : Tekst in campagnenamen of advertentiegroep namen om broad modified match aan te geven.

Frequentie: Laten we voor dagelijks gaan!

The script
// Copyright 2019, Nils Rooijmans, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


var SPREADSHEET_URL = "";  //insert a new blank spreadsheet url

var EMAIL_ADDRESS = ""; //insert your email
var EMAIL_SUBJECT = "[ALERT] - Keyword Match Type Issues";
    
var CAMPAIGN_LABEL = ""; // Leave blank for all campaigns 

// text in your campaign names and/or ad group names to indicate match type
var EXACT_MATCH_IDENTIFIER = '(exact)';
var BROAD_MATCH_IDENTIFIER = '(broad)';
var BROAD_MODIFIED_MATCH_IDENTIFIER = '(BMM)';

var LOG_ISSUE="yes" ; // Blank to stop use of Logger.log if lots of issues

var totalNrOfIssues = 0;
var issues =[];

function main() {
  
  //prepare the Spreadsheet
  var ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var sheet = ss.getActiveSheet();
  sheet.clear(); //remove earlies alerts
  var header = [
    "Account Name", 
    "Campaign Name",
    "Ad Group Name",
    "Keyword",
    "KeywordId",
    "Issue "
  ];
  sheet.appendRow(header);


  var campaignSelector = AdWordsApp.campaigns()
                          .withCondition("AdvertisingChannelType = SEARCH") // Search campaings only (no display/shopping, ...)    
                          .withCondition("CampaignTrialType = BASE") //skip Drafts and Experiments
                          .withCondition("Status = ENABLED") ;
    
  if (CAMPAIGN_LABEL!="") {
    campaignSelector=campaignSelector
       .withCondition("LabelNames CONTAINS_ANY ['"+CAMPAIGN_LABEL+"']");
  }
      
  var campaignIterator = campaignSelector.get();  
  var campaignIds=[] ;
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    campaignIds.push(campaign.getId()) ;
  }

 	checkKeywordMatchTypes(campaignIds);
  
  if (issues.length > 0) { // there is at least one issue
    var range = sheet.getRange(2, 1, issues.length, header.length);
    range.setValues(issues);
 
    var emailBody = 
      "Number of issues: " + issues.length + "\n" + 
      "See details: "+ SPREADSHEET_URL + "\n";
    MailApp.sendEmail(EMAIL_ADDRESS, EMAIL_SUBJECT, emailBody);
  }
}



function checkKeywordMatchTypes(campaignIds) {

  var accountName = AdWordsApp.currentAccount().getName();

  // Check Exact Match Ad Groups and Keywords 
  var awql="SELECT CampaignName, AdGroupName, Criteria, Id, KeywordMatchType FROM KEYWORDS_PERFORMANCE_REPORT WHERE CampaignId IN ["+campaignIds.join(",")+"] AND AdGroupStatus='ENABLED' AND Status='ENABLED'" ;  
  
  var rows=AdWordsApp.report(awql).rows() ;
    
  while (rows.hasNext()) {
    var row = rows.next();
    var campaignName = row['CampaignName'].toString().trim();
    var adGroupName = row['AdGroupName'].toString().trim();
    var keyword = row['Criteria'].toString().trim();
    var keywordId = row['Id'].toString().trim();
    var keywordMatchType=row['KeywordMatchType'].toString().trim() ;
    
    // Wrong matchtype in Exact match group
    if ( ( adGroupName.toString().toLowerCase().indexOf(EXACT_MATCH_IDENTIFIER.toLowerCase())>=0 || 
           campaignName.toString().toLowerCase().indexOf(EXACT_MATCH_IDENTIFIER.toLowerCase())>=0  
         ) && (keywordMatchType.toUpperCase() != 'EXACT') 
       ) {
     logIssue("Match type issue: "+adGroupName+" | "+keyword+" : KW has match type: "+row['KeywordMatchType']);
     issues.push([accountName, campaignName, adGroupName, keyword, keywordId, "Keyword Match Type issue"]);
    }
    else if ( adGroupName.toLowerCase().indexOf(BROAD_MODIFIED_MATCH_IDENTIFIER.toLowerCase())>=0 ||
              campaignName.toLowerCase().indexOf(BROAD_MODIFIED_MATCH_IDENTIFIER.toLowerCase())>=0
      ) {
      if (keywordMatchType.toUpperCase() != 'BROAD') {
        logIssue("Match type issue: "+adGroupName+" | "+keyword+" : KW has match type: "+row['KeywordMatchType']);
        issues.push([accountName, campaignName, adGroupName, keyword, keywordId, "Keyword Match Type issue"]);
      } else if (!isValidMBMKeyword(keyword)) {
        logIssue("Match type issue: "+adGroupName+" | "+keyword+" : KW is not a valid MBM keyword");
        issues.push([accountName, campaignName, adGroupName, keyword, keywordId, "MBM Keyword validation issue"]);
      }
    }
    else if ( adGroupName.toLowerCase().indexOf(BROAD_MATCH_IDENTIFIER.toLowerCase())>=0 ||
              campaignName.toLowerCase().indexOf(BROAD_MATCH_IDENTIFIER.toLowerCase())>=0
      ) { 
      if (keywordMatchType.toUpperCase() != 'BROAD')  {
        logIssue("Match type issue: "+adGroupName+" | "+keyword+" : KW has match type: "+row['KeywordMatchType']);
        issues.push([accountName, campaignName, adGroupName, keyword, keywordId, "Keyword Match Type issue"]);
      }
      else if (!isValidBroadKeyword(keyword)) {
        logIssue("Match type issue: "+adGroupName+" | "+keyword+" : KW is not a valid Broad keyword");
        issues.push([accountName, campaignName, adGroupName, keyword, keywordId, "Broad Keyword validation issue"]);
      }
    }
  }
  
  function isValidMBMKeyword(keyword) {
	
    if(!(keyword[0]=='+')) return false; // MBM keyword needs to start with a '+' 
    if(/\+ /.test(keyword)) return false; // MBM keyords can not have '+' followed by a space -> the '+' needs to be immediately in front of the terms in keyword
    if(/\w\+/.test(keyword)) return false; // MBM keyords can not have '+' that is immediately preceded by a " word character"  -> the '+' needs to be preceded by a space 
    if(/\s\w/.test(keyword)) return false; // All the terms in the keyword need to be preceded by a '+' , not a whitespace

    return true;
  }

  function isValidBroadKeyword(keyword) {
    if( (keyword.toString().indexOf("+") != -1) || 
        (keyword.toString().indexOf("[") != -1) ||
        (keyword.toString().indexOf("]") != -1) ||
        (keyword.toString().indexOf('\"') != -1) 
      ) {
      Logger.log("  * Keyword is Unvalid Broad type");
      return false;
    }
    return true;
  }
  
  function logIssue(msg) {
    if (LOG_ISSUE!="") {
      Logger.log(msg) ;
    }
  }
}
Show whole script!
Loading Comments
The Experts
Tibbe van Asten Team Lead Performance Marketing
Nils Rooijmans Water Cooler Topics
Martijn Kraan Freelance PPC Specialist
Bas Baudoin Teamlead SEA @ Happy Leads
Jermaya Leijen Digital Marketing Strategist
Krzysztof Bycina PPC Specialist from Poland
How about you? JOIN US!
Sharing Knowledge
Caring

Adsscripts.com staat voor het delen van kennis. In de huidige markt houden SEA-specialisten de kennis en ervaring graag voor zich. Wij zijn er van overtuigd dat het delen van kennis ervoor kan zorgen dat iedereen beter wordt in haar of zijn werk. Daarom lopen wij hier graag in voorop, door onze kennis over scripts te delen met iedereen.

Wil jij ook graag een bijdrage leveren? Wij staan open voor nieuwe ideeën en feedback op alles wat je op Adsscripts.com vindt.

Neem contact op

Training &
Workshop
Neem contact op!
Adsscripts Training & Workshop