Keyword Quality Rapport

Identificeer de zoekwoorden in je account waar de kwaliteit van de advertentie of landingspagina verbeterd moet worden.

Start nu!
Keyword Quality Rapport
Keyword Get started!

Als onderdeel van de kwaliteitsscore die elk zoekwoord in je account toegewezen krijgt, worden een aantal statistieken gebruikt die je terug kan vinden in je account. Het gaat dan om de volgende metrics:

  • Advertentierelevantie
  • Kwaliteit van de landingspagina
  • Verwachte CTR
  • Bouncerate
  • Time on Site (TOS)

Instellingen

In het config-gedeelte van het script, kan je meerdere waarden aanpassen naar wens.

  • LOG: Wijzig dit in 'true' om te zien wat er precies gebeurd. Laat op 'false' staan wanneer het script echt draait, want dat gaat sneller.
  • THRESHOLD_IMPRESSIONS: wijzig dit aantal als je van mening bent dat je meer vertoningen nodig hebt om goede statistieken te kunnen verzamelen.
  • DATE_RANGE: Heeft effect op de voorgaande variabele. Het script kijkt naar het aantal impressies in het gespecificeerde tijdsvak.
  • ACCOUNT_LABEL: Gebruik deze om specifieke accounts te selecteren.
  • KEYWORD_LABEL: Wordt op elk zoekwoord toegepast wanneer deze is opgenomen in de sheet, om dubbelen te voorkomen. Deze kan je naar wens aanpassen, het script maakt het label aan wanneer deze niet bestaat.
  • THRESHOLD_BOUNCE: Het zoekwoord moet minimaal deze bouncerate hebben om gerapporteerd te worden.
  • THRESHOLD_TOS: Het zoekwoord mag maximaal deze time on site (in seconden) hebben om gerapporteerd te worden.
  • SPREADSHEET_URL: Maak een kopie van deze spreadsheet en vul de URL hier in, om de resultaten van het script in te zetten.

MCC niveau

Onderstaand script kan gebruikt worden op MCC-niveau, zodat je per account een tabblad in een Google Sheet krijgt met daarin de zoekwoorden waar je verbeteringen bij kan doorvoeren. Bij de accountSelector filter ik alle accounts die het label 'Active' krijgen in je MCC. Als je dit niet wilt, kan je regel 43 verwijderen uit het script. Daarnaast wordt er aan elk zoekwoord een label gehangen, wanneer ze in het rapport worden opgenomen. Hierdoor komen zoekwoorden niet meerdere keren terug in de sheet. 

Frequentie: Draai dit script elk uur, want het kan even duren voordat alle zoekwoorden van alle accounts doorlopen zijn.

The script
// Copyright 2020. Increase BV. All Rights Reserved.
// Not to be used without permission of the creator or Increase B.V.
//
// Created By: Tibbe van Asten
// for Increase B.V.
//
// Created: 29-11-2018
// Last update: 17-08-2020
//
// 17-08-2020: Added Keyword Match Type (idea by Arjan Schoorl)
//
// ABOUT THE SCRIPT
// With this script, we will create a report with all keywords
// in your accounts that have quality issues.
//
// Link to script: https://adsscripts.com/scripts/google-ads-scripts/report-keyword-quality
//
// ------------------------------------------------------------

// Script settings
var config = {

  LOG : false,

  THRESHOLD_IMPRESSIONS : 20,
  DATE_RANGE : "LAST_30_DAYS",

  ACCOUNT_LABEL : "Active",
  KEYWORD_LABEL : "Keyword - Quality - Issue",

  THRESHOLD_BOUNCE : 80,
  THRESHOLD_TOS : 20,

  // Copy from http://tinyurl.com/y536ld89
  SPREADSHEET_URL : "XXX",

  API_VERSION : "v201809"
}

// ------------------------------------------------------------

function main() {

  var ss = connectSheet();

  // Selecting all Ads Accounts
  var accountIterator = AdsManagerApp
    .accounts()
    .withCondition("LabelNames CONTAINS '" + config.ACCOUNT_LABEL + "'")
    .get();

  while(accountIterator.hasNext()){
    var account = accountIterator.next();
    MccApp.select(account);

        Logger.log("Account: " + account.getName());
        Logger.log("-----");

    // Create a label when it doesn't already exists
    keywordLabel(account);
    var label = AdsApp.labels().withCondition("Name = '" + config.KEYWORD_LABEL + "'").get().next();

    // Check if a sheet already exists for this account
    var sheet = checkSheet(ss, account);

    // Selecting all keywords
    var report = AdsApp.report(
      "SELECT AccountDescriptiveName, CampaignName, AdGroupName, AdGroupId, Criteria, KeywordMatchType, Id, BounceRate, AverageTimeOnSite, FinalUrls, CpcBid, SearchPredictedCtr, CreativeQualityScore, HistoricalLandingPageQualityScore, Clicks " +
      "FROM KEYWORDS_PERFORMANCE_REPORT " +
      "WHERE LabelIds CONTAINS_NONE [" + label.getId() + "] " +
      "AND CampaignStatus = ENABLED " +
      "AND AdGroupStatus = ENABLED " +
      "AND Status = ENABLED " +
      "AND Impressions > " + config.THRESHOLD_IMPRESSIONS +
      " DURING " + config.DATE_RANGE
    );

    var rows = report.rows();
    while (rows.hasNext()) {
      var row = rows.next();

      reportRows(row, sheet);

    } // row iterator

    	Logger.log(account.getName() + " afgerond");

  } // account iterator

} // function main()

// ------------------------------------------------------------

function reportRows(row, sheet){

  // Checking a couple of variables, to make sure everything works as expected
  var bounceRate = checkBounce(row);
  var tos = checkTos(row)

  if((tos < config.THRESHOLD_TOS && tos != "") || bounceRate > config.THRESHOLD_BOUNCE || row["SearchPredictedCtr"] == "Below average" || row["CreativeQualityScore"] == "Below average" || row["HistoricalLandingPageQualityScore"] == "Below average"){

    if(config.LOG == true){
      Logger.log("Keyword: " + row["Criteria"]);
      Logger.log("TOS: " + row["AverageTimeOnSite"]);
      Logger.log("Bounce: " + row["BounceRate"]);
      Logger.log("Ad Quality: " + row["CreativeQualityScore"]);
      Logger.log("LP Experience: " + row["HistoricalLandingPageQualityScore"]);
      Logger.log("Exp. CTR: " + row["SearchPredictedCtr"]);
      Logger.log(" ");
    }

    // Checking the final URL of a keyword. If not set, we will find the URL of the best performing ad in the adgroup
    var finalUrl = findUrl(row);

    // Now we put all the info in the sheet
    sheet.appendRow([row["AccountDescriptiveName"],row["CampaignName"],row["AdGroupName"],row["AdGroupId"],"'" + row["Criteria"],row["KeywordMatchType"],row["Id"],bounceRate,row["CreativeQualityScore"],row["HistoricalLandingPageQualityScore"],row["SearchPredictedCtr"],tos,row["CpcBid"],finalUrl]);

    // Label the keyword, so we know it's processed
    labelKeywords(row["AdGroupId"], row["Id"]);

  } // keyword selection

} // function reportRows

// ------------------------------------------------------------

function findUrl(row){

  if(row["FinalUrls"] == "--"){

    var keywordIterator = AdsApp
    .keywords()
    .withIds([[row["AdGroupId"], row["Id"]]])
    .get();

    while(keywordIterator.hasNext()){
      var keyword = keywordIterator.next();
      var finalUrl = keyword.getAdGroup().ads().orderBy("Ctr DESC").forDateRange(config.DATE_RANGE).withLimit(1).get().next().urls().getFinalUrl();

    } // keyword iterator

  } else {
    var finalUrl = row["FinalUrls"];
  }

  return finalUrl;

} // function findUrl()

// ------------------------------------------------------------

function checkBounce(row){

  if(row["Clicks"] >= 10){
    var bounceRate = parseInt(row["BounceRate"]);
  } else {
  	var bounceRate = "";
  }

  return bounceRate;

} // checkBounce()

// ------------------------------------------------------------

function checkTos(row){

  if(row["Clicks"] >= 10){
    var tos = parseInt(row["AverageTimeOnSite"]);
  } else {
  	var tos = "";
  }

  return tos;

} // function checkTos()

// ------------------------------------------------------------

function keywordLabel(account){

  if(!AdsApp.labels().withCondition("Name = '"+config.KEYWORD_LABEL+"'").get().hasNext()) {
    AdsApp.createLabel(config.KEYWORD_LABEL);

    	if(config.LOG == true){
    		Logger.log("Label " + config.KEYWORD_LABEL + " created");
        }
  }

} // function keywordLabel()

// ------------------------------------------------------------

function labelKeywords(adGroupId, keywordId){

  var keywordIterator = AdsApp
  	.keywords()
  	.withIds([[adGroupId, keywordId]])
 	.get();

  while(keywordIterator.hasNext()){
    var keyword = keywordIterator.next();
    keyword.applyLabel(config.KEYWORD_LABEL);

    	if(config.LOG == true){
    		Logger.log("Label toegepast op " + keyword.getText());
          	Logger.log(" ");
        }

  } // keyword iterator

} // function labelKeywords

// ------------------------------------------------------------

function connectSheet(){

  var ss = SpreadsheetApp.openByUrl(config.SPREADSHEET_URL);
  return ss;

} // function connectSheet()

// ------------------------------------------------------------

function checkSheet(ss, account){

  var sheet = ss.getSheetByName(account.getName());

  	if (sheet == null) {
      var templateSheet = ss.getSheetByName("Template");
      ss.insertSheet(account.getName(), {template: templateSheet});
      var sheet = ss.getSheetByName(account.getName());

      	Logger.log("New sheet created for " + account.getName());

    } // if sheet doesn't exists

  return sheet;

} // checkSheet()
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