Add search queries as keywords

Add search terms as a keyword when they perform well. An easy way to expand an account.

Start Now!
Add search queries as keywords
Add search Get started!

When optimizing campaigns in Google Ads, the search query report is often included. Search queries are excluded based on performance and common sense, but often there are also keywords that you can add to your adgroup. This gives you more control over the performance of these specific search queries, because you can adjust bids as desired.

With the script below you can automate this process. Based on the performance of a keyword, it is automatically added when the performance is good enough. You set the minimum requirements for impressions, clicks, conversions, CTR, CPA and cost yourself. This gives you control over the keywords that the script will actually add to the adgroup.

The script also checks whether the exact keyword that it wants to add is not already present elsewhere in the account. This way, the script will not affect the structure of the account.

Settings

  • LOG: Specify whether the script should report the intermediate steps, by adjusting the value to 'true'.
  • DATE_RANGE: Set the daterange the script will collect data on. Change the number insinde last_n_days().
  • IMPRESSIONS_THRESHOLD: Set the minimum number of impressions.
  • IMPRESSIONS_THRESHOLD: Set the minimum number of clicks.
  • CONVERSIONS_THRESHOLD: Set the minimum number of conversions.
  • CTR_THRESHOLD: Set the minimal CTR.
  • CPA_THRESHOLD: Set the maximum CPA.
  • COST_THRESHOLD: Set the minimal cost.

Frequency: Depending on the size of the account, we suggest you run this script only once a day.
BEWARE: By default, Google collect searchqueries in lowercase. When your keywords contain capitalization, this script might add queries that are already in your account. Make sure all your keywords are in lowercase.

The script
// Copyright 2020. Increase BV. All Rights Reserved.
//
// Original script by Remko van der Zwaag
// That was based on a Google example script: http://goo.gl/aunUKV
// Rewritten by: Tibbe van Asten
//
// Created: 22-05-2020
// Last update: 24-05-2020
//
// ABOUT THE SCRIPT
// This script checks all search queries in your account. Based
// on your own theresholds, these queries can be added as exact
// keywords in the same adgroup.
//
////////////////////////////////////////////////////////////////////

var config = {

  LOG : true,

  // Set the daterange to select the search queries in your account.
  // Change the number of days to your liking.
  DATE_RANGE : last_n_days(90),

  // Set the following thresholds. Set to '0' (zero) to be ignored.
  // These threshold help select the right queries to be added.
  // Each queries must match all thresholds!
  IMPRESSIONS_THRESHOLD : 0,
  CLICKS_THRESHOLD : 0,
  CONVERSIONS_THRESHOLD : 0,
  CTR_THRESHOLD : 0,
  CPA_THRESHOLD : 0,
  COST_THRESHOLD : 0

}

////////////////////////////////////////////////////////////////////

function main(){

  var exactKeywords = getKeywords();
  var queriesToBeAdded = {};

  var report = AdsApp.report(
    "SELECT Query, KeywordTextMatchingQuery, AdGroupId, Impressions, Clicks, Cost, Ctr, CostPerConversion, Conversions " +
    "FROM SEARCH_QUERY_PERFORMANCE_REPORT " +
    "WHERE Impressions > 0 " +
    "AND AdGroupStatus = ENABLED " +
    "AND CampaignStatus = ENABLED " +
    "AND KeywordTextMatchingQuery DOES_NOT_CONTAIN_IGNORE_CASE 'URL' " +
    "DURING " + config.DATE_RANGE);

  var rows = report.rows();
  while(rows.hasNext()){
    var row = rows.next();
    
    // Some selected queries are the same as the matching keyword.
    // We'll exclude them from being added.
    if(row["Query"] == row["KeywordTextMatchingQuery"]) continue;

    // Skip queries if thresholds are set and not matched.
    if(config.IMPRESSIONS_THRESHOLD != 0 && row["Impressions"] < config.IMPRESSIONS_THRESHOLD) continue;
    if(config.CLICKS_THRESHOLD != 0 && row["Clicks"] < config.CLICKS_THRESHOLD) continue;
    if(config.CONVERSIONS_THRESHOLD != 0 && row["Conversions"] < config.CONVERSIONS_THRESHOLD) continue;
    if(config.CTR_THRESHOLD != 0 && row["Ctr"].replace("%","") < config.CTR_THRESHOLD) continue;
    if(config.CPA_THRESHOLD != 0 && row["CostPerConversion"] > config.CPA_THRESHOLD) continue;
    if(config.COST_THRESHOLD != 0 && row["Cost"] < config.COST_THRESHOLD) continue;
    
      if(config.LOG === true){
        Logger.log(row["Query"] + ": " + row["Impressions"] + " impressions, " + row["Clicks"] + " clicks, " + row["Conversions"] + " conversions, " + row["Ctr"] + " CTR, €" + row["CostPerConversion"] + " CPA, €" + row["Cost"] + " cost.");
        Logger.log("Matched with " + row["KeywordTextMatchingQuery"]);
        Logger.log(" ");
      }

    // If query is not an exact keyword in the account yet, we'll add it
    if(exactKeywords.indexOf(row["Query"]) < 0){

      if(queriesToBeAdded[row["Query"]] == null){
        queriesToBeAdded[row["Query"]] = [];
      }
      queriesToBeAdded[row["Query"]].push(row["Query"], row["AdGroupId"]);

    }

  } // rowIterator

  if(config.LOG === true){
    Logger.log("------------------------");
    Logger.log("Found " + Object.keys(queriesToBeAdded).length + " keywords to be added");
    Logger.log("------------------------");
    Logger.log(" ");
  }

  // Add Keywords
  for (var key in queriesToBeAdded) {

    var adGroupId = [];
    adGroupId.push(queriesToBeAdded[key][1])

    var adGroupIterator = AdsApp
      .adGroups()
      .withIds(adGroupId)
      .get();

    while(adGroupIterator.hasNext()){
      var adGroup = adGroupIterator.next();
      
        adGroup.adParams()
      
      var keywordOperation = adGroup
        .newKeywordBuilder()
        .withText("["+queriesToBeAdded[key][0]+"]")
        .build();
      
      var keyword = keywordOperation.getResult();
      
        if(config.LOG === true){
          Logger.log("Put " + keyword.getText() + " in " + adGroup.getName());
        }        

    } // adGroupIterator


  } // keywordIterator

} // function main()

////////////////////////////////////////////////////////////////////

function last_n_days(n) {

	var	from = new Date(), to = new Date();
	to.setUTCDate(from.getUTCDate() - n);

	return google_date_range(from, to);

} // function last_n_days()

////////////////////////////////////////////////////////////////////

function google_date_range(from, to) {

	function google_format(date) {
		var date_array = [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()];
		if (date_array[1] < 10) date_array[1] = '0' + date_array[1];
		if (date_array[2] < 10) date_array[2] = '0' + date_array[2];

		return date_array.join('');
	}

	var inverse = (from > to);
	from = google_format(from);
	to = google_format(to);
	var result = [from, to];

	if (inverse) {
		result = [to, from];
	}

	return result.join(',');

} // function google_date_range()

////////////////////////////////////////////////////////////////////

function getKeywords(){
  
    if(config.LOG === true){
      Logger.log("Start collecting keywords");
    }

  var keywords = [];

  var keywordIterator = AdsApp
    .keywords()
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("AdGroupStatus = ENABLED")
    .withCondition("Status != REMOVED")
    .withCondition("KeywordMatchType = EXACT")
    .get();

  while(keywordIterator.hasNext()){
    var keyword = keywordIterator.next();
    keywords.push(keyword.getText());
  } // keywordIterator
  
    if(config.LOG === true){
      Logger.log("Collected " + keywords.length + " exact keywords");
      Logger.log(" ");
    }

  return keywords;

} // function getKeywords
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 is all about sharing knowledge. In the current market, PPC specialists like to keep their knowledge and experience to themselves. We're convinced that sharing knowledge can ensure that everyone gets better at their work. We want to change this by sharing our knowledge about scripts with everyone.

Do you also want to contribute? We are open to new ideas and feedback on everything you find on Adsscripts.com.

Contact us

Training &
Workshop
Contact us!
Adsscripts Training & Workshop