{"id":529,"date":"2018-06-08T16:13:22","date_gmt":"2018-06-08T16:13:22","guid":{"rendered":"https:\/\/www.digitalposition.com\/resources\/learn\/?p=529"},"modified":"2023-03-01T17:49:22","modified_gmt":"2023-03-01T17:49:22","slug":"account-emergency-detector-free-adwords-ppc-script","status":"publish","type":"post","link":"https:\/\/dev.digitalposition.com\/resources\/blog\/ppc\/account-emergency-detector-free-adwords-ppc-script\/","title":{"rendered":"Account Emergency Detector &#8211; Free Adwords PPC Script"},"content":{"rendered":"<p>Keeping an eye on the health of your Adwords accounts can be an overwhelming task if you\u2019re managing many of them. Thankfully, using Google Adwords Scripts can help take away some of the hassle and automate many tasks and processes. One essential task that many skilled developers have attempted to automate is making sure your accounts are running as expected. The central idea is, if the account\u2019s ads are getting impressions, that\u2019s good; but if not, there\u2019s most likely a problem. Catching these problems early can potentially save your clients thousands of dollars, therefore it\u2019s essential to have the best Adwords script out there running on your accounts. Here are some of the most popular free Adwords scripts on the internet that periodically check to make sure your accounts are getting impressions:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>Google Anomaly Detector &#8211; <u><a href=\"https:\/\/developers.google.com\/adwords\/scripts\/docs\/solutions\/account-anomaly-detector\">https:\/\/developers.google.com\/adwords\/scripts\/docs\/solutions\/account-anomaly-detector<\/a><\/u><\/li>\n<li>Google Anomaly Detector MCC &#8211; <u><a href=\"https:\/\/developers.google.com\/adwords\/scripts\/docs\/solutions\/mccapp-account-anomaly-detector\">https:\/\/developers.google.com\/adwords\/scripts\/docs\/solutions\/mccapp-account-anomaly-detector<\/a><\/u><\/li>\n<li>Granular Anomaly Detector &#8211; <u><a href=\"https:\/\/searchengineland.com\/script-getting-granular-adwords-account-anomaly-alerts-249139\">https:\/\/searchengineland.com\/script-getting-granular-adwords-account-anomaly-alerts-249139<\/a><\/u><\/li>\n<li>Zero Impressions Email Alarm &#8211; <u><a href=\"http:\/\/catalyst.ca\/blog\/set-a-fire-alarm-on-your-accounts-with-adwords-scripts\/\">http:\/\/catalyst.ca\/blog\/set-a-fire-alarm-on-your-accounts-with-adwords-scripts\/<\/a><\/u><\/li>\n<li>Check If Account Is Offline &#8211; <u><a href=\"https:\/\/bitbucket.org\/snippets\/fvallaeys\/nLEoj\/check-if-account-is-offline\">https:\/\/bitbucket.org\/snippets\/fvallaeys\/nLEoj\/check-if-account-is-offline<\/a><\/u><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>When I investigated the scripts listed above, I noticed that every one of them is subject to the fact that data released by Google often has a delay of 3-4 hours. Each of these scripts are using the Impressions metric to determine if their accounts are functioning as expected. Run hourly, this can be a great indication of whether an account is functioning properly; but Google releases impressions (along with clicks and conversion) only periodically.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-524 size-medium_large\" src=\"https:\/\/www.digitalposition.com\/resources\/learn\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280-768x512.jpg\" alt=\"waiting-for-adwords-data\" width=\"768\" height=\"512\" srcset=\"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280-768x512.jpg 768w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280-300x200.jpg 300w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280-1024x682.jpg 1024w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280-600x400.jpg 600w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280-1200x800.jpg 1200w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/pocket-watch-3156771_1280.jpg 1280w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>A general rule of thumb for top level metrics is that the data won\u2019t be available for at least 3 hours after the time in question (although it can vary depending on the size of the account and many other factors).<\/p>\n<p>In the case of an emergency however, this is no good. For accounts that make any significant amount of their income through Adwords, a 3-4 hour delay could translate into thousands of dollars being lost.<\/p>\n<p>Another problem with these other scripts is that many things can trigger a warning email to be sent out, but it may not necessarily translate to a real emergency with your accounts. Imagine a situation where you\u2019re managing a smaller account. It might be perfectly normal for this account to not get any impressions at 1 AM, but this could trigger and alarm with these other scripts. An ideal script for Adwords would only detect REAL emergencies and notify you IMMEDIATELY.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-525 size-medium_large\" src=\"https:\/\/www.digitalposition.com\/resources\/learn\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280-768x512.jpg\" alt=\"determining-a-real-emergency\" width=\"768\" height=\"512\" srcset=\"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280-768x512.jpg 768w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280-300x200.jpg 300w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280-1024x682.jpg 1024w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280-600x400.jpg 600w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280-1200x800.jpg 1200w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/analysis-1841158_1280.jpg 1280w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>In order to create the perfect impressions emergency alarm script, one would have to provide a better solution to the problem of stale data (we want to detect emergencies as quickly as possible!), and only send an email in the event of an emergency. In the script below, I accomplished the first goal by making use of an account\u2019s <em>total<\/em> impressions (instead of the hourly impressions). This is one of the few metrics that Google Adwords updates in real time, so it will always be current and data freshness will never be an issue. By using this data and storing its value in a Google Sheet every time the script runs (should be hourly), we can easily subtract the total number of impressions on the previous run from the total number of impressions on the most current run, and get an accurate portrayal of how many impressions the account demonstrated during the previous hour.<\/p>\n<p>&nbsp;<\/p>\n<blockquote><p><em>Note: The only time the script would generate a false value would be on the first run of the day when the total impressions metric refreshes to 0, so it would calculate the total number of impressions on the last run (a period of 23 hours, and presumably more impressions than 0) subtracting from 0, resulting in a negative number of impressions. This was unfortunately an outstanding problem, and so the first run of the day is always ignored by the script.<\/em><\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<p>The second issue was that the script was throwing too many false triggers. Accounts that were cancelled or paused that might be on an MCC account would all be getting 0 impressions.<\/p>\n<p>Small accounts also might get 0 impressions on off peak hours. With no regulation, you might easily see your inbox full with 10 emergency emails from the same account.<\/p>\n<p>No problem! First we need to specify that each account can only send one email per day. Since we\u2019re already using a Google Spreadsheet to store variables, it was easy enough to add a separate column that stores either a true or false value for the question of &#8211; has an account already sent an email (this value refreshes to false at the end of the day).<\/p>\n<p>The other issue here is that we might <em>expect<\/em> some accounts to get 0 impressions (cancelled accounts or accounts with paused campaigns). This was addressed by adding a separate IF statement to the emergency detection logic, checking whether the account demonstrated greater than 200 impressions during the same hour in question, but on the previous week. If the statement returns true, we can reasonably expect that the account is <em>supposed <\/em>to be getting impressions during that hour, and 0 impressions during this time is a real emergency. If it returns false however, we know that that either the account doesn\u2019t usually get impressions during that time, or the account isn\u2019t enabled currently.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-526 size-medium_large\" src=\"https:\/\/www.digitalposition.com\/resources\/learn\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117-768x576.jpg\" alt=\"working-out-the-code\" width=\"768\" height=\"576\" srcset=\"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117-768x576.jpg 768w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117-300x225.jpg 300w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117-1024x768.jpg 1024w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117-393x295.jpg 393w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117-786x590.jpg 786w, https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/abstract-achievement-bright-614117.jpg 1520w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>What was the end result?<\/p>\n<p>&nbsp;<\/p>\n<p>The following Adwords script uses about 250 lines of code to do a relatively simple task in regards to account management, but compared to other PPC scripts that attempt to accomplish the same thing, I believe this script is taking the most concise route, given the extra functionality I wanted to add for real time anomaly detection. Feel free to use and edit this code to match your specific needs.<\/p>\n<p>&nbsp;<\/p>\n<p>Set up:<\/p>\n<p>&nbsp;<\/p>\n<ol>\n<li>Make a copy of this Google Spreadsheet: <a title=\"Account Emergency Global Variables Sheet\" href=\"https:\/\/docs.google.com\/spreadsheets\/d\/1PRcYbIYQ0Y0-Lwvcez8eHx6ukopFjV2aDMQKwRdSj3w\/edit#gid=0\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/docs.google.com\/spreadsheets\/d\/1PRcYbIYQ0Y0-Lwvcez8eHx6ukopFjV2aDMQKwRdSj3w\/edit#gid=0<\/a><\/li>\n<li>Open your Google Adwords MCC Account &gt; Bulk Operations &gt; Scripts and add the following script<\/li>\n<li>Replace the email addresses in the EMAIL_ADDRESSES_TO_NOTIFY variable<\/li>\n<li>Replace the SHEETID variable with the id of the Google Sheet you just created<\/li>\n<li>Set the script to run hourly<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\/\/ This script gets the number of impressions on the account. If the number of impressions &lt; \/\/ 0, it will send an emergency email to the email addresses in the EMAIL_ADDRESSES_TO_NOTIFY \/\/ variable.\n\n\/\/ --------------------------START----------------------------\/\/\n\nvar accountIterator = MccApp.accounts().get();\nvar mccAccount = AdWordsApp.currentAccount();\n\nvar EMAIL_ADDRESSES_TO_NOTIFY = [\"email1@example\",\" email2@example \",\" email3@example \"];\nvar SHEETID = \"Replace me\";\n\n\/\/ Resets the Sent Email? and Impressions columns to false at the start of a new day\nfunction resetEmailSentAndImpressions(sheetID) {\n    var ss = SpreadsheetApp.openById(sheetID).getSheetByName('Sheet1');\n    var val = ss.getRange('A:D').getValues();\n    var length = 0;\n    for (var i = 0; i &lt; val.length; i++) {\n      if (!val[i][0]) {\n          length = i;\n          break;\n      }\n    }\n    ss.getRange('B2:B'+length.toString()).setValue('false');\n    ss.getRange('D2:D'+length.toString()).setValue(0);\n    return \"Reset all values in 'Sent Email?' and 'Impressions on last run' columns to false and 0\";\n}\n\n\/\/ Opens the corresponding Google Sheet to set the 'Sent Email?' column to true or false for the AccountID\nfunction setEmailSent(sheetID, accountID, value) {\n  var ss = SpreadsheetApp.openById(sheetID).getSheetByName('Sheet1');\n  var val = ss.getRange('A:B').getValues();\n  var length = val.length;\n  for (var i = 1; i &lt; length; i++) {\n    if (val[i][0]) {\n      if (val[i][0] == accountID) {\n        var val = ss.getRange('B'+(i+1).toString());\n        val.setValue(value);\n        return 'set value to '+value;\n      }\n    }\n    else {\n      return 'could not find account ID '+accountID;\n    }\n  }\n}\n\n\/\/ Opens the corresponding Google Sheet to read whether an email has been sent or not from the account in question\nfunction getEmailSent(sheetID, accountID) {\n  var ss = SpreadsheetApp.openById(sheetID).getSheetByName('Sheet1');\n  var val = ss.getRange('A:B').getValues();\n  var length = val.length;\n  for (var i = 1; i &lt; length; i++) {\n    if (val[i][0]) {\n      if (val[i][0] == accountID) {\n        return val[i][1]\n      }\n    }\n    else {\n      var val = ss.getRange('A'+(i+1).toString());\n      val.setValue(accountID);\n      val = ss.getRange('B'+(i+1).toString());\n      val.setValue('false');\n      return false;\n    }\n  }\n}\n\n\/\/ Opens the corresponding Google Sheet to set the 'Impressions on last run' column to equal impressionsIn24Hours\nfunction setImpressions(sheetID, accountID, value) {\n  var ss = SpreadsheetApp.openById(sheetID).getSheetByName('Sheet1');\n  var val = ss.getRange('C:D').getValues();\n  var length = val.length;\n  for (var i = 1; i &lt; length; i++) {\n    if (val[i][0]) {\n      if (val[i][0] == accountID) {\n        var val = ss.getRange('D'+(i+1).toString());\n        val.setValue(value);\n        return 'set value to '+value;\n      }\n    }\n    else {\n      return 'could not find account ID '+accountID;\n    }\n  }\n}\n\n\/\/ Opens the corresponding Google Sheet to read number of impressions in the last 24 hours\nfunction getImpressions(sheetID, accountID) {\n  var ss = SpreadsheetApp.openById(sheetID).getSheetByName('Sheet1');\n  var val = ss.getRange('C:D').getValues();\n  var length = val.length;\n  for (var i = 1; i &lt; length; i++) {\n    if (val[i][0]) {\n      if (val[i][0] == accountID) {\n        return val[i][1]\n      }\n    }\n    else {\n      var val = ss.getRange('C'+(i+1).toString());\n      val.setValue(accountID);\n      val = ss.getRange('D'+(i+1).toString());\n      val.setValue(0);\n      return 0;\n    }\n  }\n}\n\n\/\/ Dates must be formatted for properly querying a specific date from AWQL\nDate.prototype.yyyymmdd = function() {\n    var yyyy = this.getFullYear().toString();\n    var mm = (this.getMonth()+1).toString();\n    var dd  = this.getDate().toString();\n    return yyyy + (mm[1]?mm:\"0\"+mm[0]) + (dd[1]?dd:\"0\"+dd[0]);\n}\n\nfunction getDateOneWeekBeforeToday() {\n    var tempDate = new Date();\n    tempDate.setDate(tempDate.getDate()-7)\n    var lastWeekDate = tempDate;\n    return lastWeekDate.yyyymmdd();\n}\n\nfunction getCurrentHour() {\n    today = new Date();\n    \/\/ Reporting on data using Eastern Standard Time\n    return today.getUTCHours()-5;\n}\n\nfunction setTimestamp(sheetID) {\n    var today = new Date();\n    var ss = SpreadsheetApp.openById(sheetID).getSheetByName('Sheet1');\n  var val = ss.getRange('F2');\n    val.setValue(today.toString());\n}\n\nfunction main() {\n\n    \/\/ Check if it is the first hour of the day. If it is, reset Sent Email? and Impressions on last run columns\n    if (getCurrentHour() == 0) {\n        Logger.log(resetEmailSentAndImpressions(SHEETID));\n    } else {\n        Logger.log(\"It is now hour \" + getCurrentHour() + \". Starting hourly processing.\");\n        Logger.log(\"\\n\");\n    }\n\n    setTimestamp(SHEETID);\n\n  while (accountIterator.hasNext()) {\n      var account = accountIterator.next();\n\n      \/\/ Switch to the account you want to process.\n      MccApp.select(account);\n\n      var ACCOUNTID = AdWordsApp.currentAccount().getCustomerId();\n      var ACCOUNTNAME = AdWordsApp.currentAccount().getName();\n\n      Logger.log(\"Started processing \" + ACCOUNTNAME + \" | \" + ACCOUNTID);\n\n      function sendWarningEmail(emailAddresses, subject, body) {\n          var finalSubject = \"WARNING - \" + subject + \" - \" + ACCOUNTNAME + \" (\" + ACCOUNTID + \")\";\n          var emailAddressesString = \"\";\n\n          for (var i = 0; i &lt; emailAddresses.length; i++) {\n              if (i &lt; emailAddresses.length-1) {\n                  emailAddressesString += emailAddresses[i] + \",\";\n              } else {\n                  emailAddressesString += emailAddresses[i];\n              }\n          }\n\n          MailApp.sendEmail({to: emailAddressesString, subject: finalSubject, htmlBody: body });\n          Logger.log(\"Sent email to \" + emailAddressesString);\n      }\n\n      function runQuery() {\n          var impressionsByHour = {};\n          var impressionsIn24Hours = 0;\n          var impressionsByHourLastWeek = {};\n          var impressionsIn24HoursLastWeek = 0;\n          var currentHour = getCurrentHour().toString();\n          var previousHour = (getCurrentHour()-1).toString();\n\n          var query = function(date, impressionsVar, impressionsIn24HoursVar) {\n              var query = AdWordsApp.report(\"SELECT Impressions, HourOfDay FROM ACCOUNT_PERFORMANCE_REPORT DURING \" + date);\n              var rows = query.rows();\n              while (rows.hasNext()) {\n                  var data = rows.next();\n                  var hour = parseFloat(data[\"HourOfDay\"]);\n                  impressionsVar[hour] = data[\"Impressions\"]\n              }\n\n              for (k in impressionsVar) {\n                  impressionsIn24HoursVar += parseInt(impressionsVar[k]);\n              }\n\n              \/\/ We return this so we can assign it outside of the function\n              return impressionsIn24HoursVar;\n          }\n\n          impressionsIn24Hours = query(\"TODAY\", impressionsByHour, impressionsIn24Hours);\n          \/\/ We pass in two dates separated by a comma and a space because of the nature of specific date requesting within AWQL\n          impressionsIn24HoursLastWeek = query(getDateOneWeekBeforeToday() + \", \" + getDateOneWeekBeforeToday(), impressionsByHourLastWeek, impressionsIn24HoursLastWeek);\n\n                    \/\/ Get the total impressions on last run before we overwrite it with the current total impressions in last 24 hours\n                  var totalImpressionsOnLastRun = getImpressions(SHEETID, ACCOUNTID);\n                getEmailSent(SHEETID, ACCOUNTID);\n                  Logger.log(setImpressions(SHEETID, ACCOUNTID, impressionsIn24Hours));\n\n                    var subject = \"Warning on Adwords Account\";\n                    var body = \"&lt;h3&gt;Whoa there cowboy! One of your accounts has gotten 0 impressions.&lt;\/h3&gt;&lt;strong&gt;Account: &lt;\/strong&gt;\"+ACCOUNTNAME+\n                    \"&lt;br&gt;&lt;strong&gt;ID: &lt;\/strong&gt;\"+ACCOUNTID+\"&lt;br&gt;&lt;strong&gt;Impressions during hour \"+\n                    previousHour+\":&lt;\/strong&gt; \"+(impressionsIn24Hours-totalImpressionsOnLastRun)+\"&lt;br&gt;&lt;strong&gt;Impressions in the last 24 hours: &lt;\/strong&gt;\"+\n                    impressionsIn24Hours+\"&lt;br&gt;&lt;strong&gt;Impressions during hour \"+previousHour+\" last week:&lt;\/strong&gt; \"+impressionsByHourLastWeek[getCurrentHour()-1] +\n                    \"&lt;br&gt;&lt;strong&gt;Impressions in the last 24 hours last week: &lt;\/strong&gt;\"+impressionsIn24HoursLastWeek+\"&lt;br&gt;&lt;br&gt;Since this account has previously demonstrated \" +\n                    \" impressions during this period, it is highly recommended that you contact your account administrators to find out the cause.&lt;br&gt;&lt;br&gt;\"+\n                    \"Sincerely,&lt;br&gt;&lt;i&gt;Your Management Team&lt;\/i&gt;\";\n\n                    \/\/ Check to make sure total impressions on most recent run is GREATER THAN total impressions on last run. (That would mean we are getting impressions) (Unless it's the first hour of the day)\n                    if (impressionsIn24Hours &gt; totalImpressionsOnLastRun) {\n                        Logger.log(\"Everything looks okay! You've gotten impressions since the last time I ran!\");\n                    }\n                    \/\/ If total impressions on most recent run is LESS THAN total impression on last run, it must mean that this is the first run of the day, because it's impossible to lose impression that we had previously. Reset data in the sheet.\n                    else if (impressionsIn24Hours &lt; totalImpressionsOnLastRun) {\n                        Logger.log(\"First run of the day.\");\n                    }\n                    \/\/ If the two are EQUAL, it means that since the last time the script ran, no new impressions have been recorded\n                    else if (impressionsIn24Hours == totalImpressionsOnLastRun) {\n                        \/\/ We have to go back a week and check if it is normal for there to be no impressions during the previous hour\n                        \/\/ (We check to make sure there are more than 200 impressions last week instead of zero to filter out smaller accounts who have inconsistent impression trends at off peak hours.)\n                        if (impressionsByHourLastWeek[getCurrentHour()-1] &gt; 200) {\n                            \/\/ There is a problem, but let's see if we've already sent an email\n                            if (getEmailSent(SHEETID, ACCOUNTID) == false) {\n                                \/\/ We really have a problem.\n                                Logger.log(\"Warning! You have no new impressions on this account but you had impressions during this hour last week!\");\n                                sendWarningEmail(EMAIL_ADDRESSES_TO_NOTIFY, subject, body);\n                                setEmailSent(SHEETID, ACCOUNTID, 'true');\n                            }\n                            else {\n                                Logger.log(\"Email already sent today\");\n                            }\n                        }\n                        else {\n                            Logger.log(\"You have no new impressions on this account during the last hour, but this is consistent with last week's data. (Or the number of impressions falls below the cut off point of 200.\");\n                        }\n                    }\n                    Logger.log(\"Impressions last hour: \" + (impressionsIn24Hours - totalImpressionsOnLastRun) + \".\");\n                    Logger.log(\"Impressions last hour (last week): \" + impressionsByHourLastWeek[getCurrentHour()-1] + \".\");\n                    Logger.log(\"\\n\")\n      }\n      runQuery();\n  }\n  Logger.log(\"Script finished\");\n}\n\/\/ ---------------------------END-----------------------------\/\/\n<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Keeping an eye on the health of your Adwords accounts can be an overwhelming task if you\u2019re managing many of them. Thankfully, using Google Adwords Scripts can help take away some of the hassle and automate many tasks and processes. One essential task that many skilled developers have attempted to automate is making sure your&#8230;<\/p>\n","protected":false},"author":6,"featured_media":1378,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"thumbnail_src":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/DPBlogPost-EmergencyDetectorTool1-2-300x168.jpg","thumbnail_medium_src":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/DPBlogPost-EmergencyDetectorTool1-2.jpg","featured_image_src":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2018\/06\/DPBlogPost-EmergencyDetectorTool1-2.jpg","author_avatar_src":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-content\/uploads\/2024\/09\/jordan1.webp","author_name":"Jordan Lagan","category_labels":["PPC"],"tag_labels":[],"_links":{"self":[{"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/posts\/529"}],"collection":[{"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/comments?post=529"}],"version-history":[{"count":7,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/posts\/529\/revisions"}],"predecessor-version":[{"id":1143,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/posts\/529\/revisions\/1143"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/media\/1378"}],"wp:attachment":[{"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/media?parent=529"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/categories?post=529"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.digitalposition.com\/resources\/blog\/wp-json\/wp\/v2\/tags?post=529"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}