Google Ads Scripts Image

Introduction to Google Ads Scripts

Using Google Ads scripts is essential to anyone looking to automate any of the more repetitive parts of account management.

Here at Brainlabs, we can’t get enough of scripts. We use them all the time, from something as simple as sending an hourly spend email to much more complex bid management systems that work across multiple accounts. They can be used to adjust ads and bids based on the weather, exchange rates, live betting odds, social media activity, and more! You can see some examples of cool stuff we’ve built on our open-source Google Ads scripts directory. And if you want to use some of our technology that’s arrived back from the future then sign up for one of our paid plans on the Brainlabs Tech Stack.

In this article we’ll cover the following:

  • Why you need to start using Google Ads scripts today!
  • Some things you can do with scripts
  • How to get started
  • Additional resources to help you get started

Happy scripting!


Why you need to start using Google Ads scripts today!

Digital marketing is complicated. There are dozens of interrelated on- and off-site metrics. There are hidden factors like quality score and competitor activity. There are unquantifiable, fuzzy influences like user intent and ad quality. And everything varies by time, device, demographic, and location.

On top of that, anything can be altered over time: not only do features come and go, but trends turn and competitors change. Even if you could set up your campaigns perfectly, you can’t leave them alone and expect to keep raking in the highest possible profits.

PPC technology is almost synonymous with third-party bid management tools. The problem with these tools is that they weren’t designed just for you; you can tweak settings, but you don’t have full control. Every business has its own needs and goals, so it’s unlikely these broad brush tools can always do precisely what you require. Rather than struggle to manipulate a third-party tool, why not just build something that works for you?

That’s where Google Ads scripts come in. Historically, the Google Ads API was an impossible starting point for people who wanted to automate little snippets of their PPC. You sometimes needed to wait three months for approval to use the API and had to spec out a whole program before you even knew if it would work. Then Google Ads scripts (previously AdWords scripts) came along and let you programmatically control Google Ads with the relatively easy JavaScript.


So, what can you do with scripts?

Control over your bids at scale

It may seem obvious that everyone is trying to optimize their campaigns as much as possible, but it matters whether you’re trying to maximise revenue, profit, the number of conversions, or the ROI.

For example, you might not want to be as aggressive as possible; you might want to buy the right number of leads according to the number of operators in your call center.

And your strategy depends on whether you have a fixed budget to use, or if you can spend as much as you want while the results are good.

Coding gives you the control to do precisely what you want, as many times as you want, as often as you want, informed by all the insider business knowledge that you possess. 

Scripts can bring in extra data

PPC depends on many factors, not all of which are standard Google Ads metrics.

You can use scripts to pull Salesforce or Zoho data into Google Ads. Code can make your ads and bids change according to the weather or the sports results.

It can pause ad groups for out-of-stock products, or even bid in real time based on hotel pricing and availability.  

Scripts take care of repetition

Reporting can be a hassle — it involves a lot of data manipulation — and it takes time away from optimizing your Google Ads accounts or planning your next move. 

You can automatically run reports in Google Ads or Analytics, but if you code your own reports you can customize any external or calculated fields you want and use that data to make custom dashboards.

You can also reduce repetition by using code where you want to make identical changes to a large number of similar campaigns — like if you have copies of campaigns with different location settings.

Scripts overcome platform limitations

If you use Google Ad’s native ad scheduling for your manual bidding campaigns, you can only schedule six bid changes a day. With code you can change bids every hour.

If you set up your campaigns normally, an exact match keyword will pick up any ‘closely matching’ search terms. With code, you can exclude everything but the search term you want.

There are limits to what you can overcome, but those limits are much wider than the limits of just using the Google Ads interface and/or a third-party tool.

Scripting can handle statistics

With a Google Ads script you can build your own experiments, testing anything, with control and test campaigns that switch on and off with alternate ad schedules.

Then you can code a test to see if those results are statistically significant.

Coding does the worrying for you

A program can watch your accounts all day, every day, so you don’t have to. You can set up emails so you’re warned when URLs break, performance plummets, ads are disapproved, or budgets are in danger of being exhausted too soon.


How do I get started with Google Ads scripts?

You can find the scripts page in the Bulk Operations column hiding under Tools & Settings in the top bar. Click on the + button (hover over text New Script) to begin. You will be taken to a page containing a box, a space for writing and executing your code.  These scripts will act upon the account in which they are located. You can write scripts which will act on multiple accounts, which you can find by opening the scripts page when viewing your MCC.


Clicking on DOCUMENTATION then Google Developers takes you to the reference pages for Google Ads scripting. Becoming proficient at scripting means understanding and becoming adept at using the reference documentation. This is covered in greater detail in a later section.  In addition to this, there are numerous examples of common tasks which you can adapt to your specific needs under Examples.


Getting to grips with Javascript

All Google Ads scripts are written in JavaScript (and also in AdWords Query Language, AWQL, which is similar to SQL).

If you’re new to JS or have never programmed before, make sure you understand the basics. There are many great online resources to learn from, including Codecademy.

As a refresher:

  • Variable: A variable contains information which can be accessed at a later point in time.
  • String: A string is information in the form of text wrapped in quotation marks. It is one of the types of data that can be stored in a variable; another type is numbers.
  • Function: A function contains code between two curly brackets which can be executed over and over again by writing out the function’s name – known as calling the function.
  • Argument: An argument is information in the form of a variable which is passed into a function. A function can take any number of arguments, including none at all.
  • Object: An object is a collection of variables and functions contained between two curly brackets. The object pointed to in the snippet above, MailApp, is one of the many objects that comes ready-made in Google Ads.
  • Method: When a function is contained within an object, it is known as a method. From the snippet above: the sendMail method is one of the functions belonging to the MailApp object.


Documentation

You will inevitably come to rely quite heavily on the documentation provided so here is a simple worked example to show how simple it is to use.

The following snippet shows how to retrieve a campaign from Google Ads:

1 function main() {
2     var campaignSelector = AdsApp.campaigns().withLimit(1);
3     var campaignIterator = campaignSelector.get();
4     while (campaignIterator.hasNext()) {
5         var campaign = campaignIterator.next();
6         var startDate = campaign.getStartDate();
7     }
8 }

The campaignSelector

  • We define a campaignSelector on line 2 using AdsApp.campaigns(). There are many options available for the campaignSelector, known as methods.
  • To make sure we’re looking at just one campaign, we use the withLimit() method which specifies the number of campaigns to select in the brackets (known as the argument).
  • If you don’t include withLimit, the selector will try to pull all the campaigns stopping at a maximum of 50,000.
  • You can see a list of possible methods here. Clicking on the name of a method in the documentation will scroll you down to that section, Wikipedia-style.
  • One of the most commonly used options is the withCondition() method where you can refine your search by choosing campaigns with certain names or those which have spent more than a threshold amount, for example.

Pro tip:

If you have multiple withCondition methods, the selected campaigns will satisfy all the conditions (think of it as a filter with conditions joined by an AND operator, e.g. cost >10 AND cost < 30).

For example, how would you be able to choose two campaigns that have completely unrelated names? Take a look at the first code snippet below. We included two withCondition lines in our selector.

As a result all the campaigns pulled by the selector will have to satisfy both conditions — not very useful when trying to return data on unrelated campaign groups.

You’ll notice that using multiple conditions can be quite restrictive because you can’t specify campaigns which satisfy one of two conditions. 

As in the second code snippet, use an array containing a list of all the campaign names you want your selector to pull. This technique overcomes the problem in the first snippet as campaigns with either name are now retrieved by the selector.


Code snippet 1:

1 function main() {
2     var campaignSelector = AdsApp.campaigns()
3         .withCondition("Name CONTAINS 'Campaign_1'")
4         .withCondition("Name CONTAINS 'Campaign_2'");
5     var campaignIterator = campaignSelector.get();
6     while (campaignIterator.hasNext()) {
7         var campaign = campaignIterator.next();
8     }
9 }


Code snippet 2:

1 function main() {
2     var campaignSelector = AdsApp.campaigns()
3         .withCondition("Name IN ['Campaign_1', 'Campaign_2']");
4     var campaignIterator = campaignSelector.get();
5     while (campaignIterator.hasNext()) {
6         var campaign = campaignIterator.next();
7     }
8 }


Example 1: Weekly spend email

This worked example will calculate the cost of your campaigns over the last week, and automate an email with the details.

Here’s a basic road map of the script:

  • We pull a list of campaigns from Google Ads.
  • We go through the list of campaigns one by one and get cost data on each.
  • The results are emailed to a few lucky recipients.

The code is below. Don’t worry if any of it is unfamiliar, we’ll comb through it line-by-line.

 
 1 function main() {
 2     var emailContent = "";
 3     var total = 0;
 4 
 5     var campaignSelector = AdsApp.campaigns()
 6         .withCondition("Cost > 10")
 7         .forDateRange("LAST_WEEK");
 8 
 9     var campaignIterator = campaignSelector.get();
10     while (campaignIterator.hasNext()) {
11         var campaign = campaignIterator.next();
12         var campaignName = campaign.getName();
13         var stats = campaign.getStatsFor("LAST_WEEK");
14         var cost = stats.getCost();
15         emailContent = emailContent + "The campaign " + campaignName + 
16             " spend £" + cost + "\n";
17         total = total + cost;
18     }
19     
20     var recipient = "you_are_so_good@this.com";
21     var subject = "Subject of the message";
22     var body = "The cost over the last 7 days: \n\n" + emailContent + 
23         ".\n\n" + "Total cost: £" + total;
24 
25     MailApp.sendEmail(recipient, subject, body);
26 }


Line 1. As with all Google Ads scripts this one contains a function called main. The code inside the curly brackets of the main function is executed when your script is run.
Line 2. We’re declaring these variables on lines 2 and 3 so we can use them later. The variable emailContent will contain the data to be emailed: the campaigns and how much they cost. The variable total will house the total cost.
Line 5. The first step is to create a selector. Selectors and iterators (you’ll meet iterators in a moment) are the bread and butter of Google Ads scripting. In basic terms, a selector is a way to state which Google Ads entities — in our case campaigns — you’d like to fetch and interact with. You can use a selector to filter down and order the entities you pull from Google.
Line 7. The methods on lines 6 and 7 provide the conditions for which campaigns to pull from Google Ads. We’ve chosen to go for campaigns which have cost more than £10 (line 6) in the last week (line 7). If you didn’t use any methods after campaigns(), you would return all the campaigns in the account.
Line 9. Now it’s time to get an iterator. The iterator allows you go through our list of campaigns one by one, pulling data or making changes as you go along (for example, you might want to change budgets). This process is known as iterating through the campaigns.
Line 10. Let’s iterate through. Use a while loop together with the hasNext() method to do this. You can think of the iterator and while loop as looping through an array of campaigns, stopping when it gets to the final one.
Line 11. The method next() picks out the next campaign in the iterator. You can now interact with the current campaign by pulling data or making changes.
Line 12. We want to match a campaign name to its cost. To retrieve the campaign name, use the getName() method.
Line 13. To retrieve performance statistics for each campaign we need to specify a date range. We use the getStatsFor() method on our campaign with the argument “LAST_WEEK” to let Google Ads know that we want last week’s data.
Line 14. Using the stats object, we can retrieve any of last week’s performance data for our campaigns. We’ve chosen the getCost() method, which returns the cost. Be sure to check out the link for the stats documentation page to see all the other types of data you can pull from Google Ads.
Line 15. Once we have the data we need (the cost and name of our campaign) we can format the data in a string ready to be emailed. The \n character starts a new line so that each campaign sits neatly on its own row.
Line 17. This line gives us the total cost of all the campaigns.
Line 20. Now format and send the email containing the cost of your campaigns!


Example 2: Scanning landing pages

Landing pages with broken URLs can wreak havoc in your Google Ads account.  Whether the links have moved or were inputted incorrectly from the start, the outcome is the same: you’re paying for dead-end clicks.

As before, here is a basic road map of the script:

  • Grab all the keywords from your account and gets their associated final URLs
  • Check the response code of these URLs
  • Any that do not receive a whitelisted response (200, 301, 302) will be emailed to relevant parties.

Below is the code, followed by a line-by-line explanation of what it does:

1 function main() {
 2     var emailRecipients = "userA@example.com, userB@example.com";
 3 
 4     var urls = [];
 5     var badUrls = [];
 6 
 7     var keywordIterator = AdsApp.keywords()
 8         .withCondition("Status = ENABLED")
 9         .withCondition("AdGroupStatus = ENABLED")
10         .withCondition("CampaignStatus = ENABLED")
11         .get();
12 
13     while (keywordIterator.hasNext()) {
14         var keyword = keywordIterator.next();
15         var finalUrl = keyword.urls().getFinalUrl();
16         if (finalUrl !== null && finalUrl !== "") {
17             var url = finalUrl.split('?')[0];
18             if (urls.indexOf(url) === -1) {
19                 urls.push(url);
20             }
21         }
22     }
23 
24     var options = {'muteHttpExceptions': false};
25     for (var x = 0; x < urls.length ; x++) {
26         try {
27             UrlFetchApp.fetch(urls[x], options);
28         } catch (err) {
29             badUrls.push(urls[x]);    
30         }
31     }
32 
33     if (badUrls.length !== 0) {
34         var accountName = AdsApp.currentAccount().getName();
35         var subject = accountName + " = Broken Final URLs";
36         var body = "The following are broken URLs in the account " + 
37             accountName + ". Please find attached a CSV file containing " +
38             "the URLS. \n\n" + badUrls.join("\n");
39         var options = {attachments: [Utilities.newBlob(
40             badUrls.join("\n"), 
41             "text/csv", 
42             accountName + " - Broken Final URLs.csv"
43         )]};
44         MailApp.sendEmail(email_recipients, subject, body, options);
45     }
46 }


Line 1. We start as usual with function main().
Line 2. This is the string containing the recipients of the broken URLs email. To add more addresses, just separate them out using commas inside the quote marks. To have just one email, wrap one email address in quote marks, e.g. “userA@example.com”.
Line 4. Here we’re creating two arrays to house URLs. The array urls will contain a list of all the unique URLs in the Google Ads account and badUrls will have a list of all the broken URLs. These are the URLs which will be emailed out at the end of the script.
Line 7. Here we construct a keyword iterator. The selector picks active keywords from enabled ad groups within enabled campaigns filtered using withCondition(). Since URLs can be set at the ad level as well as the keyword level, to construct an iterator which will get ads and not keywords, change AdsApp.keywords() to AdsApp.ads().
Line 13. The while loop combined with the iterator’s hasNext() method is the standard way to loop through Google Ads entities.
Line 14. Assign the next keyword object to the variable keyword.
Line 15. Use the inbuilt methods to get the final URL associated with the keyword.
Line 16. The if condition is just a check to make sure that the URL actually exists before continuing.
Line 17. Many people use tracking parameters in their URLs. The tracking parameters can be used for various tasks such as signalling the source of the traffic to your site. The parameters are placed after a URL and separated using a question mark. Tracking parameters are unnecessary when checking if a URL is functioning correctly and can even cause errors, so it’s best practice to remove them here. The split() method of a string is used to split the string up at the specified parameter and returns the different portions as an array.  Choosing the question mark as we do on line 17 splits the string into an array with two elements. Element zero contains the URL so we select it by writing [0].
Line 18. This if condition is here to make sure we have a list of unique URLs in the account. For larger accounts it can take a lot of time to check over all the URLs. By making sure you are only checking each URL once your scripts will run much more quickly.
Here’s what’s happening in plain English: The if condition asks if the current URL,  url, is contained within the array urls. If the URL is absent (indexOf returns -1) then the if condition is satisfied and the URL is pushed to the array on the next line. If, however, the URL was already contained in the array, then the code within the if condition will not be executed.
Line 24. These settings are for the method that gets called on line 27. This option says that if a URL is invalid, then throw out an error.
Line 25. We start a for loop to go through all the unique URLs that we put into the urls array. We’ll check the urls one by one.
Line 26. Here we’re introducing something new: the try-catch. If the code executed in the try block has an error, rather than bringing the script to a halt, the script jumps to the catch and executes the code contained there instead. This part of the script is useful for containing errors and not letting them stop your scripts mid way.
Line 27. UrlFetchApp is a utility that allows us to fetch a web page, returning an HTTP response object if successful, or throwing out an error if the URL is invalid.
Line 28. This catches urls that fail to be fetched, and puts them into the badUrls array.
Line 33. After an initial check to make sure badUrls isn’t empty (to make sure that broken URLs have actually been found), an email is sent containing the details both in the body of the message and in an attachment.


Example 3: Tracking account-level quality score

Google does not provide an account-level quality score to Google Ads users – QS is only available at the keyword level.  As it’s tedious and time-consuming to go through the quality score of each keyword, it’s scripts to the rescue! Here is an example inspired by this piece (an oldie but a goodie) by Fred Vallaeys on Search Engine Land.

Here is our basic road map:

  • Get the quality score and number of impressions for all keywords in our account.
  • Aggregate each keyword’s contribution to the account level quality score.
  • Output the account level quality score to a Google Sheet to see how it changes over time.

Here is the code followed by a line-by-line explanation:

1 function main() {
 2     var totalImpressions = 0;
 3     var totalWeightedQualityScore = 0;
 4 
 5     var keywordIterator = AdsApp.keywords()
 6         .withCondition("Status = ENABLED")
 7         .withCondition("CampaignName CONTAINS_IGNORE_CASE " + 
 8 	   	   "'INSERT CAMPAIGN NAME HERE'"
 9         )
10         .withCondition("CampaignStatus = ENABLED")
11         .withCondition("AdGroupStatus = ENABLED")
12         .orderBy("Impressions DESC")
13         .forDateRange("LAST_30_DAYS")
14         .withLimit(10000)
15         .get();
16 
17     while (keywordIterator.hasNext()) {
18         var keyword = keywordIterator.next();
19         var qualityScore = keyword.getQualityScore();
20         var keywordStats = keyword.getStatsFor("LAST_30_DAYS");
21         var impressions = keywordStats.getImpressions();
22         var qualityScoreContribution = qualityScore * impressions;
23 
24         totalWeightedQualityScore += qualityScoreContribution;
25         totalImpressions += impressions;
26     }
27 
28     var accountQualityScore = totalImpressions / totalWeightedQualityScore;
29 
30     Logger.log("QS: " + accountQualityScore);
31 
32     var date = new Date();
33     var spreadsheetUrl = "INSERT SPREADSHEET URL HERE";
34     var qualityScoreSheet = SpreadsheetApp
35         .openByUrl(spreadsheetUrl)
36         .getActiveSheet();
37     qualityScoreSheet.appendRow([date, accountQualityScore]);
38 }


Line 1. As before, our function is called main().
Line 2. We start off by initialising totalImpressions and totalQualityScore as zero. Each keyword we analyse will add its own metrics to these totals.
Line 5. We begin our keywordIterator with all active keywords.
Line 7. We filter to include only campaigns containing a specific substring (case insensitive).
Line 10. We only look at enabled campaigns and ad groups.
Line 12. We order by impressions and limit our query to 10,000 due to Google Ad’s built-in time limit. The script cannot run for more than 30 minutes and we want to ensure that we get a result in that time.  Should we have more than 10,000 keywords in our account, we know we are at least looking at the 10,000 with the most impressions and therefore with the most effect on account-level quality score.
Line 17. Loop through our keywords and set the variable keyword to the keyword we are currently analysing.
Line 18. Get the quality score and number of impressions for the keyword and assigns them to variables qualityScore and impressions.
Line 22. Calculate the quality score contribution of the keyword by multiplying quality score by number of impressions.
Line 24. Add this quality score contribution and the total number of impressions analysed to the running totals which we initialised on lines 2 and 3.
Line 28. Having gone through all the keywords, we can now calculate the total account quality score by dividing the totalQualityScoreAnalysed by the totalImpressionsAnalysed.
Line 32. We want to record the date that this quality score was recorded, luckily Javascript provides an easy way to get the current date.
Line 33. Insert the URL of the Google Sheet where you would like to record your quality score
Line 34. Like AdsApp and MailApp, SpreadsheetApp is the scripts way of communicating with Google sheets. Here the methods applied open the spreadsheet at the URL provided in line 33, and point at the active sheet within that spreadsheet.
Line 37. We add a new row to the spreadsheet consisting of two columns, today’s date, and the total account quality score.

You can set this script to run every day by locating the script under Tools and Settings → Scripts, then clicking the edit icon under the Frequency column. Each time it runs a new row will be appended to your spreadsheet.


Conclusion

Hopefully these brief examples have given a flavor of the power and control of harnessing Google Ads scripts.  Using only basic Javascript concepts, not only can you iterate through all your campaigns or keywords (or any other entity) to aggregate data or to apply changes, but you can connect these easily to emails or spreadsheets to create automated updates to your specifications. To learn more or to see further examples of scripts which you can use, check out the further resources below. 

Of course there is also the Google Ads API, but getting started with scripts is much quicker and a lot less daunting, with only a few simple steps before you’re ready to go.

Further resources

Make sure to follow our honourable leader, Daniel Gilbert, on Linkedin, and keep an eye on his Search Engine Land page where we publish our new open-source scripts alongside set-up guides!