Google Ads Negative Keywords Automation with AI

FlowHunt automates Google Ads negative keyword management with AI, helping businesses cut costs, optimize ad spend, and improve campaign results effortlessly.

Google Ads Negative Keywords Automation with AI

Understanding Unwanted Keyword Spend

Unwanted keyword spend happens when your ads appear in search results that don’t match what you’re selling. This can quickly deplete your budget, as each irrelevant click costs money without leading to a sale. For example, if a company selling high-end leather shoes targets broad keywords like “buy shoes,” it might attract clicks from people interested in sneakers or sandals, which aren’t what they offer. This mismatch in keyword targeting can lead to wasted ad spend and lower ROI. Businesses need to grasp this concept to avoid unnecessary financial losses and focus their budget on the right keywords.

The Role of Negative Keywords

Negative keywords are an essential tool in any Google Ads campaign. They let advertisers exclude specific search terms from triggering their ads, ensuring that only relevant searches lead to ad views. For example, using negative keywords like “cheap” or “discount” can help the leather shoe company avoid clicks from people not interested in premium products. By carefully crafting a list of negative keywords, businesses can optimize their ad spending, reduce unwanted clicks, and boost their campaign’s overall effectiveness.

Using AI for Keyword Management

artificial intelligence (AI) is changing how advertisers manage Google Ads campaigns. AI tools like FlowHunt are made for keyword grouping, helping businesses identify and organize related keywords more effectively. This automation simplifies the process of finding both positive and negative keywords, cutting down on the manual work involved in managing campaigns. AI-driven keyword management allows for real-time changes based on performance data, ensuring that ad spending is continually optimized for the best ROI.

Strategies to Reduce Unwanted Keyword Spend

To cut down on unwanted keyword spending, businesses should adopt several strategies:

  • Regularly update your keyword list to match changing market trends and consumer interests.
  • Implement a strong negative keyword strategy by constantly researching and updating the list of terms you want to exclude.
  • Monitor and tweak campaigns based on performance data.
  • Analyze which keywords lead to sales and which don’t to refine targeting and maximize ad spend.

Case Study: PostAffiliatePro’s Approach

PostAffiliatePro was facing issues with their monthly ad spending, struggling to get the ROI they wanted from their Google Ads campaigns. They decided to use AI to address this problem. By incorporating AI-driven tools, they automated their keyword management process, identifying both positive and negative keywords more accurately. This change allowed them to optimize their ad spending, significantly cutting costs and improving campaign efficiency. Their experience highlights the benefits of using AI technology to manage keyword spending effectively. Analyses of each new keyword are running within an hour from the first impression of the keyword. The speed helps to catch negative keywords before visitors could click in the Google Ad.

improved conversion rate Improved conversion rate (just relevant search brings more sales)

Additional Resources

For those interested in learning more about effective keyword management and AI optimization, consider exploring these resources:

Here is our script, which we run each hour to evaluate keyword clusters.

This script aims to automate several tasks related to managing Google Ads campaigns. It interacts with Google Sheets for configuration and settings, and performs operations on Google Ads accounts, like analyzing search terms, adding or excluding keywords, and interfacing with the FlowHunt API for advanced AI keyword clustering.

Google Sheet to manage script settings Google Sheet to manage script settings

Negative keywords automatically applied to Ad groups Negative keywords automatically applied to Ad groups

Main Function

  • The core control logic is housed in the main() function. This function opens the Google Sheets document specified by spreadsheetURL, retrieves necessary configuration settings like apiKey, country, language, and others.
  • Initially, the system attempts to add any new positive keywords to the FlowHunt cluster. If successful, it proceeds to analyze any unassigned search terms.

Keyword Analysis

  • Analyzing Not Assigned Words: The function iterates over all ad groups within the Ads account marked with a specific label. It retrieves search terms from Google Ads that are not currently targeted and had minimum one impression.
  • The system uses the FlowHunt API to find similar keywords to currently analyzed keyword, filtering them based on a specified minimumMatch criterion.
  • Search terms that match the criteria are either added as positive keywords or marked as negatives if minimum criteria are not matched, updating the relevant Google Sheet with this information and also updating your Google Ads campaigns.

FlowHunt Integration

  • API Interaction: The script relies on the function callFlowHuntApi() to interact with the FlowHunt API for various tasks, including retrieving workspace IDs and clustering keywords.
  • Add Keywords to Cluster: This function pushes positive keywords back to FlowHunt for clustering, ensuring they’re informed by live search query data from Google Ads.
  • Added and negative keywords are logged into separate sheets for ongoing tracking and review.

Usage

To deploy this script, users need to:

  • Provide a valid Google Sheets URL and ensure necessary sheets (“Settings”, “AddedKW”, “NegativeKW”) are present.
  • Configure the Google Sheets with correct FlowHunt API key, country codes, and other operational settings.
  • Ensure the script is executed within a Google Ads Script environment with proper API access enabled.

Add script to your Google Ads in menu Tools -> Bulk Actions -> Scripts Add script to your Google Ads in menu Tools -> Bulk Actions -> Scripts.

Don’t forget to set the real link to your Google Sheet document. The rest is our magic. We identify keywords, which belong to the campaign and automate the management of keywords (Both negative or positive).

//Global variables
var spreadsheetURL;
var spreadsheet;
var sheetSettings; 
var sheetAddedKW;
var sheetNegativeKW;
var apiKey;
var labelName;
var country;
var language;
var location;
var urlsCount;
var minimumMatch;
var workspaceId;

function main() {
    // Provide the Google Sheets URL here
  spreadsheetURL = "https://docs.google.com/spreadsheets/d/....... FULL URL TO GOOGLE SHEET";
  spreadsheet = SpreadsheetApp.openByUrl(spreadsheetURL);
  sheetSettings = spreadsheet.getSheetByName("Settings"); 
  sheetAddedKW = spreadsheet.getSheetByName("AddedKW");
  sheetNegativeKW = spreadsheet.getSheetByName("NegativeKW");
  apiKey = getSettingValue("FlowHuntAPIkey")
  labelName = getSettingValue("LabelName")
  country = getSettingValue("CountryCode")
  language = getSettingValue("LanguageCode")
  location = getSettingValue("Location")

  urlsCount = getSettingValue("TopUrlsCount")
  minimumMatch = getSettingValue("MinimumMatch")
  workspaceId = getWorkspaceId()
  
  if (workspaceId.length < 10) {
    Logger.log("Failed to load workspace id from FlowHunt, check API key");
    return;
  }
  
  Logger.log("FlowHunt WorkspaceId: " + workspaceId);
  
  if (addPositiveKWsToCluster() == 0) {
    // Analyze new keywords just if all positive keywords added already
    analyzeNotAssignedWords();
  }
}

function analyzeNotAssignedWords() {
  Logger.log("*** START Checking not assigned keywords");
  
  // Iterate through all ad groups in the account
  var adGroupsIterator = AdsApp.adGroups().get();
  
  while (adGroupsIterator.hasNext()) {
    var adGroup = adGroupsIterator.next();
    var groupName = adGroup.getId() + " - " + adGroup.getName();
    if (hasLabel(adGroup, labelName)) {
      // Get the search terms for the current ad group ordered by clicks in the last X days
      var searchTermsQuery = "SELECT Query FROM SEARCH_QUERY_PERFORMANCE_REPORT " +
        "WHERE AdGroupId = " + adGroup.getId() +
        " AND QueryTargetingStatus = \"NONE\" " +
        "DURING TODAY";

      var searchTermsIterator = AdsApp.report(searchTermsQuery).rows();
      var adGroupKeywords = [];
      while (searchTermsIterator.hasNext()) {
        var searchTerm = searchTermsIterator.next();
        var searchTermText = searchTerm["Query"].trim();
        var similarQueries = getSimilarQueries(groupName, searchTermText)
        var filteredSimilarQueries = getFilteredSimilarQueries(similarQueries);
        if (filteredSimilarQueries.length > 0) {
          var keywordOperation = adGroup.newKeywordBuilder().withText("[" + searchTermText + "]").build();
          if (keywordOperation.isSuccessful()) {
            adGroupKeywords.push(searchTermText);
            var rowData = [groupName, searchTermText, new Date(), "ADDING AS POSITIVE, REVIEW!", JSON.stringify(filteredSimilarQueries)];
            sheetAddedKW.appendRow(rowData);
          } else {
            Logger.log("Failed to add keyword as positive:" + searchTermText)
          }
        } else {
          // add to negative
           adGroup.createNegativeKeyword("[" + searchTermText + "]");
          Logger.log("Excluded search term in ad group '" + groupName + "': " + searchTermText);
          var rowData = [groupName, "[" + searchTermText + "]", new Date(), JSON.stringify(similarQueries)];
          sheetNegativeKW.appendRow(rowData);
        }
      }
      if (adGroupKeywords.length > 0) {
        //Add all keywords in the list to FlowHunt Cluster
        addKeywordsToFlowHunt(groupName, adGroupKeywords);
      }
    }
  }
  Logger.log("*** FINISHED Checking not assigned keywords");
}

function getSimilarQueries(groupName, query) {
  result = callFlowHuntApi("/serp/serp/cluster/query_intersections?workspace_id="+workspaceId, "POST", {
    "query": query,
    "country": country,
    "language": language,
    "location": location,
    "group_name": groupName,
    "live_mode": true,
    "max_position": urlsCount
  });
  Logger.log(result)
  if (result.status=="SUCCESS") {
    return JSON.parse(result.result);
  }
  return []
}

function getFilteredSimilarQueries(similarQueries) {
  filtered = [];
  for (var i=1; i<similarQueries.length; i++){
    if (similarQueries[i].count>=minimumMatch) {
      filtered.push(similarQueries[i]);
    }
  }
  return filtered;
}

function addPositiveKWsToCluster() {
  Logger.log("*** START Checking new campaign keywords");
  // Iterate through all ad groups in the account
  var adGroupsIterator = AdsApp.adGroups().get();
  var processedKWs = sheetAddedKW.getDataRange().getValues();
  var processedKWsMap = {};
  var rowsAdded = 0;
  
  for (var i = 1; i < processedKWs.length; i++) { // Start at 1 to skip header row if exists
    var groupName = processedKWs[i][0];
    var keyword = processedKWs[i][1];
    processedKWsMap[groupName + '|' + keyword] = true;
  }
  
  while (adGroupsIterator.hasNext()) {
    var adGroup = adGroupsIterator.next();
    var groupName = adGroup.getId() + " - " + adGroup.getName();
    if (hasLabel(adGroup, labelName)) {
      var keywordsIterator = adGroup.keywords().get();
      var adGroupKeywords = [];
      while (keywordsIterator.hasNext()) {
        var keyword = keywordsIterator.next();
        if (keyword.isEnabled()) {
          var key = groupName + '|' + keyword.getText();
          if (!processedKWsMap[key]) {
            adGroupKeywords.push(keyword.getText());
            var rowData = [groupName, keyword.getText(), new Date(), "Already present in campaign"];
            sheetAddedKW.appendRow(rowData);
            processedKWsMap[key] = true; 
          }
        }
      }
      if (adGroupKeywords.length > 0) {
        //Add all keywords in the list to FlowHunt Cluster
        addKeywordsToFlowHunt(groupName, adGroupKeywords);
      } else {
        Logger.log("No new keywords in Group: " + groupName);
      }
      rowsAdded = rowsAdded + adGroupKeywords.length
    }
  }
  Logger.log("*** FINISHED Checking new campaign keywords");
  return rowsAdded;
}

function addKeywordsToFlowHunt(GroupName, adGroupKeywords) {
  requests = []
  adGroupKeywords.forEach(function(keyword) {
    requests.push(
        {
          "query": keyword,
          "country": country,
          "language": language,
          "location": location,
          "group_name": GroupName,
          "count_urls": 30
        }
      );
    });
  callFlowHuntApi("/serp/serp/cluster/add_queries?workspace_id="+workspaceId, "POST", {"requests":requests});
}

function getSettingValue(settingName) {
    var data = sheetSettings.getDataRange().getValues();
    for (var i = 0; i < data.length; i++) {
        if (data[i][0] === settingName) {
            return data[i][1];
        }
    }
    return null;
}
  
function getWorkspaceId() {
  result = callFlowHuntApi("/auth/me", "GET")
  if (result !== null) {
    return result.api_key_workspace_id;
  }
}

function callFlowHuntApi(endpoint, method, requestBody) {
    var url = "https://api.flowhunt.io/v2" + endpoint;
    var headers = {
        "Api-Key": apiKey,
        "Content-Type": "application/json"
    };
    var options = {
        "method" : method,  // or "post", "put", etc.
        "headers" : headers,
        "payload": JSON.stringify(requestBody)
    };
    
    try {
        var response = UrlFetchApp.fetch(url, options);
        var responseData = JSON.parse(response.getContentText());
        Logger.log(responseData);
        return responseData;
    } catch (e) {
        Logger.log("An error occurred: " + e.message);
    }
    return null;
}

function hasLabel(adGroup, labelName) {
  var labels = adGroup.labels().get();
  while (labels.hasNext()) {
    var label = labels.next();
    if (label.getName() === labelName) {
      Logger.log("Processing Adgroup " + adGroup.getName());
      return true;
    }
  }
  return false;
}

Frequently asked questions

Why are negative keywords important in Google Ads?

Negative keywords prevent your ads from appearing for irrelevant searches, reducing wasted spend and improving campaign ROI by focusing only on the most relevant queries.

How does AI automate negative keyword management?

AI tools like FlowHunt analyze real-time search data, identify irrelevant keywords, and automatically update your campaigns with negative keywords, saving time and boosting efficiency.

What results can I expect from automating negative keywords with AI?

Expect increased conversion rates, reduced ad spend on irrelevant clicks, and more efficient campaigns as AI continuously optimizes your keyword lists and targeting.

How do I set up FlowHunt's automation for my Google Ads?

You'll need to connect your Google Ads account, configure settings in a Google Sheet, and deploy the provided script to enable automated keyword management powered by FlowHunt's AI.

Automate Your Google Ads with AI

Ready to maximize your Google Ads ROI? Discover how AI-powered automation manages your negative keywords and optimizes ad spend.

Learn more