This guide provides guidelines to migrate the Core Reporting API v3
to the Analytics Reporting API v4.
Introduction
To take advantage of the new
features
introduced in the Analytics Reporting API v4, migrate your code to use the API.
This guide shows requests in the Core Reporting API v3 and the equivalent requests
in the Analytics Reporting API v4 to make your migration easier.
Python migration
If you are a Python developer, use the
GAV4
helper library on GitHub to convert Google Analytics Core Reporting API v3 requests
to Analytics Reporting API v4 requests
Endpoints
The Core Reporting API v3 and the Analytics Reporting API v4 have
different endpoints and HTTP methods:
v3 Endpoint
GET https://www.googleapis.com/analytics/v3/data/ga
v4 Endpoint
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
The following examples compare a request in v3 and the equivalent request in v4:
v3
v3 reference documentation
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&start-date=2015-11-01&end-date=2015-11-06 \
&metrics=ga:users&dimensions=ga:pagePath
v4
v4 reference documentation
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
"viewId":"XXXX",
"dateRanges":[
{
"startDate":"2015-11-01",
"endDate":"2015-11-06"
}],
"metrics":[
{
"expression":"ga:users"
}],
"dimensions": [
{
"name":"ga:pagePath"
}]
}]
}
Client Libraries and Discovery Service
If you use the Python, JavaScript, or other client library that relies on
Google Discovery Service
,
you need to provide the location of the discovery document for the Reporting API v4.
Python
from apiclient import discovery
...
# Build the Analytics Reporting API v4 authorized service object.
analyticsReporting = discovery.build(
'analyticsreporting',
'v4',
http=http,
discoveryServiceUrl='https://analyticsreporting.googleapis.com/$discovery/rest')
JavaScript
gapi.client.load(
'https://analyticsreporting.googleapis.com/$discovery/rest',
'v4'
).then(...)
The
Java and PHP client libraries
are pre-built, but you can use the discovery service and the
Google APIs generator
to generate them.
Requests
The
API v4 reference
describes in detail the structure of the request body. The following sections describe the
migration of v3 request parameters to v4 request parameters.
View IDs
In v3, an
ids
paramter, which accepts a "table ID", is in the format of
ga:XXXX
,
where
XXXX
is the view (profile) ID. In v4, a view (profile) ID is specified
in the
viewId
field in the request body.
The following examples compare the
ids
parameter in a v3 request and the
viewId
field in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
"viewId":"XXXX",
...
}]
}
Date Ranges
The Analytics Reporting API v4 allows you to specify multiple date ranges
in a single request. The
dateRanges
field takes a list of
DateRange
objects.
In v3, you use the
start-date
and
end-date
parameters to specify a date range
in a request.
The following examples compare the
start-date
and
end-date
parameters in a v3 request
and the
dateRanges
field in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&start-date=2015-11-01&end-date=2015-11-06 \
...
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
"viewId":"XXXX",
"dateRanges":[
{
"startDate":"2015-11-01",
"endDate":"2015-11-06"
}],
....
}]
}
Metrics
The v3
metrics
parameter corresponds to the v4
metrics
field that takes a list of
Metric
objects.
The following examples compare the
metrics
parameters in a v3 request
and the
metrics
field in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&start-date=2015-11-01&end-date=2015-11-06 \
&metrics=ga:users,ga:sessions \
...
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
"viewId":"XXXX",
"dateRanges":[
{
"startDate":"2015-11-01",
"endDate":"2015-11-06"
}],
"metrics":[
{
"expression":"ga:users"
},{
"expression":"ga:sessions"
}],
...
}]
}
Dimensions
The v3
dimensions
parameter corresponds to the v4
dimensions
field that takes a list of
Dimension
objects.
The following examples compare the
dimensions
parameters in a v3 request
and the
dimensions
field in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&dimensions=ga:country,ga:browser&... \
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
...
"dimensions": [
{
"name":"ga:country"
},{
"name":"ga:browser"
}],
...
}]
}
Sorting
The v3
sort
parameter is equivalent to the v4
orderBys
field that takes a list of
OrderBy
objects.
In v4, to sort the results by a dimension or metric value:
- Supply its name or alias through the
fieldName
field.
- Specify the sort order (
ASCENDING
or
DESCENDING
)
through the
sortOrder
field.
The following examples compare the
sort
parameter in a v3 request
and the
orderBy
field in a v4 request; they both sort the users
in descending order and sources alphabetically:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&sort=-ga:users,ga:source
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
...
"orderBys": [
{
"fieldName": "ga:users",
"sortOrder": "DESCENDING"
},{
"fieldName": "ga:source"
}],
}]
}
Sampling Level
The v3
samplingLevel
parameter corresponds to the v4
samplingLevel
field. In v3, the accepted
samplingLevel
values are
FASTER
,
HIGHER_PRECISION
, and
DEFAULT
; and
in v4, the accepted
samplingLevel
values are
SMALL
,
LARGE
, and
DEFAULT
.
Note that
FASTER
in v3 has changed to
SMALL
in v4,
HIGHER_PRECISION
to
LARGE
.
The following examples compare the
samplingLevel
parameter in a v3 request
and the
samplingLevel
field in a v4 request:
v3
https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX ...\
samplingLevel=HIGHER_PRECISION
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
...
"samplingLevel": "LARGE"
}]
}
Segments
The v3
segment
parameter corresponds to the v4
segments
field that takes a list of
Segment
objects.
Segment IDs
In v4, to request a segment by segment ID, construct a
Segment
object and supply its ID through the
segmentId
field.
The following examples compare the
segment
parameter in a v3 request
and the
segments
field in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&segment=gaid::-11
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests": [{
...
"viewId": "XXXX",
"segments": [{
"segmentId": "gaid::-11"
}]
}]
}
Dynamic Segments
In v4, to express more complicated segment definitions, use
the
segments
field that includes a
DynamicSegment
object.
The following examples compare the
segment
parameter in a v3 request
and the
segments
field containing a
DynamicSegment
object in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&segment=sessions::condition::ga:medium==referral
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests": [{
...
"segments": [{
"dynamicSegment": {
"name": "segment_name",
"sessionSegment": {
"segmentFilters": [{
"simpleSegment": {
"orFiltersForSegment": [{
"segmentFilterClauses": [{
"dimensionFilter": {
"dimensionName": "ga:medium",
"operator": "EXACT",
"expressions": [ "referral" ]
}
}]
}]
}
}]
}
}
}]
}]
}
You can combine conditions and sequences in a segment:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&segment=users::condition::ga:revenue>10;sequence::ga:deviceCategory==desktop->>ga:deviceCategory==mobile
v4
"reportRequests": [{
"dateRanges": [
{ "endDate": "2014-11-30", "startDate": "2014-11-01" }
],
"metrics": [
{"expression": "ga:pageviews"},
{"expression": "ga:sessions"}
],
"viewId": "XXXX",
"dimensions":[{"name":"ga:medium"}, {"name":"ga:segment"}],
"segments": [{
"dynamicSegment": {
"name": "segment_name",
"userSegment": {
"segmentFilters": [{
"simpleSegment": {
"orFiltersForSegment": [{
"segmentFilterClauses": [{
"metricFilter": {
"metricName": "ga:sessions",
"operator": "GREATER_THAN",
"comparisonValue": "10"
}
}]
}]
}
},
{
"sequenceSegment": {
"segmentSequenceSteps": [{
"orFiltersForSegment": [{
"segmentFilterClauses": [{
"dimensionFilter": {
"dimensionName": "ga:deviceCategory",
"operator": "EXACT",
"expressions": ["desktop"]
}
}]
}],
"matchType": "PRECEDES"
},{
"orFiltersForSegment": [{
"segmentFilterClauses": [{
"dimensionFilter": {
"dimensionName": "ga:deviceCategory",
"operator": "EXACT",
"expressions": ["mobile"]
}
}]
}]
}]
}
}]
}
}
}]
}]
v3 Segments Syntax in v4
The
segmentId
field in the v4 API supports the segment syntax in the v3 API.
The following examples show how the
segment
parameter in a v3 request
is supported by the
segmentId
field in the equivalent request in v4:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&segment=sessions::condition::ga:medium==referral
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests": [{
...
"viewId": "XXXX",
"segments": [{
"segmentId": "sessions::condition::ga:medium==referral"
}]
}]
}
Filters
v4 uses
dimensionFilterClauses
to
filter dimensions and
metricFilterClauses
to filter metrics. A
dimensionFilterClauses
contains a list of
DimensionFilter
objects;
and a
metricFilterClauses
contains a list of
MetricFilter
objects.
The following examples compare the
filters
parameter in a v3 request
and the
dimensionFilterClauses
field in a v4 request:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXX \
&start-date=2015-06-01&end-date=2015-07-31&metrics=ga:users& \
dimensions=ga:browser&filters=ga:browser==Firefox
v4
"reportRequests": [{
"dateRanges": [
{ "endDate": "2014-11-30", "startDate": "2014-11-01" }
],
"metrics": [
{"expression": "ga:pageviews"},
{"expression": "ga:sessions"}
],
"viewId": "XXXX",
"dimensions":[{"name":"ga:browser"}, {"name":"ga:country"}],
"dimensionFilterClauses": [{
"filters": [{
"dimension_name": "ga:browser",
"operator": "EXACT",
"expressions": ["Firefox"]
}]
}]
}]
v3 filters syntax in v4
Although the
filtersExpression
field in v4 supports the
filters
syntax in v3, use
dimensionFilterClauses
and
metricFilterClauses
to filter
dimensions and metrics.
The following examples show how the
filters
parameter in a v3 request
is supported by the
filtersExpression
field in the equivalent request in v4:
v3
GET https://www.googleapis.com/analytics/v3/data/ga?ids=ga%XXXX \
&filters=ga:browser==Firefox
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests": [{
...
"filtersExpression": "ga:browser==Firefox"
}]
}
Empty rows
The v3
include-empty-rows
parameter corresponds to the
includeEmptyRows
field in v4. The v3 parameter defaults to
true
, while in v4 the field
defaults to
false
. If you do not have the value set in v3 you will need to set the
value to
true
in v4.
The following examples compare the
include-empty-rows
parameter in a v3 request to the
includeEmptyRows
field in a v4 request:
v3
https://www.googleapis.com/analytics/v3/data/ga? ...\
&include-empty-rows=true
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
...
"includeEmptyRows": "true",
}]
}
v4 uses the
pageToken
and
pageSize
fields
to paginate through a large number of results. The
pageToken
is obtained from the
nextPageToken
property of a response object.
The following examples compare the
start-index
and
max-results
parameters
in a v3 request to the
pageToken
and
pageSize
fields in a v4 request:
v3
https://www.googleapis.com/analytics/v3/data/ga? ...\
&start-index=10001&max-results=10000
v4
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet
{
"reportRequests":[
{
...
# Taken from `nextPageToken` of a previous response.
"pageToken": "10000",
"pageSize": "10000",
}]
}
Standard Parameters
The Analytics Reporting API v4 supports most of the
standard query parameters
in the v3 API, except for the
userIp
and
callback
parameters.
The following examples compare the
quotaUser
parameter in a v3 request to that in
a v4 request:
v3 Endpoint
GET https://www.googleapis.com/analytics/v3/data/ga?quotaUser=1X3F2F2
v4 Endpoint
POST https://analyticsreporting.googleapis.com/v4/reports:batchGet?quotaUser=1X3F2F2
Responses
Because v4 allows you to submit multiple
ReportRequest
objects in a single HTTP request, you get an array of report objects in the response.
For every submitted
ReportRequest
,
you get a corresponding
Report
in the response.
Reports
A v4
Report
has three top-level fields:
columnHeader
,
data
, and
nextPageToken
.
Because the v4 response body doesn't include responses
to all query parameters as the v3 response does, to get a response
to a specific query parameter, the client application must add that
parameter to the
ReportRequest
.
We've already addressed
nextPageToken
in the
Pagination
section, so lets
first look at the
columnHeader
object.
Column Header
The column header contains a list of named
dimensions
and a
MetricHeader
object,
which contains a list of
MetricHeaderEntry
objects. Each
MetricHeaderEntry
object specifies the metric
name
and its
type
(currency, percent, etc.)
, which helps you format the output.
The following examples compare the
columnHeaders
field in a v3 response
to the
columnHeader
field in a v4 response:
v3
"columnHeaders": [
{
"name":"ga:source",
"columnType":"DIMENSION",
"dataType":"STRING"
},{
"name":"ga:city",
"columnType":"DIMENSION",
"dataType":"STRING"
},{
"name":"ga:sessions",
"columnType":"METRIC",
"dataType":"INTEGER"
},{
"name":"ga:pageviews",
"columnType":
"METRIC",
"dataType":"INTEGER"
}
]
v4
"columnHeader": {
"dimensions": [
"ga:source",
"ga:city"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:pageviews",
"type": "INTEGER"
},
{
"name": "ga:sessions",
"type": "INTEGER"
}
]
}
},
Report Rows
The Core Reporting API v3 returns the report data in the
rows
array,
which contains the requested dimensions and metrics.
The Analytics Reporting API v4 returns the report data in a
ReportRow
object,
which contains an array of
dimensions
and an array of
DateRangeValues
objects, each of which contains one or two date ranges, as the following diagram depicts:
Rows
v3
"rows": [
[
"google",
"Philadelphia",
"60",
"5"
],
[
"google",
"Johnstown",
"21",
"1"
],
[
"google",
"Progress",
"7",
"1"
]
],
v4
"rows": [
{
"dimensions": [
"google",
"Philadelphia"
],
"metrics": [
{
"values": [
"60",
"5"
]
}
]
},
{
"dimensions": [
"google",
"Johnstown"
],
"metrics": [
{
"values": [
"21",
"1"
]
}
]
},
{
"dimensions": [
"google",
"Progress"
],
"metrics": [
{
"values": [
"7",
"1"
]
}
]
}
],
Sampled data
If the results are
sampled
the Core Reporting API v3 returns the boolean field
containsSampledData
,
which is set to
true
.
The Analytics Reporting API v4 does not return a boolean if the data is
sampled; rather the API returns the
samplesReadCounts
and the
samplingSpaceSizes
fields.
If the results are not sampled these fields will not be defined.
The following Python example shows how to calculate if a
report
contains sampled data:
def ContainsSampledData(report):
"""Determines if the report contains sampled data.
Args:
report (Report): An Analytics Reporting API v4 response report.
Returns:
bool: True if the report contains sampled data.
"""
report_data = report.get('data', {})
sample_sizes = report_data.get('samplesReadCounts', [])
sample_spaces = report_data.get('samplingSpaceSizes', [])
if sample_sizes and sample_spaces:
return True
else:
return False
Below is an example response which contains sampled data from a request with
two date ranges. The results were calculated from almost
500k samples
of a sampling space size of approximately
15 million sessions
:
{
"reports":
[
{
"columnHeader": {
...
},
"data": {
...
"samplesReadCounts": [ "499630","499630"],
"samplingSpaceSizes": ["15328013","15328013"],
}
}
]
}
Parsing the v4 response
The following sample code parses and prints the Analytics Reporting API v4
response:
Python
def printResponse(self, response):
"""Parses and prints the Analytics Reporting API v4 response"""
for report in response.get('reports', []):
columnHeader = report.get('columnHeader', {})
dimensionHeaders = columnHeader.get('dimensions', [])
metricHeaders = columnHeader.get('metricHeader', {}).get('metricHeaderEntries', [])
rows = report.get('data', {}).get('rows', [])
for row in rows:
dimensions = row.get('dimensions', [])
dateRangeValues = row.get('metrics', [])
for header, dimension in zip(dimensionHeaders, dimensions):
print header + ': ' + dimension
for i, values in enumerate(dateRangeValues):
print 'Date range (' + str(i) + ')'
for metricHeader, value in zip(metricHeaders, values.get('values')):
print metricHeader.get('name') + ': ' + value
Java
public static void printResponse(GetReportsResponse response) {
for (Report report: response.getReports()) {
ColumnHeader header = report.getColumnHeader();
List<String> dimensionHeaders = header.getDimensions();
List<MetricHeaderEntry> metricHeaders = header.getMetricHeader().getMetricHeaderEntries();
List<ReportRow> rows = report.getData().getRows();
for (ReportRow row: rows) {
List<String> dimensions = row.getDimensions();
List<DateRangeValues> metrics = row.getMetrics();
for (int i = 0; i < dimensionHeaders.size() && i < dimensions.size(); i++) {
System.out.println(dimensionHeaders.get(i) + ": " + dimensions.get(i));
}
for (int j = 0; j < metrics.size(); j++) {
System.out.print("Date Range (" + j + "): ");
DateRangeValues values = metrics.get(j);
for (int k = 0; k < values.size() && k < metricHeaders.size(); k++) {
System.out.println(metricHeaders.get(k).getName() + ": " + values.get(k));
}
}
}
}
}
Error handling
Because the
error response
format in v4 is different from that in v3,
update your code to handle v4 error responses.
The following examples compare an error response in v3 and the equivalent error
response in v4:
v3
{
"error": {
"errors": [
{
"domain": "global",
"reason": "insufficientPermissions",
"message": "User does not have sufficient permissions for this profile.",
}
],
"code": 403,
"message": "User does not have sufficient permissions for this profile."
}
}
v4
{
"error": {
"code": 403,
"message": "User does not have sufficient permissions for this profile.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.DebugInfo",
"detail": "[ORIGINAL ERROR] generic::permission_denied: User does not have sufficient permissions for this profile. [google.rpc.error_details_ext] { message: \"User does not have sufficient permissions for this profile.\" }"
}
]
}
}