Reporting of performance data is an integral part of most AdWords API applications. With the API's flexible reporting options, you can obtain a report with performance data for an entire campaign, or focus more narrowly, for example, on the search queries that triggered your ad.
This guide describes the steps necessary to create and submit a report request to the Google server. It then describes some more advanced reporting concepts like data segmentation, data formats, and attribution.
For a complete list of all the available report types in the AdWords API, see the Report Types reference pages.
Overview
There are two main steps to generate reports from the API:
- Create a report definition. The report definition is an XML or AWQL fragment that defines the parameters of your report, including the report name, the types of information to include in the report, the download format, and other details.
- Enclose the report definition in an HTTP POST request, and submit it to the Google server.
Both of these steps are described below.
Create a report definition
The report definition constitutes the body of the request, where you specify the elements to include in the report.
You can create report definitions in XML or in AWQL, the AdWords Query Language.
The sections below cover XML-based report definitions. Check out the reporting section of the AWQL guide if you'd prefer to use AWQL instead of XML.
Below is an example of an XML report definition. The table below it defines each element in the report definition.
XML
<reportDefinition xmlns="https://adwords.google.com/api/adwords/cm/v201809"> <selector> <fields>CampaignId</fields> <fields>AdGroupId</fields> <fields>Impressions</fields> <fields>Clicks</fields> <fields>Cost</fields> <predicates> <field>AdGroupStatus</field> <operator>IN</operator> <values>ENABLED</values> <values>PAUSED</values> </predicates> </selector> <reportName>Custom Adgroup Performance Report</reportName> <reportType>ADGROUP_PERFORMANCE_REPORT</reportType> <dateRangeType>LAST_7_DAYS</dateRangeType> <downloadFormat>CSV</downloadFormat> </reportDefinition>
AWQL
SELECT CampaignId, AdGroupId, Impressions, Clicks, Cost
FROM ADGROUP_PERFORMANCE_REPORT
WHERE AdGroupStatus IN [ENABLED, PAUSED]
DURING LAST_7_DAYS
Report Definition Element | Description |
---|---|
<reportDefinition> |
This is the report definition header. Use the same URL shown in the request, ensuring the correct version of the API is listed. |
<selector> |
The selector section contains a list of fields for the data
elements you want to select and include in your report. See the
Report Types page for
more information about the values possible here. Note the field list
available depends on the reportType specified.
You can also use the
|
<predicates> |
Predicates are equivalent to filters in the Google Ads UI. A predicate is comprised of a report field, operators, and values. Predicates are treated as inclusive (AND) conditions. |
<reportType> |
Indicates the type of report you are requesting. See the Reports Types pages for more information and the complete list of report types. |
<dateRangeType> |
The date range your report should encompass. See Date ranges below for more information. |
<downloadFormat> |
The format in which you want to download the report. See Download formats below for more information. |
XML schema definition
An XML Schema Definition (XSD) defining the structure of the
reportDefinition
is published at the following URL:
https://adwords.google.com/api/adwords/reportdownload/v201809/reportDefinition.xsd
Both application/x-www-form-urlencoded
and multipart/form-data
Content-Types
are supported; for the former, you would need to URL-encode the submitted XML.
Date ranges
To specify the report's date range, use a ReportDefinition.DateRangeType
from
the report definition XSD.
Valid DateRange Types | Reports are generated for... |
---|---|
TODAY |
Today only. |
|
Yesterday only. |
LAST_7_DAYS |
The last 7 days not including today. |
LAST_WEEK |
The seven-day period starting with previous Monday. |
LAST_BUSINESS_WEEK |
The 5 day business week, Monday through Friday, of the previous business week. |
THIS_MONTH |
All days in the current month. |
LAST_MONTH |
All days in the previous month. |
ALL_TIME |
The entire available time range. |
CUSTOM_DATE |
A custom date range. See Custom date ranges below for more information. |
LAST_14_DAYS |
The last 14 days not including today. |
LAST_30_DAYS |
The last 30 days not including today. |
THIS_WEEK_SUN_TODAY |
The period between the previous Sunday and the current day. |
THIS_WEEK_MON_TODAY |
The period between the previous Monday and the current day. |
LAST_WEEK_SUN_SAT |
The seven-day period starting with the previous Sunday. |
For every ReportDefinition.DateRangeType
except CUSTOM_DATE
, only the dateRangeType
is required.
<reportDefinition xmlns="https://adwords.google.com/api/adwords/cm/v201809"> ... <dateRangeType>LAST_7_DAYS</dateRangeType> </reportDefinition>
Custom date ranges
If you want a custom date range, then you must:
- Specify
CUSTOM_DATE
for thedateRangeType
. - Include a
dateRange
withmin
andmax
inYYYYMMDD
format on yourselector
.
XML
<reportDefinition xmlns="https://adwords.google.com/api/adwords/cm/v201809"> <selector> ... <dateRange> <min>20150201</min> <max>20150301</max> </dateRange> </selector> <dateRangeType>CUSTOM_DATE</dateRangeType> </reportDefinition>
AWQL
...
DURING 20150201,20150301
Data freshness
Some statistics that go into your reports may be calculated continuously, while others may be calculated once a day. This is one aspect of how data freshness works in Google Ads. To use reporting effectively, see the data freshness documentation.
Prepare the request
Once your report definition is created, you can now prepare the HTTP POST request.
You can make plain synchronous HTTP requests directly to the Google server, an approach whose low overhead makes it suitable for high-volume reporting, especially when implemented using multiple threads (we recommend starting with 10). The HTTP request is synchronous because the call effectively blocks until the report data is ready to download.
You'll probably reach the Queries Per Second (QPS) limit (RateExceededError
)
before you exceed the number of open connections allowed on the server.
Reporting requests do not count toward the daily operations quota, but
there is a report downloads-per-day limit.
For an XML report definition, the POST
request body must contain a parameter
named "__rdxml
" whose value is your XML report definition.
Request headers
Use the normal HTTP header values when downloading reports:
HTTP header | Description |
---|---|
Authorization: Bearer OAUTH2_ACCESS_TOKEN
|
Authorization to download the report. Use the same
accessToken that's used for the
SOAP request header. |
developerToken: DEVELOPER_TOKEN |
Your developer token consisting of a unique string, for example, 1a2B3c4D5e_-6v7w8x9y0z. |
clientCustomerId: CLIENT_CUSTOMER_ID |
Customer ID of the client account. |
You can specify the following optional HTTP headers to control whether your report includes a header or summary row:
Optional HTTP Header | Description |
---|---|
skipReportHeader: true|false |
If true , report output will not include a header row
containing the report name and date range. If false or
not specified, report output will include the header row. |
skipColumnHeader: true|false |
If true , report output will not include a header row
containing field names. If false or
not specified, report output will include the field names. |
skipReportSummary: true|false |
If true , report output will not include a summary row
containing the report totals. If false or
not specified, report output will include the summary row. |
useRawEnumValues: true|false |
Set to true if you want the returned format to be the actual
enum value, for example, "IMAGE_AD" instead of "Image ad".
Set to false or omit this header if you want the returned
format to be the display value. |
includeZeroImpressions: true|false |
If true , report output will include rows where all specified metric fields are zero,
provided the requested fields and predicates support zero impressions.
If false , report output will not include such rows.
Thus, even if this header is false and the Impressions of a row is zero, the row is still returned in case any of the specified metric fields have non-zero values.
If omitted, the report will use the default behavior described in
the Zero Impressions guide. |
HTTP request URL
The request consists of an HTTP POST to the Google server at the following URL:
https://adwords.google.com/api/adwords/reportdownload/v201809
Complete example
Here is a complete example showing the report definition above enclosed within an HTTP POST request.
XML
POST /api/adwords/reportdownload/v201809 HTTP/1.1 Host: adwords.google.com User-Agent: curl, gzip Accept: */* Accept-Encoding: gzip Authorization: Bearer [Enter OAuth 2.0 access token here] developerToken: [Enter developerToken here] clientCustomerId: [Enter clientCustomerID here] Content-Length: 784 Expect: 100-continue Content-Type: multipart/form-data; boundary=------------------------12d01fae60c7b559 Parameters: __rdxml: <?xml version="1.0" encoding="UTF-8"?> <reportDefinition xmlns="https://adwords.google.com/api/adwords/cm/v201809"> <selector> <fields>CampaignId</fields> <fields>AdGroupId</fields> <fields>Impressions</fields> <fields>Clicks</fields> <fields>Cost</fields> <predicates> <field>AdGroupStatus</field> <operator>IN</operator> <values>ENABLED</values> <values>PAUSED</values> </predicates> </selector> <reportName>Custom Adgroup Performance Report</reportName> <reportType>ADGROUP_PERFORMANCE_REPORT</reportType> <dateRangeType>LAST_7_DAYS</dateRangeType> <downloadFormat>CSV</downloadFormat> </reportDefinition>
AWQL
POST /api/adwords/reportdownload/v201809 HTTP/1.1 Host: adwords.google.com User-Agent: curl, gzip Accept: */* Accept-Encoding: gzip Authorization: Bearer [Enter OAuth 2.0 access token here] developerToken: [Enter developerToken here] clientCustomerId: [Enter clientCustomerID here] Content-Length: 182 Expect: 100-continue Content-Type: multipart/form-data; boundary=------------------------12d01fae60c7b559 Parameters: __fmt: CSV __rdquery: SELECT CampaignId, AdGroupId, Impressions, Clicks, Cost
FROM ADGROUP_PERFORMANCE_REPORT
WHERE AdGroupStatus IN [ENABLED, PAUSED] DURING LAST_7_DAYS
Response codes
If the report request is successful, the server returns a Response Code of 200
.
A Response Code of 400
indicates an API error; check for any issues with
the XML in your report definition.
A Response Code of 500
typically indicates a temporary problem with the server;
if this error occurs, retry the request after a few moments.
Reports for multiple accounts
A given report request can only include data from a single Google Ads account.
If you need to gather reporting data for multiple accounts, submit a separate
report request for each account by setting the clientCustomerId
header
described above.
Timeouts
The report download request may time out on extremely large data sets. There is no explicit data size limit; however, due to a variety of factors, the server may return an error if the report is too large.
If you encounter timeouts or errors, try a shorter date range or use predicates to break up the report request into multiple, smaller requests. For example, instead of running a single report for all campaigns, you could submit multiple requests that each filter for a subset of Campaign IDs.
Supported download formats
Format | Description |
---|---|
CSVFOREXCEL | The format for Excel. This uses a format of unicode which is prepended with a BOM (byte order marker) to signal to Excel that it is unicode. Excel defaults to use tab as a separator when unicode is being used. If comma is used then Excel will put all of the data in each row into a single column (by default). |
CSV | The csv (comma separated) output format. |
TSV | The tsv (tab separated) output format. |
XML | The xml output format. |
GZIPPED_CSV | The gzip compressed csv (comma separated) output format. |
GZIPPED_XML | The gzip compressed xml output format. |
Choosing the right report
Because of the extensive reporting options available in the AdWords API, determining the correct report for a particular business need can be tricky.
Use the chart below to determine the most suitable report, then check out the details for that report on the Report Types page.

Segmentation
For more detailed statistics, you can split the data by segments. For example, you might be interested in knowing the number of impressions specific to the Google Search Network, separate from the Google Display Network; in which case, you will want to segment your report by network.
Segmentation, which is available in the UI as a separate menu, is achieved in
the API by just adding the proper field to the report. For example, adding the
field AdNetworkType1
to an Ad Group Performance report results
in a report with a row for each ad group and network combination, and
the statistical values (impressions, clicks, conversions, etc.) split between
them. While in the UI only one segment at a time can be used for display, with
the API you can combine multiple segments in the same report. Keep in mind that
the amount of rows can increase exponentially for each additional segment field
included in your report.
Implicit segmentation
Every report is segmented by its unique key. For example,
the Keywords Performance
report is implicitly segmented by Id
and AdGroupId
, even
though they're not included in the selector fields, because a keyword is
identified by both Id
and AdGroupId
.
Keyword,MatchType,Impressions
Keyword1,Exact,3
Keyword2,Exact,10
Keyword3,Exact,5
Keyword4,Broad,4
Single and multiple attribution
When an impression occurs on the Display network, the criteria that play a role in this occurrence can be recorded in one of two ways: single or multiple attribution.
Single attribution
With single attribution, only one of the triggering criteria (such as placement, age, keyword, etc.) is recorded for a given impression. An impression may be triggered by multiple criteria, but on a single attribution report the impression and all of its stats are attributed only to a single criterion.
Each impression is counted exactly once (under one criterion); adding up all the criteria will give you values that match the totals in multiple attribution reports.
Both the Criteria Performance and Keywords Performance reports use this model.
Example report
The example below shows a Criteria Performance Report (single attribution) for a campaign targeting only the Display Network, and using only verticals and placements as criteria. The report shows 10 total impressions across five rows, one row for each of three placements and one row for each of two verticals that triggered impressions—each getting two impressions.
Keyword / Placement,Impressions
www.example.com,2
www.example.ca,2
www.example.net,2
Computers & Electronics,2
Sports,2
Multiple attribution
With multiple attribution, up to one criterion in each dimension that triggered the impression will have the impression recorded for it. Multiple attribution reports can be thought of as criteria type-specific reports: Unlike single attribution where a row can contain different criteria types, each multiple attribution report contains criteria for only one criteria type.
For example, the Gender Performance report summarizes all of your impressions by Gender, the Age Range Performance report summarizes impressions by AgeRange, and so on. The Display Topics Performance and Placement Performance reports also follow this model.
Unlike single attribution, multiple attribution reports should NOT be aggregated together, since this may double count impressions and clicks.
Example
Topic,Impressions
Computers & Electronics,6
Sports,4
Placement,Impressions
www.example.com,4
www.example.ca,3
www.example.net,3
If you target Display Only with verticals (topics) and placements, and run a Display Topics report, you'll get one row for each vertical (topic) that triggered impressions. Likewise, a Placements performance report will return one row per impressions. These reports are covering the same impressions, because up to one vertical and one placement will both be attributed to each impression.
Special criterion IDs
KeywordId=100 (runofnetwork::100)
This ID is reserved for logging served ads from ad groups that have no targeting criteria (and so are eligible for running on the entire Display or Video network).
KeywordId=3000000
In single attribution reports, all keywords that triggered impressions on the
display network will be represented by a special keyword (text: Content
) with
ID 3000000
.
Example
Keyword ID,Impressions
23458623485,2
23655322314,2
23953456345,2
3000000,4
If you target keywords and placements for Display Only and run an Ad
Performance report, you'll get a row for each ad and triggering criteria
combination for placements, and a single row with ad and ID 3000000
which
accounts for all the display keywords that triggered that ad (where single
attribution chose the keyword rather than a placement).
KeywordId=3000004
A criteria ID of 3000004
was used for a feature that has since been removed
from Google Ads.
KeywordId=3000006
A criteria ID of 3000006
represents stats associated with
aggressive auto-targeting.
Format of various fields
While all fields returned in reports have a
Type
, the actual values returned won't always match these values. You should
always check the Notes column, which often contains additional information
about the expected format of values. For example, the Notes column for
ConversionRate
states: Percentage returned as "x.xx%"
.
Money fields in reports
Fields of type Money
are returned in micro currency units (micros) but may be
prefixed with "auto: " or may simply be the string "auto" if automatic bidding
is used.
For example, $1.23 will come back as 1230000
(1.23 x 1,000,000).
Micro amounts always refer to the account's local currency.
When filtering on money fields, you'll have to provide the value in micros.
For example, WHERE AverageCpc > 1000000
will return rows where the
AverageCpc
is greater than $1 (one unit of the account currency).
Quality score in reports
Quality score is represented in Keywords Performance and Criteria Performance reports as a score from 1 (lowest) to 10 (highest).
A value of two dashes (--
) are used to indicate that no current quality score
is available for a keyword. In addition, the column HasQualityScore
allows you
to easily filter for keywords that have no quality score available. For example,
the following AWQL query selects keywords that have a valid quality score:
SELECT CampaignId, AdGroupId, Id, Criteria, CriteriaType, QualityScore
FROM CRITERIA_PERFORMANCE_REPORT
WHERE Status IN [ENABLED, PAUSED] and HasQualityScore='TRUE'
The following table summarizes the behavior for QualityScore
and HasQualityScore
:
Keyword state | QualityScore | HasQualityScore |
---|---|---|
Has a valid quality score | Between 1 and 10 , inclusive |
true |
Insufficient impressions or clicks to determine quality score | -- |
false |
Has not served recently | -- |
false |
Deleted | -- |
false |
Display keyword whose quality score could not be determined | -- |
false |
Two dashes
A value of two dashes (--) indicates there is no value for this cell.
Lists and maps
Items of a list will be formatted using JSON; for example, a Scheduling
from
PLACEHOLDER_FEED_ITEM_REPORT
value would consist of an array of strings:
["Monday, 6:00PM - 9:00PM","Tuesday, 6:00PM - 9:00PM","Wednesday,6:00PM - 9:00PM",
"Thursday, 6:00PM - 9:00PM","Friday, 6:00PM - 9:00PM"]
Similarly, for a map (such as UrlCustomParameters
):
{"param0":"value0","param1":"value1"}
Criteria prefixes
The
Criteria
and
CriteriaParameters
fields contain string representations of criteria. In
many cases, the string representation is straightforward:
Luxury Cruise to Mars
for aKeyword
withtext = 'Luxury Cruise to Mars'
.Not a parent
for aParent
withparentType = PARENT_NOT_A_PARENT
.18-24
for anAgeRange
withageRangeType = AGE_RANGE_18_24
.
However, the criteria types below are more complex and will have a string
representation of the form prefix::identifier
.
CriterionUserInterest
- Prefix:
uservertical
- Identifier:
CriterionUserInterest.userInterestId
Sample:
uservertical::92000
To get more details for each identifier, use either of the following:
- The Affinity categories and In-market categories documentation.
ConstantDataService.getUserInterestCriterion
withuserInterestTaxonomyType = IN_MARKET
.
CriterionUserList
Prefix:
boomuserlist
Identifier:
CriterionUserList.userListId
Sample:
boomuserlist:123456
To get more details for each identifier, use
AdwordsUserListService
to retrieveUserList
objects where theid
matches the identifier.ContentLabel
Prefix:
contentlabel
Identifier:
ContentLabel.contentLabelType
Sample:
contentlabel::afe
To get more details for each identifier, see the description for the
ContentLabelType
instance that matches the identifier (ignoring case).- Custom intent audiences
Prefix:
custominmarket
Identifier: N/A
Sample:
custominmarket::1771944
The AdWords API does not support management or retrieval of custom intent audiences via services such as AdGroupCriterionService, but you may see this prefix appear in reports.
MobileAppCategory
Prefix:
mobileappcategory
Identifier:
MobileAppCategory.mobileAppCategoryId
Sample:
mobileappcategory::60019
To get more details for each identifier, use the Mobile app categories documentation or the
DisplayName
field in reports.MobileApplication
Prefix:
mobileapp
Identifier:
MobileApplication.appId
Sample:
mobileapp::2-com.google.android.launcher
To get more details for each identifier, use the
DisplayName
field in reports.Vertical
Prefix:
docvertical
Identifier:
Vertical.verticalId
Sample:
docvertical::3
To get more details for each identifier, use either of the following:
- The Verticals documentation.
ConstantDataService.getVerticalCriterion
to retrieveVertical
objects where theverticalId
matches the identifier.
Troubleshooting
This section describes how to resolve some common reporting issues.
Empty default rows returned in reports
You might see reports containing rows labelled Default
that
contain blank values. These rows are typically returned when your
report selectors are not logically consistent. This could occur
if you select a sub-field of a parent category when you didn't
select the parent category in the report definition, for example,
if you specify a field such as ConversionTypeName
without also
selecting its parent Conversions
or AllConversions
.
If these rows appear in your reports, checking the logical consistency of the selectors used to generate the report should reveal the source of the problem.
Selecting system-wide default conversion trackers
The Google Ads UI and the AdWords API handle system-wide default conversion trackers in special ways that allow for cleaner presentation in the user interface, and automatic translation when running reports in languages other than English.
Using a system-wide default conversion tracker as a selector
in a report definition without specifying its id
can produce
unexpected results in reports.
For example, if you use the
AdCallMetricsConversion
system-wide default conversion tracker, and specify its
id 239
,
the row is rendered in Google Ads UI reports as Store Visits.
If you specify the same id
in a report definition through the API, it also
recognizes the selection as a system-wide type, and renders it as
Store Visits. Moreover, if you run the report in another language, this
phrase is automatically translated, since the
system understands you've explicitly selected this system-wide default
conversion tracker.
System-wide default conversion trackers are user-modifiable, and the
system retains any changes you make to them. Therefore, if you don't
explicitly select the id
, the report returns
the default name store_visits
, since it can't determine if
you intended to include the id
of the system-wide default conversion tracker,
or a user-defined id
.
Thus, when using system-wide default conversion trackers in your reports,
be sure to explicitly specify the id
of the conversion tracker to ensure
consistent output.