Skip to content

Quality Score history logger

The Quality Score column in Google Ads shows the current score; daily values need the historical columns segmented by day. This appends a daily row per keyword with the score, expected CTR, ad relevance and landing page experience to a Google Sheet, so the history is one table you can chart next to your changes.

Google Ads script
/**
 * Goodlabs Google Ads Script: Quality Score Tracker
 * Schedule: Daily at 05:00
 */
var CONFIG = {
  SPREADSHEET_URL: "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit",
  MIN_IMPRESSIONS: 10
};

function main() {
  var report = AdsApp.report(
    "SELECT segments.date, ad_group_criterion.keyword.text, campaign.name, ad_group.name, " +
    "metrics.historical_quality_score, metrics.historical_search_predicted_ctr, " +
    "metrics.historical_creative_quality_score, metrics.historical_landing_page_quality_score " +
    "FROM keyword_view " +
    "WHERE ad_group_criterion.status = 'ENABLED' " +
    "AND metrics.impressions > " + CONFIG.MIN_IMPRESSIONS + " " +
    "AND segments.date DURING YESTERDAY"
  );

  var ss = SpreadsheetApp.openByUrl(CONFIG.SPREADSHEET_URL);
  var sheet = ss.getSheetByName("QS_Log") || ss.insertSheet("QS_Log");
  if (sheet.getLastRow() === 0) {
    sheet.appendRow(["Date", "Keyword", "Campaign", "Ad Group", "Quality Score", "Expected CTR", "Ad Relevance", "Landing Page Exp"]);
  }

  var rows = report.rows();
  var batch = [];

  while (rows.hasNext()) {
    var row = rows.next();
    batch.push([
      row["segments.date"],
      row["ad_group_criterion.keyword.text"],
      row["campaign.name"],
      row["ad_group.name"],
      row["metrics.historical_quality_score"],
      row["metrics.historical_search_predicted_ctr"],
      row["metrics.historical_creative_quality_score"],
      row["metrics.historical_landing_page_quality_score"]
    ]);
  }

  if (batch.length > 0) {
    sheet.getRange(sheet.getLastRow() + 1, 1, batch.length, 8).setValues(batch);
  }
}

How it works

  1. Queries keyword_view for yesterday's historical_quality_score, historical_search_predicted_ctr (expected CTR), historical_creative_quality_score (ad relevance) and historical_landing_page_quality_score (landing page experience), for enabled keywords with more than MIN_IMPRESSIONS impressions that day.
  2. Appends one row per keyword to the Google Sheet, dated with the day the scores belong to in the account's time zone, so a landing page or ad change shows up as a step in the history.

Installation

  1. In Google Ads, open Tools > Bulk actions > Scripts and create a script.
  2. Paste the code and set your Google Sheet URL.
  3. Schedule it daily at 05:00.

Questions

How much history fits?

A Google Sheet holds 10 million cells. At eight columns that is roughly 1.2 million keyword-days: years for a small account, months for a large one.

Need one adapted to your account?

We write Google Ads scripts, set up server-side GA4 and build reports that answer a specific question.