Monthly Budget Enforcer Google Ads script

As a Google Ads Manager managing a dozen different Google Ads accounts for local businesses across the country. I find one of most common requirement a local business owner would like to have control over is their monthly spending. Very understandable, as a business owner myself, an unchecked monthly spending can lead us to a business disaster.

So, on a monthly basis ever since I started working with local and small business owners more than a decade ago. I will always get requests from clients to stop their account as soon as their Google Ads account reaches a certain amount whether it be $500 a month or $5,000 a month. While we can always set the daily budget to an amount equal to their monthly budget divided by 30.5, and allocate the daily budget to several campaigns it’s not always clear cut.

With the repeated requests from clients, I developed a budgeting script that will enforce monthly budget for an account and also turn it back on if a new month starts. While you can use Google Ads automated rules, the most granular running frequency for automated rules is daily. So if you reach your monthly budget mid day and your automated rules won’t run until 23 hours later, then most likely you’ll be over budget. 

And not long after, an angry and unsatisfied client will be giving you a call. Well some are more forgiving but some will immediately fire you.

This is the Google Ads Campaign Budgeting Script: Monthly Enforcer script I’ve developed. This monthly budget script will allow you to define a monthly max budget threshold and the script will turn off your campaigns automatically. It will also automatically turn the campaigns on when a new month rolls around.

/**
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the LeadCamp PSL License.
 *
 * This source file is subject to the LeadCamp PSL License that is
 * bundled with this package in the license.txt file.
 *
 * @name       Monthly Budget Enforcer for a Campaign or Group of Campaigns.
 * @desc       This script allows you to set a hard stop for a campaign or group 
 *             of campaigns if the campaign(s) have reached your budget for the month. 
 *             Say for example, you have a campaign or a group of campaigns that you want to 
 *             completely stop running if their total spend has already reached $1000 for the 
 *             current month. You can use this script to pause and unpause the campaign or group 
 *             of campaigns automatically.
 * @version    101.01
 * @author     Harris Lim
 * @license    LeadCamp PSL
 * @copyright  (c) 2008-Beyond, LeadCamp, Inc
 * @link       https://searchadspro.com/google-ads-campaign-budgeting-scripts/
 */
// this is your monthly budget.
var monthlyBudget = 1000;
// assumptions only tag campaigns you want to process with the label inside labelToCheck.
var labelToCheck = 'Budget'; //default is Budget label

function main() {
  runScript();
}
function runScript(){
  createLabelIfNotExists(labelToCheck);
  var campaigns = [];
  var costThisMonth = 0;
  var labelItr = AdsApp.labels().withCondition("Name = '" + labelToCheck + "'").get();
  if(labelItr.totalNumEntities()>0){
    var campaignItr = labelItr.next().campaigns().get();
    while(campaignItr.hasNext()){
      var campaign = campaignItr.next();
      campaigns.push(campaign);
      costThisMonth += campaign.getStatsFor("THIS_MONTH").getCost();
    }
    Logger.log("Spend this month:" + costThisMonth);
    if(costThisMonth>monthlyBudget){
      for(i=0;i<campaigns.length;i++){
        if(campaigns[i].isEnabled()){
          campaigns[i].pause();
        }
      }
    }else{
      for(i=0;i<campaigns.length;i++){
        if(!campaigns[i].isEnabled()){
          campaigns[i].enable();
        }
      }
    }
  }else{
    Logger.log("Error: The label [" + labelToCheck + "] not associated to any campaign.");
  }
}
function createLabelIfNotExists(labelName){
  var labelIterator = AdWordsApp.labels()
        .withCondition('Name CONTAINS "' + labelName +'"')
        .get();
  if(labelIterator.totalNumEntities() === 0){
    createALabel(labelName);
    labelIterator = AdWordsApp.labels()
      .withCondition('Name CONTAINS "' + labelName +'"')
      .get();    
  }
  Logger.log(labelName)
  //return labelIterator.next();
}
function createALabel(theLabel){
  AdWordsApp.createLabel(theLabel,'This label is created by the SearchAdsPro.com Monthly Budget Script ','#F4CCCC');
} 

 

Explanation of the Campaign Budgeting Monthly Enforcer Google Ads Script:

On line 35 the script will load the label specified on line 26. 

var labelItr = AdsApp.labels().withCondition("Name = '" + labelToCheck + "'").get();

Then the script will load all the campaigns associated to the label on line 37.

var campaignItr = labelItr.next().campaigns().get();

The the script will add up each campaign’s total cost for this month on line 41.

costThisMonth += campaign.getStatsFor("THIS_MONTH").getCost();

Then on line 44, the script will check if the total cost is greater than the budget specified on line 24.

if(costThisMonth>monthlyBudget){

On line 45, If the cost exceeds the monthly budget, it will go through all enabled campaigns and pause them.

for(i=0;i<campaigns.length;i++){
  if(campaigns[i].isEnabled()){
    campaigns[i].pause();
  }
}

But if the cost is below the monthly budget, the opposite will happen, the script will enable all disabled campaigns.

for(i=0;i<campaigns.length;i++){
  if(!campaigns[i].isEnabled()){
    campaigns[i].enable();
  }
}

Steps to use:

Step 1: Copy the script and paste it to your Google Ads Account Script section.

Step 2: Change line 24 to your own budget – whole number only 2000, 1000, 5000 etc.

// this is your monthly budget.
var monthlyBudget = 2000;
// assumptions only tag campaigns you want to process with the label inside labelToCheck.
var labelToCheck = 'Budget'; //default is Budget label

Step 3: Use Budget Label or Change Your Label to something meaningful and label all your campaigns that you want to turn off and on with the label at line 26.

// this is your monthly budget.
var monthlyBudget = 2000;
// assumptions only tag campaigns you want to process with the label inside labelToCheck.
var labelToCheck = 'Budget'; //default is Budget label

 

Testing Your Script

Step 1: Add the following code after line 29. You would a test amount that is currently below your actual spend and another amount that is above your current spend. This will allow you to test turning off the campaigns as well as turning them back on.

function main() {
  runScript();
  monthlyBudget = 100; // a number that's below your actual spend
  runScript();
  monthlyBudget = 1000; // a number above your actual spend
  runScript();
}

Step 2: Be sure you have the campaigns associated to your label defined on line 26.

Step 3: Do a preview of your script

Step 4: You should see your campaigns being paused and enabled verifying that your script works.

 

Step 5: Clean up the code you added and save your Google Ads script.

Monthly Budget Enforcer Google Ads Script Variations

Variation 1: Monthly Budget Enforcer Google Ads Script for Groups of Campaigns

Now, what if your client is a law firm with 3 different practice areas. And each practice area has it’s own set of campaigns as well as budget? Say they want to allocate $500 towards real estate law, $750 towards personal injury and $250 towards business law. How would you use the above Google Ads Budget Management script to handle this scenario? you can’t here’s an expanded script that will allow you to do that.

We would need to define a label for each practice area and also specify how much budget we are allocating to each practice area in the script. Below the monthly enforcer script will let you define group of campaigns together and enforce your monthly budget accordingly.

Here’s the script:

/**
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the LeadCamp PSL License.
 *
 * This source file is subject to the LeadCamp PSL License that is
 * bundled with this package in the license.txt file.
 *
 * @name       Monthly Budget Enforcer for a Campaign or Group of Campaigns.
 * @desc       This script allows you to set a hard stop for a campaign or group 
 *             of campaigns if the campaign(s) have reached your budget for the month. 
 *             Say for example, you have a campaign or a group of campaigns that you want to 
 *             completely stop running if their total spend has already reached $1000 for the 
 *             current month. You can use this script to pause and unpause the campaign or group 
 *             of campaigns automatically.
 * @version    101.01
 * @author     Harris Lim
 * @license    LeadCamp PSL
 * @copyright  (c) 2008-Beyond, LeadCamp, Inc
 * @link       https://searchadspro.com/google-ads-campaign-budgeting-scripts/
 */
// this is your monthly budget.
var GroupBudgetDefinition = [
  {GroupLabel:"Group1", GroupBudget: 750}
  ,{GroupLabel:"Group2", GroupBudget: 500}
  ,{GroupLabel:"Group3", GroupBudget: 250}
  ];

function main() {
  for(i=0;i<GroupBudgetDefinition.length;i++){
    runScript(
      GroupBudgetDefinition[i].GroupLabel,
      GroupBudgetDefinition[i].GroupBudget);
  }
}
function runScript(labelToCheck,monthlyBudget){
  createLabelIfNotExists(labelToCheck);
  var campaigns = [];
  var costThisMonth = 0;
  var labelItr = AdsApp.labels().withCondition("Name = '" + labelToCheck + "'").get();
  if(labelItr.totalNumEntities()>0){  
    var campaignItr = labelItr.next().campaigns().get();
    while(campaignItr.hasNext()){
      var campaign = campaignItr.next();
      campaigns.push(campaign);
      costThisMonth += campaign.getStatsFor("THIS_MONTH").getCost();
    }
    Logger.log("Spend this month:" + costThisMonth);
    if(costThisMonth>monthlyBudget){
      for(i=0;i<campaigns.length;i++){
        if(campaigns[i].isEnabled()){
          campaigns[i].pause();
        }
      }
    }else{
      for(i=0;i<campaigns.length;i++){
        if(!campaigns[i].isEnabled()){
          campaigns[i].enable();
        }
      }
    }
  }
}
function createLabelIfNotExists(labelName){
  var labelIterator = AdWordsApp.labels()
        .withCondition('Name CONTAINS "' + labelName +'"')
        .get();
  if(labelIterator.totalNumEntities() === 0){
    createALabel(labelName);
    labelIterator = AdWordsApp.labels()
      .withCondition('Name CONTAINS "' + labelName +'"')
      .get();    
  }
  Logger.log(labelName)
  //return labelIterator.next();
}
function createALabel(theLabel){
  AdWordsApp.createLabel(theLabel,'This label is created by the SearchAdsPro.com Monthly Budget Script ','#F4CCCC');
} 

 

Below is the code you would need to change for your purposes. On line 25, 26 and 27 you would define a Label to identify a group of campaigns and define the max budget for that group.

// this is your monthly budget.
var GroupBudgetDefinition = [
  {GroupLabel:"Group1", GroupBudget: 100}
  ,{GroupLabel:"Group2", GroupBudget: 100}
  ,{GroupLabel:"Group3", GroupBudget: 250}
  ];

You can use the default labels or change it and you need to change the GroupBudget accordingly. And you should be good to go.

 

Variation 2: Running the Monthly Enforcer Script in Your MCC Account

Alright, what if you want to run this Google Ads script in your MCC account. Is there a simple modification you can do? Yes, there is a simple one I might add.. you need to add the code below right after your the function main(). Where XXX-XXX-XXXX is your account number.

var mccAccount = AdsApp.currentAccount();
var childAccounts = AdsManagerApp.accounts().withIds(['XXX-XXX-XXXX']).get();
var childAccount = childAccounts.next();
AdsManagerApp.select(childAccount);

It should look like this for the original script:

function main() {
  var mccAccount = AdsApp.currentAccount();
  var childAccounts = AdsManagerApp.accounts().withIds(['XXX-XXX-XXXX']).get();
  var childAccount = childAccounts.next();
  AdsManagerApp.select(childAccount);  

  runScript();
}

It should look like this for Variation 1:

function main() {
  var mccAccount = AdsApp.currentAccount();
  var childAccounts = AdsManagerApp.accounts().withIds(['XXX-XXX-XXXX']).get();
  var childAccount = childAccounts.next();
  AdsManagerApp.select(childAccount);  

  for(i=0;i<GroupBudgetDefinition.length;i++){
    runScript(
      GroupBudgetDefinition[i].GroupLabel,
      GroupBudgetDefinition[i].GroupBudget);
  }
}

 

 

Variation 3: Change the Budget without Changing this Ad Script if a Client ask you to change the current month’s budget.

This requirement came from one of my clients. They wanted to change the budget almost every month but they didn’t want to update the Monthly Budget Enforcer Google Ads script to avoid making a mistake and breaking the script this is completely a valid concern. This is because most Google Ads managers are not programmers and could easily mess up the code. 

I proposed using Shared Budgets for them to enter new budget for the month whether there is a change or not. This shared budget won’t be used in any campaigns but will serve as a place holder for my modified Monthly Budget Enforcer script. Their script had a few modifications that are irrelevant to this post so I had to rewrite it without their customization.

Here’s the tested Google Ads Script Monthly Budget Enforcer using Shared Budget:

/**
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the LeadCamp PSL License.
 *
 * This source file is subject to the LeadCamp PSL License that is
 * bundled with this package in the license.txt file.
 *
 * @name       Monthly Budget Enforcer for a Campaign or Group of Campaigns.
 * @desc       This script allows you to set a hard stop for a campaign or group 
 *             of campaigns if the campaign(s) have reached your budget for the month. 
 *             Say for example, you have a campaign or a group of campaigns that you want to 
 *             completely stop running if their total spend has already reached $1000 for the 
 *             current month. You can use this script to pause and unpause the campaign or group 
 *             of campaigns automatically.
 * @version    101.01
 * @author     Harris Lim
 * @license    LeadCamp PSL
 * @copyright  (c) 2008-Beyond, LeadCamp, Inc
 * @link       https://searchadspro.com/google-ads-campaign-budgeting-scripts/
 */
// this is your monthly budget.
var GroupBudgetDefinition = [
  {GroupLabel:"Group1", GroupBudget: 750}
  ,{GroupLabel:"Group2", GroupBudget: 500}
  ,{GroupLabel:"Group3", GroupBudget: 250}
  ];

function main() {
  for(i=0;i<GroupBudgetDefinition.length;i++){
    runScript(
      GroupBudgetDefinition[i].GroupLabel,
      GroupBudgetDefinition[i].GroupBudget);
  }
}
function runScript(labelToCheck,monthlyBudget){
  createLabelIfNotExists(labelToCheck);
  var campaigns = [];
  var costThisMonth = 0;
 
  var budgetSelector = AdsApp
  .budgets()
  .withCondition("BudgetName = '" + labelToCheck + "'");
  
  var budgetIterator = budgetSelector.get();
  if(budgetIterator.hasNext()){
    var budget = budgetIterator.next();
    monthlyBudget = budget.getAmount();
  }    
  
  var labelItr = AdsApp.labels().withCondition("Name = '" + labelToCheck + "'").get();
  if(labelItr.totalNumEntities()>0){  
    var campaignItr = labelItr.next().campaigns().get();
    while(campaignItr.hasNext()){
      var campaign = campaignItr.next();
      campaigns.push(campaign);
      costThisMonth += campaign.getStatsFor("THIS_MONTH").getCost();
    }
    Logger.log("Spend this month:" + costThisMonth);
    if(costThisMonth>monthlyBudget){
      for(i=0;i<campaigns.length;i++){
        if(campaigns[i].isEnabled()){
          campaigns[i].pause();
        }
      }
    }else{
      for(i=0;i<campaigns.length;i++){
        if(!campaigns[i].isEnabled()){
          campaigns[i].enable();
        }
      }
    }
  }
}
function createLabelIfNotExists(labelName){
  var labelIterator = AdWordsApp.labels()
        .withCondition('Name CONTAINS "' + labelName +'"')
        .get();
  if(labelIterator.totalNumEntities() === 0){
    createALabel(labelName);
    labelIterator = AdWordsApp.labels()
      .withCondition('Name CONTAINS "' + labelName +'"')
      .get();    
  }
  Logger.log(labelName)
  //return labelIterator.next();
}
function createALabel(theLabel){
  AdWordsApp.createLabel(theLabel,'This label is created by the SearchAdsPro.com Monthly Budget Script ','#F4CCCC');
} 

 

The above code have a few additional lines wherein it uses a Google Ads Shared Budget’s daily budget as the monthly budget limit. You need to make sure you have a shared budget named similar to your label, give it the max amount you want to spend say $1,500 or something and set that as the “Daily Budget” and you are ready to go. Be sure not use this shared budget anywhere else.

These are the new lines for the above script:

var budgetSelector = AdsApp
.budgets()
.withCondition("BudgetName = '" + labelToCheck + "'");

var budgetIterator = budgetSelector.get();
if(budgetIterator.hasNext()){
  var budget = budgetIterator.next();
  monthlyBudget = budget.getAmount();
} 

 

Variation 4: Supporting Shopping and Video Campaigns

What if you have shopping campaigns and video campaigns? I tested this since I have clients with shopping campaigns and noticed that the labels.campaigns() function only returns search and display campaigns. To be able to handle this correctly we cannot utilize labels as a way to reach the campaigns but instead use the campaign selectors for each kind of campaign to reach all the campaigns.

This is the label code that won’t capture shopping and video campaigns.

var campaignItr = labelItr.next().campaigns().get();

This is the replacement code that will handle all 4 campaign types:Search, Display, Shopping and Video campaigns.

We utilize the withCondition and find campaigns with the label to get to the campaigns.

var campaignItr = AdsApp
	.campaigns()
	.withCondition("LabelNames CONTAINS_ANY ['" + labelToCheck + "']")
	.get();
while(campaignItr.hasNext()){
  var campaign = campaignItr.next();
  campaigns.push(campaign);
  var campaignCost = campaign.getStatsFor("THIS_MONTH").getCost();
  costThisMonth += campaignCost;
  Logger.log(campaign.getName() + ":" + campaignCost + ":" + costThisMonth);
}
var shoppingCampaignItr = AdsApp
	.shoppingCampaigns()
.withCondition("LabelNames CONTAINS_ANY ['" + labelToCheck + "']")
.get();
while(shoppingCampaignItr.hasNext()){
  var campaign = shoppingCampaignItr.next();
  campaigns.push(campaign);
  var campaignCost = campaign.getStatsFor("THIS_MONTH").getCost();
  costThisMonth += campaignCost;
  Logger.log(campaign.getName() + ":" + campaignCost + ":" + costThisMonth);
}  
var videoCampaignItr = AdsApp
	.videoCampaigns()
.withCondition("LabelNames CONTAINS_ANY ['" + labelToCheck + "']")
.get();
while(videoCampaignItr.hasNext()){
  var campaign = videoCampaignItr.next();
  campaigns.push(campaign);
  var campaignCost = campaign.getStatsFor("THIS_MONTH").getCost();
  costThisMonth += campaignCost;
  Logger.log(campaign.getName() + ":" + campaignCost + ":" + costThisMonth);
}  

So the full code for this change is below. Do note I added video campaign code in there but since I didn’t test it on an account with video campaign you will need to test this yourself.

/**
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the LeadCamp PSL License.
 *
 * This source file is subject to the LeadCamp PSL License that is
 * bundled with this package in the license.txt file.
 *
 * @name       Monthly Budget Enforcer for a Campaign or Group of Campaigns.
 * @desc       This script allows you to set a hard stop for a campaign or group 
 *             of campaigns if the campaign(s) have reached your budget for the month. 
 *             Say for example, you have a campaign or a group of campaigns that you want to 
 *             completely stop running if their total spend has already reached $1000 for the 
 *             current month. You can use this script to pause and unpause the campaign or group 
 *             of campaigns automatically.
 * @version    101.01
 * @author     Harris Lim
 * @license    LeadCamp PSL
 * @copyright  (c) 2008-Beyond, LeadCamp, Inc
 * @link       https://searchadspro.com/google-ads-campaign-budgeting-scripts/
 */
// this is your monthly budget.
var GroupBudgetDefinition = [
  {GroupLabel:"MonthlyBudget1", GroupBudget: 4000}
  ,{GroupLabel:"MonthlyBudget2", GroupBudget: 10}
  ,{GroupLabel:"MonthlyBudget3", GroupBudget: 10}
  ];

function main() {
  for(i=0;i<GroupBudgetDefinition.length;i++){
    runScript(
      GroupBudgetDefinition[i].GroupLabel,
      GroupBudgetDefinition[i].GroupBudget);
  }
}
function runScript(labelToCheck,monthlyBudget){
  createLabelIfNotExists(labelToCheck);
  var campaigns = [];
  var costThisMonth = 0;
 
  var budgetSelector = AdsApp
  .budgets()
  .withCondition("BudgetName = '" + labelToCheck + "'");
  
  var budgetIterator = budgetSelector.get();
  if(budgetIterator.hasNext()){
    var budget = budgetIterator.next();
    monthlyBudget = budget.getAmount();
  }    

  var campaignItr = AdsApp
  	.campaigns()
  	.withCondition("LabelNames CONTAINS_ANY ['" + labelToCheck + "']")
  	.get();
  while(campaignItr.hasNext()){
    var campaign = campaignItr.next();
    campaigns.push(campaign);
    var campaignCost = campaign.getStatsFor("THIS_MONTH").getCost();
    costThisMonth += campaignCost;
    Logger.log(campaign.getName() + ":" + campaignCost + ":" + costThisMonth);
  }
  var shoppingCampaignItr = AdsApp
  	.shoppingCampaigns()
  .withCondition("LabelNames CONTAINS_ANY ['" + labelToCheck + "']")
  .get();
  while(shoppingCampaignItr.hasNext()){
    var campaign = shoppingCampaignItr.next();
    campaigns.push(campaign);
    var campaignCost = campaign.getStatsFor("THIS_MONTH").getCost();
    costThisMonth += campaignCost;
    Logger.log(campaign.getName() + ":" + campaignCost + ":" + costThisMonth);
  }  
  var videoCampaignItr = AdsApp
  	.videoCampaigns()
  .withCondition("LabelNames CONTAINS_ANY ['" + labelToCheck + "']")
  .get();
  while(videoCampaignItr.hasNext()){
    var campaign = videoCampaignItr.next();
    campaigns.push(campaign);
    var campaignCost = campaign.getStatsFor("THIS_MONTH").getCost();
    costThisMonth += campaignCost;
    Logger.log(campaign.getName() + ":" + campaignCost + ":" + costThisMonth);
  }  

  Logger.log("Spend this month:" + costThisMonth);
  Logger.log("Monthly budget:" + monthlyBudget);
  if(costThisMonth>monthlyBudget){
    for(i=0;i<campaigns.length;i++){
      if(campaigns[i].isEnabled()){
        campaigns[i].pause();
      }
    }
  }else{
    for(i=0;i<campaigns.length;i++){
      if(!campaigns[i].isEnabled()){
        campaigns[i].enable();
      }
    }
  }

}
function createLabelIfNotExists(labelName){
  var labelIterator = AdWordsApp.labels()
        .withCondition('Name CONTAINS "' + labelName +'"')
        .get();
  if(labelIterator.totalNumEntities() === 0){
    createALabel(labelName);
    labelIterator = AdWordsApp.labels()
      .withCondition('Name CONTAINS "' + labelName +'"')
      .get();    
  }
  Logger.log(labelName)
  //return labelIterator.next();
}
function createALabel(theLabel){
  AdWordsApp.createLabel(theLabel,'This label is created by the SearchAdsPro.com Monthly Budget Script ','#F4CCCC');
} 

 

MCC Multi Account Variation : Running the Variation 2 in the MCC to control multiple accounts

Key benefits are
1) Control the budget of several groups of campaigns within an account across different accounts in one centralized location. This allows you to save a lot of time managing many accounts, it’s great for Google Ads Agencies managing dozens of accounts just like myself.
2) Option to control the budget of the groups of campaign within an account across different accounts without using the centralized location. This allows you to control the budget of each group of campaign inside the account itself and still allow you to manage other accounts using a centralize location.

Important: When you buy a script or share this page on your social media account. You will help fund more free scripts in the future.