Google Ads Script: Incorporate “Search Terms” as “Keywords”

Google Ads Script: Incorporate "Search Terms" as "Keywords" 1

Add search terms as a keyword when they perform well.

An easy way to expand an account.

Adding high-performing search terms as keywords is an effective way to expand and improve your Google Ads account. By analyzing the search query report, you can exclude irrelevant terms and identify new keywords to add to your ad groups. This provides greater control over these search terms by allowing you to adjust bids and optimize performance as needed.

To streamline this process, you can use the script below to automate keyword additions. Based on predefined performance criteria—such as impressions, clicks, conversions, CTR, CPA, and cost—the script evaluates search queries and automatically adds them as keywords if they meet your benchmarks.

The script also ensures that the exact keyword isn’t already present elsewhere in the account, maintaining your account’s structure and avoiding duplication. With this approach, you gain better control over your campaigns while saving time and effort.

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.
  • CLICKS_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 your account, we recommend running this script only once a day.

Important: By default, Google collects search queries in lowercase. If your keywords include capitalized letters, the script might add queries that already exist in your account. To avoid duplication, ensure all your keywords are in lowercase.

// 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

The script credit goes to: Tibbe Van Asten

Google Ads On Steroids

Uncover Game-Changing Trends, Proven Strategies, and Expert Tips to Elevate Your Marketing Every Week