Google Ads Script – Report Ad Groups that don’t have RSA’s

Since June 30 2022, advertisers are no longer able to create or edit Expanded Text Ads (ETAs) in Google Ads.
Responsive Search Ads (RSAs) are the new default.

According to many PPC practitioners, ETAs get fewer impressions than RSAs for the same set of keywords and bids.

So, unless you want to limit your growth opportunity, you need to add RSAs to each and every ad group.

Identifying ad groups that have zero RSAs can be a bit jarring, so I decided to create a script to identify ad groups without any active RSA’s.

The following script creates a Google Sheet reporting ad groups that have less than the required number of Respsonsive Search Ads (RSAs).
If there is at least one ad group that has too little RSA’s the script will send an email with a link to the report.

INSTRUCTIONS:

  1. See the script code below. Install the script in your account.
    Don’t worry if you have never done this before. You do not need any coding skills. It is as simple as copy-paste. Simply follow these instructions on how to set up and schedule Google Ads scripts.
  2. Create a new Google Sheet
    (tip for Chrome users: simply type ‘sheets.new’ in the address bar)
  3. Add the complete URL of the spreadsheet to the script (line 19)
  4. Add your email address to the script (line 20)
  5. Edit the email subject (line 21)
  6. Preview
  7. Schedule to run daily.

 

/**
*
* Report Missing RSA Ad Groups
*
* Creates a Google Sheet reporting ad groups that have less than the required number of
* Respsonsive Search Ads (RSAs)
*
*
* @author: Nils Rooijmans
*
* Version 1.0 
*
* contact nils@nilsrooijmans.com for questions and a High Performance MCC version of the script 
*/
 
 
/*** [REQUIRED] ADD YOUR SETTINGS HERE ***/

var SPREADSHEET_URL = "";  //insert a new blank spreadsheet url, be sure to include the complete url!
var EMAIL_ADDRESSES = ""; //insert your email address, multiple email addresses seperated by comma
var EMAIL_SUBJECT = "GAds Script - [INSERT YOUR ACCOUNT NAME HERE] - Missing RSA Ad Groups"; // subject of emails


/*** [OPTIONAL] YOU MIGHT WANT TO CHANGE SOME CONFIGURATIONS HERE ***/

var MIN_NR_OF_RSA_PER_AD_GROUP = 1; 
// set to your requirement for the minimum number of RSAs per ad group

var IMPRESSION_ALERT_THRESHOLD = 1000; 
// threshold for email alerts; issues with ad groups that have had less impressions will still be reported,
// owever an email is only sent if at least one ad group has had over this number of impressions during last 7 days

var SEND_EMAIL = true; // set to false if you do not want to send alert email


/*** DO NOT CHANGE ANYTHING BELOW THIS LINE ***/

var DEBUG = false; 

var EMAIL_BODY = 
    "\n"+
    "***\n"+
    "This script will check all enabled ad groups in all enabled search campaigns, \n"+
    "  for each ad group it will check if the ad group has at least "+MIN_NR_OF_RSA_PER_AD_GROUP+" RSA(s) enabled, \n"+
    "    if the ad group does not have the minimum number of RSAs, it is logged in a Google Sheet, the rows in the sheet are sorted by number of impressions of the ad group \n"+
    "    also, if the ad group does not have the minimum number of RSAs, AND the ad group has had over "+IMPRESSION_ALERT_THRESHOLD+" impressions during last 7 days, an email alert will be sent to"+EMAIL_ADDRESSES+" \n"+
    "\n"+
    "Here's the link to the output of the script: "+ SPREADSHEET_URL+ "\n---\n\n"+
    "For more FREE Google Ads Scripts to improve your results and make your working day feel like a breeze, visit https://nilsrooijmans.com \n" + 
    "---\n" + 
    "This email is generated by a copy of the free Google Ads Script - Report Missing RSA Ad Groups, (C) Nils Rooijmans \n" +
    "---\n";

var sendAlertMail = false; 


function main() {
  
  // prepare output sheet
  var sheet;
    try {
      sheet = prepareOutputSheet();  
    } catch(e) {
      alert("Reporting issue: "+e);
      return;
    }
  
  // process campaigns
  var results = processCampaigns();
 
  if (results.length > 0) {

    // report results
    addOutputToSheet(results, sheet);   

    // send alert mail if conditions are met
    if (sendAlertMail) {
      sendEmail(results.length); 
    }
  }  
}


function processCampaigns() {

  var results = [];
  
  var campaignSelector = AdsApp.campaigns()
    .withCondition('Status = "ENABLED"')
    .withCondition("AdvertisingChannelType = SEARCH") // only process search campaigns
    .withCondition("CampaignExperimentType = BASE"); // only process Base campaigns, not Experiments
  
  var campaignIterator = campaignSelector.get();
  Logger.log("NR of campaigns to process: "+campaignIterator.totalNumEntities());
  
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    var result = processCampaign(campaign);
    results = results.concat(result);
  }

  return results;
}


function processCampaign(campaign) {
  
  debug("Processing campaign: "+campaign.getName());
  var campaignId = campaign.getId();
  
  var results = [];
  
  var adGroupSelector = AdsApp.adGroups()
    .withCondition('CampaignId = "'+campaignId+'"')
    .withCondition('Status = "ENABLED"');
  
  var adGroupIterator = adGroupSelector.get();
  debug("NR of adGroups to process: "+adGroupIterator.totalNumEntities());
  
  while (adGroupIterator.hasNext()) {
    var adGroup = adGroupIterator.next();
    var result = processAdGroup(adGroup);
    results = results.concat(result);
  }

  return results;
}


function processAdGroup(adGroup) {
  
  
  var campaignId = adGroup.getCampaign().getId();
  var campaignName = adGroup.getCampaign().getName();
  
  var adGroupId = adGroup.getId();
  var adGroupName = adGroup.getName();
  
  debug("Processing adGroup: "+adGroupName);
  
  var impressions = adGroup.getStatsFor('LAST_7_DAYS').getImpressions();
  
  var results = [];
  
  var adSelector = AdsApp.ads()
    .withCondition('CampaignId = "'+campaignId+'"')
    .withCondition('AdGroupId = "'+adGroupId+'"')
    .withCondition("Type IN [RESPONSIVE_SEARCH_AD]")
    .withCondition('Status = "ENABLED"');
  
  var adIterator = adSelector.get();
  var nrOfRSAs = adIterator.totalNumEntities();
  debug("NR of RSAs in this ad group: "+nrOfRSAs);
        
  
  if (nrOfRSAs < MIN_NR_OF_RSA_PER_AD_GROUP) { // this adGroup does not meet the minimum required number of RSAs
    results.push([campaignName, adGroupName, impressions, nrOfRSAs]);
    if (impressions > IMPRESSION_ALERT_THRESHOLD) { 
      sendAlertMail = true;
    }
  }

  return results;
}

function prepareOutputSheet() {
  
  if(SPREADSHEET_URL == ""){
    throw("Create new Google Sheet and copy paste complete url in config variable 'SPREADSHEET_URL' at the top of the script");
  }  
  
  var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);

  var sheet = spreadsheet.getActiveSheet();
  
  try {
    sheet.clear();
    addHeaderToOutputSheet(sheet);
  } catch(e) {
    throw(e);
  }
 
  return sheet;
}


function addHeaderToOutputSheet(sheet) {
  
  var header = [
    "campaignName",
    "adGroupName",
    "impressions",
    "number of RSAs"
    ];
  
  sheet.appendRow(header);
  
  var range=sheet.getRange(1,1,1,header.length);
  range.setFontWeight("bold");  
}


function addOutputToSheet(output, sheet) {
  
  if (!(output.length > 0)) return; // nothing to add to sheet

  var numberOfRows=sheet.getLastRow() ;
  debug("NR of rows in output sheet: "+numberOfRows);
  
  sheet.insertRowsBefore(2, output.length); // add empty rows below header row

  var startRow = 2;
  
  var range=sheet.getRange(startRow, 1, output.length, output[0].length) ;
  range.setValues(output) ;
  range.sort([{column: 3, ascending: false}]);    

  Logger.log("\nNumber of rows added to output sheet: "+output.length+"\n\n");
  
}



function sendEmail(number) {

  if (SEND_EMAIL) {
    // send the email
    var emailBody = 
        "Number of issues: " + number + "\n" + 
        "See details: "+ SPREADSHEET_URL+ "\n" + EMAIL_BODY;

    MailApp.sendEmail(EMAIL_ADDRESSES, EMAIL_SUBJECT, emailBody);
    Logger.log("Sending mail");
  }  
}


/** HELPER FUNCTIONS **/

function debug(string) {
  if (DEBUG == true) {
    Logger.log("* "+string);
  }
}

function alert(string) {
  Logger.log("##### ERROR: "+string+" #####");
}

 

Join thousands of PPC geeks who already have access:

If the button above isn’t working for you, you can sign up here to get access.