Google Ads Script to Receive Disapproved Ads Alerts


Ad Disapprovals happen.

There are many reasons why an ad can get disapproved and I had to deal with a lóóóóóót of them.
Most of which were my own “fault” (me trying to squeeze in that extra special symbol, or some more CAPS, or…).

Not last year though.

2019 showed a worrying increase in the number of ads being disapproved on multiple accounts.
For 3 of my accounts, the unexpected reason was “Disapproved: Malicious or unwanted software”.

There is nothing suspicious, nothing malicious, no malware anywhere on the sites at all.
The sites have not seen any changes for years.
Yet, Google Ads just decided to go bonkers all of a sudden.

It took 3 weeks and countless less-then-fruitful conversations with support reps to fix the issues.
But, in the end… we got it fixed! [sigh of relief]

[2020 update: The same thing seems to be happening right now with a lot of ads being disapproved during COVID19 period]

Here’s my theory on the story:
Google is adding more AI to the review process. Google is training its AI to enforce their policy.
And while the AI is learning, it is up to us to fix its mistakes -> endlessly contact support to convince them the machine is wrong.

 

Disapproved ads hurt your account.

They mess up your tests, reduce your reach and in the worst case prevent any ad from showing up for your keywords.

That’s why you want to fix them asap.

In order to do so, you have to know when they get disapproved AS SOON AS POSSIBLE!

Guess what… there’s a script for that!

 

➥  ACTION: Block Facebook for the next ten minutes and install the script.

Peace of mind is your BONUS.
(Don’t worry if you have never run a script before. You do not need any coding skills. It is as simple as copy-paste.)

 

UPDATE June 2022:  
- changed AWQL query to GAQL query
- updated the script to be compatible with new script environment
- added support for policy findings in the Google Ads API

 

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 16)
  4. Add your email address to the script (line 17)
  5. Preview
  6. Schedule to run hourly/daily.
/**
*
* Report Disapproved Ads
*
* Creates a report indicating which ads are disapproved, including the reason why
* Sends an alert via email whenever ads are disapproved
*
* Version 2.0
* - changed AWQL query to GAQL query
* - updated the script to be compatible with new script environment
* - added support for policy findings in the Google Ads API
*
* @author: Nils Rooijmans
*
* contact nils@nilsrooijmans.com for questions and the MCC version of the script 
*/
 

// CHANGE SETTINGS HERE

var SPREADSHEET_URL = "";  //insert a new blank spreadsheet url between the quotes
var EMAIL = ""; //insert your email adresses between the quotes


// NO CHANGES NEEDED BELOW THIS LINE

var SHEET_REPORT_HEADER = [
    "Campaign Name", 
    "AdGroup Name", 
    "AdID",
    "Ad Type",
    "Ad Status",
    "Disapproval Reason"
  ];


function main() {

  // first we clear the report sheet and add header
  prepareSpreadsheet();  
  
  // now let's check for disapprovals
  var disapprovedAds = getDisApprovedAds();    
  
  // finally, let's report on any issues
  if (disapprovedAds.length > 0) { // there is at least one issue
    Logger.log("Total NR of Ads Disapproved: "+disapprovedAds.length);
    reportResults(disapprovedAds);
  }  
}


function prepareSpreadsheet() {

  var ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
  var sheet = ss.getActiveSheet();
  sheet.clear(); //remove earlies alerts
  sheet.clearConditionalFormatRules();
  sheet.appendRow(SHEET_REPORT_HEADER);
}


function getDisApprovedAds() {
  
  var accountName = AdsApp.currentAccount().getName();
  Logger.log("Checking account: "+accountName);
  
  var issues = [];
  
  var whereClause = "WHERE ad_group_ad.policy_summary.approval_status = 'DISAPPROVED' AND campaign.status = 'ENABLED' AND campaign.serving_status != 'ENDED' AND ad_group.status = 'ENABLED' AND ad_group_ad.status = 'ENABLED' AND segments.date DURING TODAY";
  
  var gaqlQuery = "SELECT campaign.name, ad_group.name, ad_group_ad.ad.id, ad_group_ad.ad.type, ad_group_ad.policy_summary.approval_status, ad_group_ad.policy_summary.policy_topic_entries FROM ad_group_ad "+whereClause;

  Logger.log("gaqlQuery: "+gaqlQuery);
  
  var results=AdsApp.search(gaqlQuery);   
  
  while (results.hasNext()) {
    
    var row=results.next() ;
    
    var campaignName = row.campaign.name;
    var adGroupName = row.adGroup.name;
    var adId = row.adGroupAd.ad.id;
    var adType = row.adGroupAd.ad.type;
    var approvalStatus = row.adGroupAd.policySummary.approvalStatus;
    var policyTopicEntries = row.adGroupAd.policySummary.policyTopicEntries;
    
    var policyFindings = "";
    
    if (policyTopicEntries.length > 0) {
      for (var i=0; i < policyTopicEntries.length; i++) {
        var policyTopic = policyTopicEntries[i].topic;
        if (policyFindings == "") {
          policyFindings = policyTopic;
        } else {
          policyFindings = policyFindings.concat(" , "+policyTopic);
        }
      }      
    }
    
    Logger.log("Campaign '%s', ad group '%s', ad_id '%s', issue: '%s'", campaignName, adGroupName, adId, policyFindings);

    issues.push([
      campaignName,
      adGroupName,
      adId,  
      adType,
      approvalStatus, 
      policyFindings
    ]);  
  } 
  return issues;

}


function reportResults(results) {

    var ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
    var sheet = ss.getActiveSheet();
    var lastRow = sheet.getLastRow();

    // write issues to sheet
    var range = sheet.getRange(lastRow+1, 1, results.length, SHEET_REPORT_HEADER.length);
    range.setValues(results);

    // send the email
    var emailBody = 
      "Number of Ads Disapproved: " + results.length + "\n" + 
      "See details: "+ SPREADSHEET_URL + "\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 - Disapproved Ads Checker, (C) Nils Rooijmans \n" +
      "---\n";

    MailApp.sendEmail(EMAIL, "[GOOGLE ADS ALERT] - Disapproved Ads", emailBody);
}

 

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.