AdWords Quality Score Tracker Version 2.0 – Now with Labels

Google just made some very helpful additions to AdWords Scripts. One of them is that you can now use labels within scripts. To demonstrate how powerful this feature is, I’ve rewritten the Quality Score Tracker.

The first version required a spreadsheet with a list of keywords to track. It also required you to get the spreadsheet first. This new version relies on labels to mark keywords for tracking and the setup is much easier.

What the Script does

Just like the first version, this script tracks keyword quality scores over time. When run, the script goes through all keywords you’ve marked with a certain label and checks their quality scores. Changes are logged and can be emailed to you. The script also writes all values into a spreadsheet, so that over time you’ll get a complete history.

The recommended use is to run the script regularly for your top keywords to see changes over time. You can use it for a quick diagnosis, but you can also use the history in the spreadsheet for an in depth analysis later.

The Setup

As I mentioned, this one is much easier than before. Again, three steps are needed:

  1. Get the script
  2. Run the script once to create the label
  3. Mark all keywords you want tracked with the label

The Script

Go to your AdWords account and click Bulk operations (formerly Automation) and then Scripts on the left hand side of the AdWords interface. Next, click Create script. Copy and paste the following code:

var email_address = "YOUR_EMAIL_HERE"; // Change this to be notified of changes
var label_name = "Track QS";

function main() {
  var labelIterator = AdWordsApp.labels().withCondition("Name = '" + label_name + "'").get();
  // If there is no label, this is the first time this script is running
    // Create the spreadsheet
    var spreadsheet = SpreadsheetApp.create("AdWords Quality Score Tracker");
    Logger.log("Spreadsheet for QS history created: " + spreadsheet.getUrl());
    var sheet = spreadsheet.getActiveSheet();
    sheet.setName("QS history");
    // Put in the table headings
    sheet.getRange(1, 1, 1, 6).setValues([["Date", "Campaign", "AdGroup", "Keyword", "Quality Score", "Change"]]);
    sheet.getRange(1, 1, 1, 6).setFontWeight("bold");
    // Create the label and save the spreadsheet's URL in the description
    AdWordsApp.createLabel(label_name, "Marks Keywords for QS tracking. Results are here: " + spreadsheet.getUrl() + " (keep URL in this description)", "#339999");
    Logger.log("Label '" + label_name + "' has been created. Apply this label to all keywords want to track. Then run the script again.");
    for(i = 1; i <= 10; i++){
      AdWordsApp.createLabel("QS: " + i, "Used for QS comparison.", "#ffffff");
    Logger.log("Ten additional labels ('QS: 1' to 'QS: 10') have been created. Those are needed by the script to compare old and new Quality Scores later. You can just ignore those.");
  // There is a label so get it and get the spreadsheet's URL from its description
  label =;
  var matches = new RegExp(' (http(s?)://[^ ]+) ').exec(label.getDescription());
  if (!matches || !matches[1]) {
    throw "Couldn't get spreadsheet URL from label description: " + label.getDescription();
  var spreadsheetUrl = matches[1];
  var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl);
  var alert_text = new Array();
  var history = new Array();
  var currentTime = new Date();
  var today = (currentTime.getMonth() + 1) + "/" + currentTime.getDate() + "/" + currentTime.getFullYear();
  var keywordIterator = label.keywords().get();
  var line_counter = 0;
  while (keywordIterator.hasNext()) {
    var keyword =;
    var current_quality_score = keyword.getQualityScore();
    keywordLabelsIterator = keyword.labels().withCondition("Name STARTS_WITH 'QS: '").get();
      keyword_label =;
      var matches = new RegExp('QS: ([0-9]+)$').exec(keyword_label.getName());
      old_quality_score = matches[1];
      old_quality_score = 0;
    // For the history also note the change or whether this keyword is new
    if(old_quality_score > 0) var change = current_quality_score - old_quality_score;
    else var change = "NEW";
    var row = [today, keyword.getCampaign().getName(), keyword.getAdGroup().getName(), keyword.getText(), current_quality_score, change];
    // If there is a previously tracked quality score and it's different from the current one...
    if(old_quality_score > 0 && current_quality_score != old_quality_score){
      // Make a note of this to log it and possibly send it via email later
      alert_text.push(current_quality_score + "\t" + old_quality_score + "\t" + change + "\t" + keyword.getText());
      // Remove the old label
    // Store the current QS for the next time by using a label
    keyword.applyLabel("QS: " + current_quality_score);
  if(line_counter == 0){
    Logger.log("Couldn't find any keywords marked for quality score tracking. To mark keywords for tracking, apply the label '" + label_name + "' to those keywords.");
  Logger.log("Tracked " + line_counter + " keyword quality scores. To select different keywords for tracking, apply the label '" + label_name + "' to those keywords.");
  // Store history
  var history_sheet = spreadsheet.getSheetByName('QS history');
  history_sheet.getRange(history_sheet.getLastRow()+1, 1, history.length, 6).setValues(history);  
  // If there are notes for alerts then prepare a message to log and possibly send via email
    var message = "The following quality score changes were discovered:\nNew\tOld\tChange\tKeyword\n";
    for(i = 0; i < alert_text.length; i++){
      message += alert_text[i] + "\n";
    // Also include a link to the spreadsheet
    message += "\n"
      + "The complete history is available at "
      + spreadsheet.getUrl();
    // If there is an email address send out a notification
    if(email_address && email_address != "YOUR_EMAIL_HERE"){
      MailApp.sendEmail(email_address, "Quality Score Tracker: Changes detected", message);

If you want to receive notifications, replace YOUR_EMAIL_HERE with your email address. If you don’t want any notifications, just ignore this.

Name the script “Quality Score Tracker v2″ and click Save.

The First Run

Click the button Run script now. AdWords will ask you to authorize the script before it can be executed. The first run takes about ten seconds.

The script will now create the spreadsheet where the history will be logged. The spreadsheet’s URL can be found in the logs, after the first run. The script will also create some labels. The label Track QS will be needed for the next step. The other ten labels (QS: 1 to QS: 10) are needed by the script and should be ignored.

Apply the label Track QS to select keywords for quality score trackingThe Keywords

Go back to your campaigns and hit F5 to reload the AdWords interface (otherwise the newly created labels won’t be available). Go to the keyword column and select the keywords you want tracked. Apply the label Track QS to those keywords.

You can always come back to this and remove the label or apply it to new keywords at any time.

Using the Script

To run the script, click the button Run script now. You can also schedule the script to run regularly.

Execution takes a while, especially if it’s the first time you track new keywords. You don’t have to wait around for the script to finish. If changes are found, the script sends an email notification and also logs the notification (to be found under View details in the script logs). The first time the script runs it naturally won’t be able to find any changed quality scores.

If at any point you want to change the set of tracked keywords, simply use the label Track QS to change it.

To analyze the quality score history of your keywords, use the spreadsheet. Its URL can be found in the logs after the script has been run, but it will also be emailed to you (if you provided your address). You can also find the URL in the label’s description.

There’s nothing you can break in the spreadsheet, but I’d recommend to copy the contents into a new sheet if you want to play with the data. To focus on changes over time, filter out the zeros in the Change column.

Limitations and Warnings

Scripts have gotten a lot faster and it wouldn’t be a problem to track hundreds, maybe thousands of keywords with it. You could also run the script hourly. If you do it, you might go crazy.

We’ve done a lot of testing and tracking with keyword quality scores and found that they change quite frequently. Most changes don’t mean anything and you won’t be able to see any difference in performance. Chances are that too much tracking will give you a lot to worry about.

So my advice is still to just track the ten or twenty most important keywords and do it once a week or once a month.

For Scripts Developers: A new Feature

If you’ve written scripts before you might have noticed that this one does something that previously wasn’t possible with AdWords Scripts: It stores data in the account.

This is especially helpful for the spreadsheet’s URL. Previously there was no way for a script to “remember” information like this between runs: If you wanted to use the same spreadsheet twice you had to put its URL into the script’s code. That’s why you had to get the spreadsheet and save its URL in the first version.

In this version the script just checks if there a label called Track QS. If not, it creates the spreadsheet and then the label, storing the spreadsheet’s URL in the label’s description. Afterwards, the script just gets the label and with it the spreadsheet.

This way of storing information opens up new possibilities for AdWords Scripts. You could use labels to store information directly (as done with the ten QS labels), or you could do it indirectly, by storing URL’s in label descriptions. Of course, usually there won’t be a reason not to write a URL directly into the script, but it’s a nice trick if you want to share a script and make the setup as easy as possible.

It would also be possible to use label descriptions to store some other pieces of data, like the last time a script was executed. However, with room for only 200 characters, the storage capabilities of label descriptions are very limited.

Minor Update 7 / 7 / 2014

Changed the way the spreadsheet is opened from byId to byUrl. If the script works fine, there’s no need to upgrade.

About the Author

Martin Roettgerding is the head of SEM at SEO/SEM agency Bloofusion Germany. On Twitter he goes by the name @bloomarty, and you can find him regularly on #ppcchat.

  • Auke Jongbloed

    Great work Martin,

    Love the label solution. It is for me a great starting point in having a script with a more weighted overall score for campaigns and adgroups. I have found a great post from Frederick Vallaeys on (

    I would like to alter the script in showing me a historical quality score on campaign and adgroups. Not a real developer so it will take me some efford :)

    Thanks for posting this script.


  • pusche

    great stuff, thanks ! gonna run some tests on limitations in the next days… :)

  • Rick

    Call me crazy.. but I can’t seem to find a URL to access the data after the initial run + subsequent runs. Help!

    • Martin Roettgerding

      Hi Rick,
      I tried several times, but I can’t reproduce the error. Someone on Twitter reported something similar yesterday.

      Could you paste the description of the label “Track QS”? The spreadsheet’s URL should be in there, but apparently something has gone wrong so that the script can’t read it. With the description I should be able to find out what went wrong and fix the script.

      Sorry for the trouble…

      • Rick

        Hi there,

        Thanks for following up.

        Actually – this seemed to have fixed itself. What I did was: a) sign in and out of the account. b) wait for a period of time (overnight).

        Checked the label’s description and viola – it’s there (whereas it wasn’t before). Woohoo!

  • Hervé – Easy Internet Marketing

    THX for the great work Martin! Very usefull stuff!

  • Russ Savage

    I started a blog that focuses on free scripting help. I try to publish a new script at least once a week. Let me know if you have any ideas.

  • searchengineman

    This is an incredibly useful script. Thank you for taking the time to share and post this script over here. I found your article via PPCHero. I’m looking forward to seeing the changes in one of our campaigns (Only 30 keywords). If fluctuations are that varied..

    Is there a repository or collection of useful Adwords Scripts out there?
    I’m sure there must be some some solutions to problems we’ve never even thought about!

    It’s time like these I wish I was a coder.

  • Aurelien

    Awesome script! Thanks a lot!

  • Marc Pearson

    Thanks Martin! This is my first time tracking keywords, wish me luck.

  • Justin

    Great script! Thank you so much, this is a real time saver.
    I was wondering, is there a way to add additional labels to this script to track multiple groups of keywords?

  • John Seal

    Martin, the script is amazing!!! Thanks for providing a great way to track Quality Score. I am no developer and I’d like to add the average position to the tracking script. Can you coach me on the best way to do that?

  • David

    Hey there Martin,

    thanks a lot for your script and the understandable instruction! It looks like an easy but efficient method to track your QS. Plus I am completly new into AdWords scripts and eager to learn more about them.

    All the best,


  • David from Hungary

    Hi Martin,

    I see that you are very good in this AdWords script thing.

    Maybe you can help me:
    I manage campaigns for an online travel agency and I would like to create a script which checks hourly an online spreadsheet to see if some offer changed (simply we give one cell for each destinations ad to check whether the cell content is different or not), if it is different, the script repleaces the text for the new offer.

    I think it is pretty simple compared to this quality score tracker script.

    Thank you

  • Peter


    This looks great however I am getting “Couldn’t get spreadsheet ID from label description: (line 30)”.

    I have probably missed a step but can’t quite see the wood for the trees! Any help would be most welcome.

    • Goran Giertz

      @Peter, where you able to sort out this problem. I am getting the same one?

      • Martin Roettgerding

        Looks like the spreadsheet hasn’t been stored in the label’s description. Maybe there was a problem with creating the spreadsheet…

        Try this: Delete the label “Track QS” and the ten QS labels, then run the script again. This should reset everything and hopefully all will work on the second run.

  • Tim

    I was able to get the script set up and running on a weekly schedule. It runs fine, and I can view results in the log details as well as the spreadsheet, but am not receiving emails despite entering my email address in both YOUR_EMAIL_HERE sections (I did double check that I’d entered it properly, as well as checking the spam folder). Any idea what may be causing the email to not go through? Not a huge deal as I can still view results in the browser, but was curious if others have had issues and had any insight to troubleshoot/solve. My knowledge of coding is very much on the basic end.

  • Martin Roettgerding

    Hi Tim,
    This should work…
    The email comes from the AdWords account’s email address. Maybe you have an automated rule in your email program that sorts out those mails?

    Oh, wait – both YOUR_EMAIL_HERE sections? The second YOUR_EMAIL_HERE in line 88 shouldn’t be changed. This part checks whether the email address is different from the string “YOUR_EMAIL_HERE”. Just change it back and you should be fine.

  • Roy Smid

    Hi Martin,

    Respect, this is great work! It has the keywordlevel detail I did not find in other scripts, but mostly the label and email function are very usefull!

    Keep up the good work.



  • Maroesja te Hennepe

    Hi Martin,

    Great Script! Thanks a lot. Is there a possibility to track the CTR next to the Quality score? As the CTR has a huge influence on the CTR it would be good to know if these changed together with the QS.

    Thanks in Advance!


    • Martin Roettgerding

      Hi Maroesja,

      You could add a column and track CTR, but the problem is that CTR refers to a time period whereas Quality Score refers to “now”.

      Another problem is that CTR alone doesn’t mean much. In connection to Quality Score you’d have to normalize by position, but all you’ll get from AdWords is average position. You’d also have to look at CTR on Google, but not on Search Partners or other networks. (From experience I know that analysts will gladly ignore the unsolvable first problem and simply forget to account for the second one.)

      However, since all other stats are available all the time, there’s no need to track them like QS. You can just pull historical CTR, average position and all the other stuff at any time.

      • Maroesja te Hennepe

        Hi Martin!

        Thanks for the quick responce!
        Indeed with the historical data it would work as well.

        Kind Regards,


  • http://Greatstuff Margo

    This one is phenomenal! I have waited for so long and tracking QS manually in excel! I love it.

  • Guest

    Is anyone having issues with this script now? I have been using it and variations of it for over a year now and just recently have been experiencing issues.

    When adding the script to a new account the initial run works, creating all 11 labels and the google spreadsheet. The issue is when I run the script again after tagging keywords. When I do this I get the following error:
    “Couldn’t get spreadsheet ID from label description: Marks Keywords for QS tracking. Results are here:{spreadsheet id removed for postin} (keep URL in this description) (line 35)”

    • Martin Röttgerding

      This was sometimes a problem in an old version of the script. I updated the script above in July to fix this. If you are having this problem, please get the code again and copy it over your existing script (you can leave lines 1 and 2).

      Let me know if there are still any problems.

  • alexpeerenboom

    Thank you for this script. It runs successfully the first to apply the labels. However, each time I run it after that I get the following error: “The label QS: null does not exist. (line 65)”

    What could this be?

    • Martin Röttgerding

      Hi Alex,
      That one is new… instead of “null” there should be the keyword’s current quality score. This would mean that the script couldn’t get a quality score from that keyword… or that the keyword simply doesn’t have one. Can you check if there’s anything special about the keyword in question? Can you get a quality score for this keyword manuelly (via status bubble or QS column)?

  • Jonny Walsh

    Love the idea of this script, however when i try to run i get the following error in the log Document 1ODMBC73xHOg4o_BDuT5jFYfmji1J4gtcTbo6oqFNt10 is missing (perhaps it was deleted?) (line 33)

    • Lee

      I’m getting this same problem – anybody found a way round this?

  • Marya Conzalyes

    Nice Script, I hoped it worked for me but it didn’t. I got error “Couldn’t get spreadsheet URL from label description”