When it comes to managing paid search campaigns, it never hurts to have an extra set of eyes. One common issue that I’ve encountered when managing AdWords accounts is pacing — how does one ensure that a campaign hasn’t exceeded its daily or monthly budget?
Getting this question wrong can, at best, lead to client disappointment and at worst, lead to practictioners (agencies and/or freelancers) having to issue credits back to clients. This is never a good time!
Thankfully, Google AdWords Scripts combined with the Slack API can serve as an extra layer of monitoring for accounts. In this tutorial, I’ll show you how to leverage these tools to create your own campaign budget monitor.
Essentially, the code shown below will review your active campaigns for high spend and send a Slack alert to the channel/user of your choice
Let’s get started!
Setting up the Slack API
Before we dive into the AdWords Script, lets make sure that you have the proper Slack credentials. Head over to the Slack API page, located here.
Make sure that you are logged into the Slack account that you plan on sending alerts to.
Next, click the ‘Create New App’ button (screenshot below), and enter your new App Name and appropriate development team — in my case, it is 3Q Digital. Make sure that you click ‘Create App’ and scroll down the page to find out your new App’s ClientID and Client Secret values.
Note: If you’re using a corporate account (e.g. 3Q Digital), you’ll need to reach out to your Slack Channel admins and ask them to approve your app.
You now have the keys to the castle. Before we move on, we’ll need to set up our incoming webhooks.
Enabling Slack Webhooks
In order to leverage Slack, we will need a way to send messages via our Google AdWords Script that are of interest to the end user. We’ll use the Slack API’s Incoming Webhooks feature to accomplish this task.
I’ll go into detail as to how this works later in the tutorial but for now, navigate to your new app’s configuration page and select Incoming Webhooks (screenshot below).
According to Slack, webhooks are a simple way to post messages from external sources (e.g. AdWords) into Slack.
In order to use Webhooks, you’ll need to decide where you want to send Slack messages. This could be a common team channel, an channel created specficially for alerts, or an individual user.
Note: You’ll need to create a new Slack Webhook each time you want to send messages to a different user or channel.
Navigate to the bottom of the incoming Webhooks page and click the Add New Webhook To Team button (screenshot below). From here, select the user/channel that will receive alerts and click Authorize.
Upon completion, you should see a new row that contains your new Slack Webhook URL address:
Copy and paste this URL into a text editor — we’ll need it later.
Make sure to take note of your credentials and head over to the AdWords UI tab.
Creating the Script Outline (to MCC or Not to MCC)
Before we dive in to the script, lets chat briefly about where to create the script. If you’re working in an agency setting, I highly encourage you to consider running your custom AdWords Script at the MCC (My Client Center) level.
Running your scripts at a MCC level allows you to a) apply your code to multiple clients and b) retain control of your code in the case that you and a client part ways.
In this tutorial, I’ll show you both the MCC approach and the non-MCC approach. Make sure to create your new script — in either the MCC or individual account — and let’s get started!
UnderscoreJS – provides a numer of useful functional programming helpers
In order to make life easier, I’ve ported over both libraries so that they work within Google AdWords. You can find these ports on my GitHub. It’s good practice to copy and paste these libraries into the bottom of new scripts so that you can use them.
All code in the rest of this tutorial assumes that you’ve included Underscore.
Creating the MCC Script Outline
Let’s create the basic skeleton for our MCC script. Make sure that you have the relevant Google AdWords Customer IDs (CIDS) before using the code below.
Note: Remove all dashes from your CIDs when adding them to your script.
Note: If you are not using a MCC, simply running the code associated with the monitorCampaigns(account) function should suffice.
In the code above, we use a MCCApp account selector to select the AdWords accounts that we’d like to monitor. We iterate over each account, select it — so that we can manipulate it if necessary — and then pass the account to a function called monitorCampaigns(account).
monitorCampaigns(account) will pull all active campaigns, check their spend levels, and send relevant Slack messages as applicable.
Defining Relevant URLs & Monitoring Thresholds
At this point if you were to run the script, you’d simply get a console message containing your selected AdWords accounts.
We can now start defining the relevant urls and monitoring thresholds that will be used on excution. Add the following code to the top of the script:
This code should be straightforward. We define the URL address that will process our Slack messages while also defining what budget spend threshold will serve as the point in which we’ll send messages.
Note: This script assumes that the budgets set in place for each campaign are indicative of desired spend levels. Feel free to tweak as your needs call for.
Creating our Slack Messaging Function
Now that we have a Slack Webhook to use, lets test it before creating the AdWords functionality. Add the following code block below the constants that we defined, but make sure that it is above the monitorCampaigns() function.
Note: Being able to to set the Slack icon image is still an open question. If you know how to do this, please ping me!
Let’s test this code! Amend monitorCampaigns(account) to the following:
You should see the equivalent of the screenshot below in your respective Slack channel. If so, congratulations! You’ve accomplished the most difficult aspect of the script.
Note: Before moving on, Comment the sendSlackMessage() line from monitorCampaigns(account).
Checking Active Campaign Budgets
Now that we know Slack works, let’s write a function that iterates over active campaigns and checks current spend levels against our COST_THRESHOLD.
If all goes to plan, this auditCampaigns(costThreshold) function will return an array (i.e. list) of campaigns that need our attention. Let’s write the function as follows:
This code is fairly straightforward and does the following:
- Declares empty variables for cost threshold and flagged campaigns.
- Iterates through all enabled AdWords campaigns and stores its respective campaign budget, budget threshold amount, and current spend.
- Performs a logical test on whether the current spend exceeds the calculated budget threshold. If this threshold has been exceeded, campaign details are appended to the campaigns If not then no action is taken.
- Returns a list of flagged campaigns — sorted by cost (thanks underscore!) —, which will be used for further processing — in our case, sending a Slack alert.
Alerting the User
At this point, we are almost home free. We’ve defined our budget thresholds, ensured that Slack messages can be sent, and have now written the code that will identify campaigns that have exceeded their budget threshold.
All we need to do at this point is iterate through this list of campaigns and alert the user. Amend monitorCampaigns(account) to the code listed below.
In the code above, we called on auditCampaigns() to identify all campaigns worth mentioning. From there, we check if there are any campaigns worth alerting.
Note: we could have passed an optional costThreshold to auditCampaigns if necessary.
If there are none (i.e. campaigns.length is less than 0), then the script will move on to the next AdWords Account in question. Otherwise, the script sends a header message via Slack and then uses underscore’s _.each() function to iterate through each campaign and alert the end user.
You did it! You now have an MCC-level Google AdWords script that will keep tabs on current campaign spend levels. Be sure to set your new script’s schedule — daily is my suggested interval — and happy optimizing!
You can find the completed script here.