This script should be used in conjunction with the Budget Automation tool, but can also be used on its own to ensure that the account's campaigns are paused if & when they go over the monthly budget listed on the Budget Input Sheet used for our Budget Tracker. You can also make some quick adjustments on a separate spreadsheet that connects the script to the Budget Tracker to add a bit more customization to what qualifies the script to turn off all campaigns.
The script will also re-enable any campaigns that get paused at the beginning of the next month, and will send an email anytime campaigns in the account are paused or enabled.
Note that the script will apply labels to Campaigns that get paused and remove them when the campaigns are re-enabled. So be wary if you are using Campaign Labels for reporting or other purposes!
NOTE: If you don't want to use the Monthly Budget to cap a campaign, but instead just want to cap any campaign when it overspends some set budget, you can use this script, instead.
Make a copy of the sheet above
Rename the sheet to "<Client Name> | Budget Cap" and place it somewhere in your drive where you can find it to stay organized – this will only belong to the one client you're setting it up for!
Scroll to the bottom of the sheet under "Link Authorizations" and click cell D26, as instructed on the sheet. Click Approve on the link to the budget tracker. This will just import (1) the list of all clients on that tracker and (2) a filtered list of the budgets you want to use for this script.
Once that turns green and is all set, scroll back up to the top.
Add your email address in the top right corner of the sheet. Email notifications about campaign status changes from this script will be sent to this address if & when they occur.
Select the account you want this sheet to function for. One sheet, one script, one account :)
That's it! Monthly budgets will update automatically from the Budget Tracker and the script will check the budget value every hour for updates.
But you'll notice that beneath the account selector, you can add an "Adjustment" to the budget if you'd like. You can use this to either add some allowance for budget overages or artificially lower the budget (if you set it to a negative value). Just as a way to be a bit more flexible with how this works! If you don't want to add any adjustments, you can either leave it blank or enter zero. But note that whatever you enter in this cell will not change on its own (like the monthly budget will every month). So be sure to come back to it and make sure that it's set up properly if you add anything here.
To get started, go to your Google Ads account, click Tools > Bulk Actions > Scripts
You'll be creating one new scripts. The instructions are below!
Create a new script, name it "Budget Cap" (...or whatever you want).
Copy and paste the code below into the script, and change the SPREADSHEET_URL_HERE_LEAVE_SINGLE_QUOTES_IN_PLACE to the URL of the spreadsheet that you created above. That's it!
When you've pasted the code in and added the URL, hit Save and then click Run. You'll be prompted to authorize a bunch of stuff. You may have to click Run again after authorizing. Once the script runs fully, you should be all set.
Go back to the Scripts page, and set the "Frequency" of this script to "Hourly"
Note that when this script runs moving forward, it will generate one error and 4 log statements. The error should just be regarding the creation of the Label – if that's the case (you can click on the Error icon), no worries! The script should still function just fine, but definitely keep an eye on it.
Feel free to run a test on this script by adding an Adjustment on the Spreadsheet above that lowers the budget below the spend from This Month. The campaigns should pause and be labelled and you should receive an email. If that works, you can just change the adjustment back and run the script once again and it will set everything back to normal (and email you again).
What This Script Does:
Checks the Spreadsheet for the Budget in Cell D7 every hour
IF: Spend from THIS MONTH is GREATER THAN OR EQUAL TO the budget listed in that cell, all active, delivering campaigns in the account are paused and the label: "Paused For Monthly Budget Overages" is added to the campaigns (other labels stay in place). Email address at the top of the sheet receives notification.
IF: Spend from THIS MONTH is LESS THAN the budget listed in that cell, all paused campaigns with the label "Paused For Monthly Budget Overages" are enabled and that particular label is removed (other labels stay in place). Email address at the top of the sheet receives notification.
IF: The script runs and the campaigns are already appropriately paused/enabled per the rules above, nothing gets changed and the operator is not notified by email.
NOTE: The way the script is structured, it should always throw one error after the script runs for the first time – this is just a message letting you know that the label "Paused For Monthly Budget Overages" already exists and therefore was not created. The script should still log 4 notes and should still function normally on its hourly trigger.
function main() {
var SPREADSHEET_URL = 'SPREADSHEET_URL_HERE_LEAVE_SINGLE_QUOTES_IN_PLACE';
// Name of the specific sheet in the spreadsheet.
var SHEET_NAME = 'Budget Overview';
var ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var sheet = ss.getSheetByName(SHEET_NAME);
// Get this month's budget & contact email from spreadsheet
var thisMonthBudget = sheet.getRange('D7');
Logger.log(thisMonthBudget.getValue());
var email = sheet.getRange('E1').getValue();
var emailaddress = email.toString();
Logger.log(emailaddress);
// Get this account ID and Name for email notifications
var accountId = AdWordsApp.currentAccount().getCustomerId();
Logger.log(accountId);
var accountName = AdWordsApp.currentAccount().getName();
Logger.log(accountName);
//update the value of monthlyBudget based on your requirement
var monthlyBudget = thisMonthBudget.getValue();
var totalCost = 0;
var alltotalCost = 0;
var campaignsList = [];
var pausedcampaignsList = [];
AdsApp.createLabel("Paused For Monthly Budget Overages");
/**
* Retrieves the names of all labels in the account.
*
* @return {Array.<string>} An array of label names.
*/
function getAccountLabelNames() {
var labelNames = [];
var iterator = AdsApp.labels().get();
while (iterator.hasNext()) {
labelNames.push(iterator.next().getName());
}
return labelNames;
}
/**
* Checks that the account has a label for each rule and
* creates the rule's label if it does not already exist.
* Throws an exception if a rule does not have a labelName.
*/
function ensureAccountLabels() {
var labelNames = getAccountLabelNames();
var labelName = "Paused For Monthly Budget Overages";
if (!labelName) {
throw 'Missing labelName!';
}
if (labelNames.indexOf(labelName) == -1) {
AdsApp.createLabel(labelName);
labelNames.push(labelName);
}
}
///ACTIVE CAMPAIGNS LIST BELOW///
var campaignIterator = AdWordsApp.campaigns()
.withCondition("Status = ENABLED")
.withCondition("ServingStatus = SERVING")
.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
//save in campaignsList the list of campaigns object.
campaignsList.push(campaign);
//use THIS_MONTH to get data for all days in the current month
var stats = campaign.getStatsFor('THIS_MONTH');
var campaignCost = stats.getCost();
totalCost += campaignCost;
}
///PAUSED CAMPAIGNS LIST BELOW///
var pausedcampaignIterator = AdWordsApp.campaigns()
.withCondition("LabelNames CONTAINS_ANY ['Paused For Monthly Budget Overages']")
.get();
while (pausedcampaignIterator.hasNext()) {
var pausedcampaign = pausedcampaignIterator.next();
//save in pausedcampaignsList the list of campaigns object.
pausedcampaignsList.push(pausedcampaign);
//use THIS_MONTH to get data for all days in the current month
var allstats = pausedcampaign.getStatsFor('THIS_MONTH');
var allcampaignCost = allstats.getCost();
alltotalCost += allcampaignCost;
}
//email structure
function sendPauseEmailAlert() {
MailApp.sendEmail(emailaddress,
accountName + ' (' + accountId + ') Campaigns Paused Due To Overspend' ,
'Campaigns have spent $' + totalCost.toFixed(2) + ' and have surpassed the budget of $' + monthlyBudget.toFixed(2) + ' and have been paused. See account for details.');
}
function sendActivationEmailAlert() {
MailApp.sendEmail(emailaddress,
accountName + ' (' + accountId + ') Campaigns Reactivated After Last Month\'s Overspend' ,
'Your campaigns have been reactivated. If they surpass this Month\'s budget of $' + monthlyBudget.toFixed(2) + ', they will get paused again. Visit the budget sheet or your campaigns to make adjustments.');
}
//if totalCost of campaigns is equal to or greater than defined monthlyBudget, pause the campaigns, apply the pause label
if (totalCost >= monthlyBudget && campaignsList.length > 0){
for (var i = 0; i < campaignsList.length; i++) {
var campaign = campaignsList[i];
Logger.log(campaign.getName())
campaign.pause();
campaign.applyLabel('Paused For Monthly Budget Overages');
}
sendPauseEmailAlert();
}
//if totalCost of campaigns is less than defined monthlyBudget, enable the campaigns, remove the pause label
if (alltotalCost < monthlyBudget && pausedcampaignsList.length > 0){
for (var i = 0; i < pausedcampaignsList.length; i++) {
var pausedcampaign = pausedcampaignsList[i];
Logger.log(pausedcampaign.getName())
pausedcampaign.enable();
pausedcampaign.removeLabel('Paused For Monthly Budget Overages');
}
sendActivationEmailAlert();
}
}