Segmentation

Segmentation, available in the Google Ads UI as a separate menu, can be implemented in the Google Ads API by just adding the proper field to a query. For example, adding segments.device to a query, results in a report with a row for each combination of device and the specified resource in the FROM clause, and the statistical values (impressions, clicks, conversions, etc.) split between them.

While in the Google Ads UI only one segment at a time can be used, with the API you can specify multiple segments in the same query.

SELECT
  campaign.name,
  campaign.status,
  segments.device,
  metrics.impressions
FROM campaign

The results from sending this query to GoogleAdsService.SearchStream would look something like this JSON string:

{
  "results":[
    {
      "campaign":{
        "resourceName":"customers/1234567890/campaigns/111111111",
        "name":"Test campaign",
        "status":"ENABLED"
      },
      "metrics":{
        "impressions":"10922"
      },
      "segments":{
        "device":"MOBILE"
      }
    },
    {
      "campaign":{
        "resourceName":"customers/1234567890/campaigns/111111111",
        "name":"Test campaign",
        "status":"ENABLED"
      },
      "metrics":{
        "impressions":"28297"
      },
      "segments":{
        "device":"DESKTOP"
      }
    },
    ...
  ]
}

Note that in the above sample result, attributes for the first and second objects including the resource name are the same. The impressions are segmented by device and thus two or more objects can be returned for the same campaign.

Implicit segmentation

Every report is initially segmented by the resource specified in the FROM clause. The resource_name field of the resource in the FROM clause is returned and metrics are segmented by it, even when the resource_name field is not explicitly included in the query. For example, when you specify ad_group as the resource in the FROM clause, then ad_group.resource_name will automatically be returned and metrics will implicitly segment against it at the ad_group level.

So for this query,

SELECT metrics.impressions
FROM ad_group

you would get a JSON string like this:

{
  "results":[
    {
      "adGroup":{
        "resourceName":"customers/1234567890/adGroups/2222222222"
      },
      "metrics":{
        "impressions":"237"
      }
    },
    {
      "adGroup":{
        "resourceName":"customers/1234567890/adGroups/33333333333"
      },
      "metrics":{
        "impressions":"15"
      }
    },
    {
      "adGroup":{
        "resourceName":"customers/1234567890/adGroups/44444444444"
      },
      "metrics":{
        "impressions":"0"
      }
    }
  ]
}

Note that the resource_name field of adGroup is always returned because ad_group was specified as a resource in the FROM clause.

Selectable segment fields

Not all segment fields are selectable for a given resource in the FROM clause. As an example, we'll continue to query from the ad_group resource. For a segment field to be selectable from the ad_group resource, that field needs to exist in the Segments list for ad_group. The Segments list is the yellow portion of the available fields table on the ad_group resource's metadata page.

Segment resources

When selecting from some resources, you may have the option to implicitly join on related resources by selecting their fields alongside the fields of the resource in the FROM clause. These related resources can be found in the Attributed Resources list on the resource in the FROM clause's metadata page. In the case of the ad_group resource, you'll see that you can also select fields from the campaign resource. The resource_name field of any Attributed Resources with at least 1 field in the SELECT clause will automatically be returned, even when the resource_name field is not explicitly included in the query.

Similar to selecting Attributed Resource fields, you can also select Segmenting Resource fields. If a given resource has a Segmenting Resources list on its metadata page, then selecting fields from one of those listed resources will cause the query to be further segmented by the returned resource_name of that Segmenting Resource. As an example, you'll find that the campaign resource is listed as a Segmenting Resource for the campaign_budget resource. Selecting any campaign field, like campaign.name, from the campaign_budget resource will not only cause the campaign.name field to be returned, but will cause the campaign.resource_name field to be returned and segmented on.

Selectability between segments and metrics

A given segment field may not be compatible with some of the other segment fields, or with some of the metrics fields. To identify which segment fields are compatible with each other, you can review the selectable_with list of the segments in the SELECT clause.

In the case of the ad_group resource, there are 50+ available segments that you can select. However, the selectable_with list for segments.hotel_check_in_date is a much smaller set of compatible segments. This means if you add the segments.hotel_check_in_date field into the SELECT clause, you will limit the available segments you have left to select to the intersection of these two lists.

When adding some segments, the metrics in the summary row may decrease
When segments.keyword.info.match_type is added to a query with FROM ad_group_ad, that segment is telling the query to only get the rows of data that have keywords, and remove any row that is not associated with a keyword. In this case, the metrics would be lower because it would exclude any non-keyword metrics.

Rules for segments in the WHERE clause

When a segment is in the WHERE clause, it must also be in the SELECT clause. The exception to this rule are the following date segments, which are referred to as core date segments:

  • segments.date
  • segments.week
  • segments.month
  • segments.quarter
  • segments.year

Rules for core date segment fields

The segments segments.date, segments.week, segments.month, segments.quarter, and segments.year function as follows:

  • These segments can be filtered in the WHERE clause without appearing in the SELECT clause.

  • If any of these segments are in the SELECT clause, a finite date range composed of core date segments must be specified in the WHERE clause (the date segments don't need to be the same ones specified in the SELECT).

Examples

Invalid: Since segments.date is in the SELECT clause, you need to specify a finite date range in the WHERE clause for a segments.date, segments.week, segments.month, segments.quarter, or segments.year.
SELECT
  campaign.name,
  metrics.clicks,
  segments.date
FROM campaign
Valid: This query returns campaign names and clicks accrued during the date range. Note that segments.date doesn't need to appear in the SELECT clause.
SELECT
  campaign.name,
  metrics.clicks
FROM campaign
WHERE segments.date > '2020-01-01'
  AND segments.date < '2020-02-01'
Valid: This query returns campaign names and clicks segmented by date for all days in the date range.
SELECT
  campaign.name,
  metrics.clicks,
  segments.date
FROM campaign
WHERE segments.date > '2020-01-01'
  AND segments.date < '2020-02-01'
Valid: This query returns campaign names and clicks segmented by month for all days in the date range.
SELECT
  campaign.name,
  metrics.clicks,
  segments.month
FROM campaign
WHERE segments.date > '2020-01-01'
  AND segments.date < '2020-02-01'
Valid: This query returns campaign names and clicks segmented by quarter and then by month for all months in the year range.
SELECT
  campaign.name,
  metrics.clicks,
  segments.quarter,
  segments.month
FROM campaign
WHERE segments.year > 2015
  AND segments.year < 2020

search_term_view

Note that for the search_term_view resource, it's also implicitly segmented by ad group, not just a search term, as reflected by the structure of its resource name, which also includes ad group as well. Therefore, you will get some seemingly duplicate rows with the same search terms appearing in your results when in actuality, the rows would belong to a different ad group:

{
  "results":[
    {
      "searchTermView":{
        "resourceName":"customers/1234567890/searchTermViews/111111111~2222222222~Z29vZ2xlIHBob3RvcyBpb3M",
        "searchTerm":"google photos"
      },
      "metrics":{
        "impressions":"3"
      },
      "segments":{
        "date":"2015-06-15"
      }
    },
    {
      "searchTermView":{
        "resourceName":"customers/1234567890/searchTermViews/111111111~33333333333~Z29vZ2xlIHBob3RvcyBpb3M",
        "searchTerm":"google photos"
      },
      "metrics":{
        "impressions":"2"
      },
      "segments":{
        "date":"2015-06-15"
      }
    }
  ]
}

Although the two returned objects in this example seem to be duplicates, their resource names are actually different, particularly in the "ad group" part. This means that the search term "google photos" is attributed to the two ad groups (ID 2222222222 and 33333333333) on the same date (2015-06-15). Thus, we can conclude that the API worked as intended and didn't return duplicate objects in this case.