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
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
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
orDESCENDING
) through thesortOrder
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",
}]
}
Pagination
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.\" }"
}
]
}
}