Generate historical metrics

  • Historical metrics provide data on past keyword performance on Google Search, including search volume, competition level, and bid ranges.

  • These metrics can be used to narrow down a large list of keywords based on their performance.

  • To obtain historical metrics, you can use the GenerateKeywordHistoricalMetrics method with specified parameters like keywords, geo targets, and language.

  • The functionality of generating historical metrics is similar to the Keyword Planner tool in the Google Ads UI.

Historical metrics provide metrics (KeywordPlanHistoricalMetrics) on how keywords have performed on Google Search, including the following fields:

  • Average monthly searches (avg_monthly_searches, averaged over the past 12 months or the specified year_month_range)
  • Approximate monthly search volume (monthly_search_volumes, available for up to the past 4 years)
  • Competition level (competition)
  • Competition index (competition_index, from 0 to 100)
  • 20th percentile of top-of-page bids (low_top_of_page_bid_micros)
  • 80th percentile of top-of-page bids (high_top_of_page_bid_micros)
  • Average cost-per-click (average_cpc_micros, returned for legacy support when HistoricalMetricsOptions.include_average_cpc is true)

If you are discovering keyword suggestions with GenerateKeywordIdeas, each returned GenerateKeywordIdeaResult already includes KeywordPlanHistoricalMetrics in its keyword_idea_metrics field. Call GenerateKeywordHistoricalMetrics when you already have an existing list of keywords and want to filter them by historical search volume, competition, and top-of-page bids before organizing them with ad group themes or estimating performance with forecast metrics.

Generate metrics

To generate historical metrics, call KeywordPlanIdeaService.GenerateKeywordHistoricalMetrics with up to 10,000 keywords per request and the targeting parameters you want to include (such as language, up to 10 geo_target_constants, and keyword_plan_network). The method returns a GenerateKeywordHistoricalMetricsResponse containing a list of GenerateKeywordHistoricalMetricsResult objects, each with a keyword_metrics field of type KeywordPlanHistoricalMetrics. Note that the API deduplicates close variants (for example, merging "car" and "cars" into a single result and listing combined queries in close_variants), so the number of returned results can be smaller than the number of requested keywords.

Java

private void runExample(GoogleAdsClient googleAdsClient, Long customerId) {
  GenerateKeywordHistoricalMetricsRequest request =
      GenerateKeywordHistoricalMetricsRequest.newBuilder()
          .setCustomerId(String.valueOf(customerId))
          .addAllKeywords(Arrays.asList("mars cruise", "cheap cruise", "jupiter cruise"))
          // See https://developers.google.com/google-ads/api/reference/data/geotargets for the
          // list of geo target IDs.
          // Geo target constant 2840 is for USA.
          .addGeoTargetConstants(ResourceNames.geoTargetConstant(2840))
          .setKeywordPlanNetwork(KeywordPlanNetwork.GOOGLE_SEARCH)
          // See
          // https://developers.google.com/google-ads/api/reference/data/codes-formats#languages
          // for the list of language constant IDs.
          // Language constant 1000 is for English.
          .setLanguage(ResourceNames.languageConstant(1000))
          .build();

  try (KeywordPlanIdeaServiceClient keywordPlanIdeaServiceClient =
      googleAdsClient.getLatestVersion().createKeywordPlanIdeaServiceClient()) {
    GenerateKeywordHistoricalMetricsResponse response =
        keywordPlanIdeaServiceClient.generateKeywordHistoricalMetrics(request);
    for (GenerateKeywordHistoricalMetricsResult result : response.getResultsList()) {
      KeywordPlanHistoricalMetrics metrics = result.getKeywordMetrics();
      System.out.printf("The search query: %s%n", result.getText());
      System.out.printf(
          "and the following variants: %s%n", Joiner.on(",").join(result.getCloseVariantsList()));
      System.out.println("generated the following historical metrics:");

      // Approximate number of monthly searches on this query averaged for the past 12
      // months.
      System.out.printf(
          "Approximate monthly searches: %s%n",
          metrics.hasAvgMonthlySearches() ? metrics.getAvgMonthlySearches() : null);

      // The competition level for this search query.
      System.out.printf("Competition level: %s%n", metrics.getCompetition());

      // The competition index for the query in the range [0,100]. This shows how
      // competitive ad placement is for a keyword. The level of competition from 0-100 is
      // determined by the number of ad slots filled divided by the total number of slots
      // available. If not enough data is available, null will be returned.
      System.out.printf(
          "Competition index: %s%n",
          metrics.hasCompetitionIndex() ? metrics.getCompetitionIndex() : null);

      // Top of page bid low range (20th percentile) in micros for the keyword.
      System.out.printf(
          "Top of page bid low range: %s%n",
          metrics.hasLowTopOfPageBidMicros() ? metrics.getLowTopOfPageBidMicros() : null);

      // Top of page bid high range (80th percentile) in micros for the keyword.
      System.out.printf(
          "Top of page bid high range: %s%n",
          metrics.hasHighTopOfPageBidMicros() ? metrics.getHighTopOfPageBidMicros() : null);

      // Approximate number of searches on this query for the past twelve months.
      metrics.getMonthlySearchVolumesList().stream()
          // Orders the monthly search volumes by descending year, then descending month.
          .sorted(
              (a, b) ->
                  ComparisonChain.start()
                      .compare(b.getYear(), a.getYear())
                      .compare(b.getMonth(), a.getMonth())
                      .result())
          // Prints each monthly search volume.
          .forEachOrdered(
              monthlySearchVolume ->
                  System.out.printf(
                      "Approximately %d searches in %s, %s%n",
                      monthlySearchVolume.getMonthlySearches(),
                      monthlySearchVolume.getMonth(),
                      monthlySearchVolume.getYear()));
    }
  }
}
      

C#

public void Run(GoogleAdsClient client, long customerId)
{
    KeywordPlanIdeaServiceClient keywordPlanIdeaService =
            client.GetService(Services.V26.KeywordPlanIdeaService);

    GenerateKeywordHistoricalMetricsRequest request =
        new GenerateKeywordHistoricalMetricsRequest()
    {
        CustomerId = customerId.ToString(),
        Keywords = { "mars cruise", "cheap cruise", "jupiter cruise" },
        // See https://developers.google.com/google-ads/api/reference/data/geotargets
        // for the list of geo target IDs.
        // Geo target constant 2840 is for USA.
        GeoTargetConstants = { ResourceNames.GeoTargetConstant(2840) },
        KeywordPlanNetwork = KeywordPlanNetwork.GoogleSearch,
        // See  https://developers.google.com/google-ads/api/reference/data/codes-formats#languages
        // for the list of language constant IDs.
        // Language constant 1000 is for English.
        Language = ResourceNames.LanguageConstant(1000)
    };

    try
    {
        GenerateKeywordHistoricalMetricsResponse response =
            keywordPlanIdeaService.GenerateKeywordHistoricalMetrics(request);

        foreach (GenerateKeywordHistoricalMetricsResult result in response.Results)
        {
            KeywordPlanHistoricalMetrics metrics = result.KeywordMetrics;

            Console.WriteLine($"The search query {result.Text}");
            Console.WriteLine("and the following variants: " +
                $"{String.Join(",", result.CloseVariants)}");
            Console.WriteLine("Generated the following historical metrics:");

            // Approximate number of monthly searches on this query averaged for the past 12
            // months.
            Console.WriteLine($"Approximate monthly searches: {metrics.AvgMonthlySearches}");

            // The competition level for this search query.
            Console.WriteLine($"Competition level: {metrics.Competition}");

            // The competition index for the query in the range [0,100]. This shows how
            // competitive ad placement is for a keyword. The level of competition from 0-100 is
            // determined by the number of ad slots filled divided by the total number of slots
            // available. If not enough data is available, null will be returned.
            Console.WriteLine($"Competition index: {metrics.CompetitionIndex}");

            // Top of page bid low range (20th percentile) in micros for the keyword.
            Console.WriteLine($"Top of page bid low range: {metrics.LowTopOfPageBidMicros}");

            // Top of page bid high range (80th percentile) in micros for the keyword.
            Console.WriteLine($"Top of page bid high range: {metrics.HighTopOfPageBidMicros}");

            // Approximate number of searches on this query for the past twelve months.
            foreach (MonthlySearchVolume month in metrics.MonthlySearchVolumes)
            {
                Console.WriteLine($"Approximately {month.MonthlySearches} searches in " +
                    $"{month.Month}, {month.Year}");
            }
        }

    }
    catch (GoogleAdsException e)
    {
        Console.WriteLine("Failure:");
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");
        throw;
    }
}
      

PHP

public static function runExample(
    GoogleAdsClient $googleAdsClient,
    int $customerId
): void {
    $keywordPlanIdeaServiceClient = $googleAdsClient->getKeywordPlanIdeaServiceClient();
    // Generates keyword historical metrics based on the specified parameters.
    $response = $keywordPlanIdeaServiceClient->generateKeywordHistoricalMetrics(
        new GenerateKeywordHistoricalMetricsRequest([
            'customer_id' => $customerId,
            'keywords' => ['mars cruise', 'cheap cruise', 'jupiter cruise'],
            // See https://developers.google.com/google-ads/api/reference/data/geotargets for
            // the list of geo target IDs.
            // Geo target constant 2840 is for USA.
            'geo_target_constants' => [ResourceNames::forGeoTargetConstant(2840)],
            'keyword_plan_network' => KeywordPlanNetwork::GOOGLE_SEARCH,
            // https://developers.google.com/google-ads/api/reference/data/codes-formats#languages
            // for the list of language constant IDs.
            // Language constant 1000 is for English.
            'language' => ResourceNames::forLanguageConstant(1000)
        ])
    );

    // Iterates over the results and print its detail.
    foreach ($response->getResults() as $result) {
        /** @var GenerateKeywordHistoricalMetricsResult $result */
        $metrics = $result->getKeywordMetrics();
        printf("The search query: '%s' ", $result->getText());
        printf(
            "and the following variants: '%s' ",
            implode(',', iterator_to_array($result->getCloseVariants()->getIterator()))
        );
        print "generated the following historical metrics:" . PHP_EOL;

        // Approximate number of monthly searches on this query averaged for the past 12 months.
        printf(
            "Approximate monthly searches: %s%s",
            $metrics->hasAvgMonthlySearches()
                ? sprintf("%d", $metrics->getAvgMonthlySearches())
                : "'none'",
            PHP_EOL
        );

        // The competition level for this search query.
        printf(
            "Competition level: '%s'%s",
            KeywordPlanCompetitionLevel::name($metrics->getCompetition()),
            PHP_EOL
        );

        // The competition index for the query in the range [0,100]. This shows how
        // competitive ad placement is for a keyword. The level of competition from 0-100 is
        // determined by the number of ad slots filled divided by the total number of slots
        // available. If not enough data is available, null will be returned.
        printf(
            "Competition index: %s%s",
            $metrics->hasCompetitionIndex()
                ? sprintf("%d", $metrics->getCompetitionIndex())
                : "'none'",
            PHP_EOL
        );

        // Top of page bid low range (20th percentile) in micros for the keyword.
        printf(
            "Top of page bid low range: %s%s",
            $metrics->hasLowTopOfPageBidMicros()
                ? sprintf("%d", $metrics->getLowTopOfPageBidMicros())
                : "'none'",
            PHP_EOL
        );

        // Top of page bid high range (80th percentile) in micros for the keyword.
        printf(
            "Top of page bid high range: %s%s",
            $metrics->hasHighTopOfPageBidMicros()
                ? sprintf("%d", $metrics->getHighTopOfPageBidMicros())
                : "'none'",
            PHP_EOL
        );

        // Approximate number of searches on this query for the past twelve months.
        $monthlySearchVolumes =
            iterator_to_array($metrics->getMonthlySearchVolumes()->getIterator());
        usort(
            $monthlySearchVolumes,
            // Orders the monthly search volumes by descending year, then descending month.
            function (MonthlySearchVolume $volume1, MonthlySearchVolume $volume2) {
                $yearsCompared = $volume2->getYear() <=> $volume1->getYear();
                if ($yearsCompared != 0) {
                    return $yearsCompared;
                } else {
                    return $volume2->getMonth() <=> $volume1->getMonth();
                }
            }
        );
        // Prints each monthly search volume.
        array_walk($monthlySearchVolumes, function (MonthlySearchVolume $monthlySearchVolume) {
            printf(
                "Approximately %d searches in %s, %s.%s",
                $monthlySearchVolume->getMonthlySearches(),
                MonthOfYear::name($monthlySearchVolume->getMonth()),
                $monthlySearchVolume->getYear(),
                PHP_EOL
            );
        });
        print PHP_EOL;
    }
}
      

Python

def main(client: GoogleAdsClient, customer_id: str):
    """The main method that creates all necessary entities for the example.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
    """
    generate_historical_metrics(client, customer_id)


def generate_historical_metrics(client: GoogleAdsClient, customer_id: str):
    """Generates historical metrics and prints the results.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
    """
    googleads_service: GoogleAdsServiceClient = client.get_service(
        "GoogleAdsService"
    )
    keyword_plan_idea_service: KeywordPlanIdeaServiceClient = (
        client.get_service("KeywordPlanIdeaService")
    )
    request: GenerateKeywordHistoricalMetricsRequest = client.get_type(
        "GenerateKeywordHistoricalMetricsRequest"
    )
    request.customer_id = customer_id
    request.keywords = ["mars cruise", "cheap cruise", "jupiter cruise"]
    # Geo target constant 2840 is for USA.
    request.geo_target_constants.append(
        googleads_service.geo_target_constant_path("2840")
    )
    request.keyword_plan_network = (
        client.enums.KeywordPlanNetworkEnum.GOOGLE_SEARCH
    )
    # Language criteria 1000 is for English. For the list of language criteria
    # IDs, see:
    # https://developers.google.com/google-ads/api/reference/data/codes-formats#languages
    request.language = googleads_service.language_constant_path("1000")

    response: GenerateKeywordHistoricalMetricsResponse = (
        keyword_plan_idea_service.generate_keyword_historical_metrics(
            request=request
        )
    )

    results: Iterable[GenerateKeywordHistoricalMetricsResult] = response.results
    for result in results:
        metrics: KeywordPlanHistoricalMetrics = result.keyword_metrics
        # These metrics include those for both the search query and any variants
        # included in the response.
        print(
            f"The search query '{result.text}' (and the following variants: "
            f"'{result.close_variants if result.close_variants else 'None'}'), "
            "generated the following historical metrics:\n"
        )

        # Approximate number of monthly searches on this query averaged for the
        # past 12 months.
        print(f"\tApproximate monthly searches: {metrics.avg_monthly_searches}")

        # The competition level for this search query.
        print(f"\tCompetition level: {metrics.competition}")

        # The competition index for the query in the range [0, 100]. This shows
        # how competitive ad placement is for a keyword. The level of
        # competition from 0-100 is determined by the number of ad slots filled
        # divided by the total number of ad slots available. If not enough data
        # is available, undef will be returned.
        print(f"\tCompetition index: {metrics.competition_index}")

        # Top of page bid low range (20th percentile) in micros for the keyword.
        print(
            f"\tTop of page bid low range: {metrics.low_top_of_page_bid_micros}"
        )

        # Top of page bid high range (80th percentile) in micros for the
        # keyword.
        print(
            "\tTop of page bid high range: "
            f"{metrics.high_top_of_page_bid_micros}"
        )

        # Approximate number of searches on this query for the past twelve
        # months.
        months: Iterable[MonthlySearchVolume] = metrics.monthly_search_volumes
        for month in months:
            print(
                f"\tApproximately {month.monthly_searches} searches in "
                f"{month.month.name}, {month.year}"
            )
      

Ruby

def generate_historical_metrics(customer_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  # Generates historical metrics and prints the results.
  keyword_plan_idea_service = client.service.keyword_plan_idea

  response = keyword_plan_idea_service.generate_keyword_historical_metrics(
    customer_id: customer_id,
    keywords: ["mars cruise", "cheap cruise", "jupiter cruise"],
    keyword_plan_network: :GOOGLE_SEARCH,

    # For the list of geo target IDs, see:
    # https://developers.google.com/google-ads/api/reference/data/geotargets
    # Geo target constant 2840 is for USA.
    geo_target_constants: [client.path.geo_target_constant("2840")],

    # Language criteria 1000 is for English.
    # For the list of language criteria IDs, see:
    # https://developers.google.com/google-ads/api/reference/data/codes-formats#languages
    language: client.path.language_constant("1000"),
  )

  for result in response.results
    metrics = result.keyword_metrics
    # These metrics include those for both the search query and any variants
    # included in the response.
    puts"The search query '#{result.text}' (and the following variants: " \
        "'#{result.close_variants}'), " \
        "generated the following historical metrics:\n"


    # Approximate number of monthly searches on this query averaged for the
    # past 12 months.
    puts "\tApproximate monthly searches: #{metrics.avg_monthly_searches}"

    # The competition level for this search query.
    puts "\tCompetition level: #{metrics.competition}"

    # The competition index for the query in the range [0, 100]. This shows
    # how competitive ad placement is for a keyword. The level of
    # competition from 0-100 is determined by the number of ad slots filled
    # divided by the total number of ad slots available. If not enough data
    # is available, undef will be returned.
    puts "\tCompetition index: #{metrics.competition_index}"

    # Top of page bid low range (20th percentile) in micros for the keyword.
    puts "\tTop of page bid low range: #{metrics.low_top_of_page_bid_micros}"

    # Top of page bid high range (80th percentile) in micros for the
    # keyword.
    puts"\tTop of page bid high range: "
        "#{metrics.high_top_of_page_bid_micros}"

    # Approximate number of searches on this query for the past twelve
    # months.
    for month in metrics.monthly_search_volumes
      puts "\tApproximately #{month.monthly_searches} searches in "
           "#{month.month.name}, #{month.year}"
    end
  end
end
      

Perl

sub generate_historical_metrics {
  my ($api_client, $customer_id) = @_;

  my $keyword_historical_metrics_response =
    $api_client->KeywordPlanIdeaService()->generate_keyword_historical_metrics({
      customerId => $customer_id,
      keywords   => ["mars cruise", "cheap cruise", "jupiter cruise"],
      # Geo target constant 2840 is for USA.
      geoTargetConstants => [
        Google::Ads::GoogleAds::V26::Utils::ResourceNames::geo_target_constant(
          2840)
      ],
      keywordPlanNetwork => 'GOOGLE_SEARCH',
      # Language criteria 1000 is for English. See
      # https://developers.google.com/google-ads/api/reference/data/codes-formats#languages
      # for the list of language criteria IDs.
      language =>
        Google::Ads::GoogleAds::V26::Utils::ResourceNames::language_constant(
        1000)});

  foreach my $result (@{$keyword_historical_metrics_response->{results}}) {
    my $metric = $result->{keywordMetrics};
    # These metrics include those for both the search query and any
    # variants included in the response.
    # If the metric is undefined, print (undef) as a placeholder.
    printf
"The search query, %s, (and the following variants: %s), generated the following historical metrics:\n",
      $result->{text},
      $result->{closeVariants}
      ? join(', ', $result->{closeVariants})
      : "(undef)";

    # Approximate number of monthly searches on this query averaged for
    # the past 12 months.
    printf "\tApproximate monthly searches: %s.\n",
      value_or_undef($metric->{avgMonthlySearches});

    # The competition level for this search query.
    printf "\tCompetition level: %s.\n", value_or_undef($metric->{competition});

    # The competition index for the query in the range [0, 100]. This shows how
    # competitive ad placement is for a keyword. The level of competition from
    # 0-100 is determined by the number of ad slots filled divided by the total
    # number of ad slots available. If not enough data is available, undef will
    # be returned.
    printf "\tCompetition index: %s.\n",
      value_or_undef($metric->{competitionIndex});

    # Top of page bid low range (20th percentile) in micros for the keyword.
    printf "\tTop of page bid low range: %s.\n",
      value_or_undef($metric->{lowTopOfPageBidMicros});

    # Top of page bid high range (80th percentile) in micros for the keyword.
    printf "\tTop of page bid high range: %s.\n",
      value_or_undef($metric->{highTopOfPageBidMicros});

    # Approximate number of searches on this query for the past twelve months.
    foreach my $month (@{$metric->{monthlySearchVolumes}}) {
      printf "\tApproximately %d searches in %s, %s.\n",
        $month->{monthlySearches}, $month->{month}, $month->{year};
    }
  }

  return 1;
}
      

curl

Google updates metrics such as search volume monthly based on the preceding month's search data.

Map to the UI

The following table maps KeywordPlanIdeaService.GenerateKeywordHistoricalMetrics parameters to Keyword Planner in the Google Ads UI:

Keyword Planner in the UI Google Ads API
Enter Keywords GenerateKeywordHistoricalMetricsRequest.keywords
Locations GenerateKeywordHistoricalMetricsRequest.geo_target_constants
Language GenerateKeywordHistoricalMetricsRequest.language
Search Networks GenerateKeywordHistoricalMetricsRequest.keyword_plan_network
Date Range GenerateKeywordHistoricalMetricsRequest.historical_metrics_options
CPC Bid HistoricalMetricsOptions.include_average_cpc