Interact with the Google Analytics API using Node.js
Learn how to interface a Node.js application with the Google Analytics API, using the official `googleapis` package. We'll use a JSON Web Token and see some examples
Note: uBlock Origin blocks the images on this post, because they have the
analyticsword in the path. So make sure you disable it for this page, to see the images 🖼
In this post I’m going to show some examples of using the Google Analytics API with Node.js.
- Environment variables
- Add the user to Google Analytics
- Import the Google library
- Define the scope
- The Google Analytics Reporting API
- Create the JWT
- Perform a request
- Metrics
- Common code
- Get the number of today sessions
- Get the number of today sessions coming from organic sources (Search Engines)
- Get the number of yesterday sessions
- Get the number of sessions in the last 30 days
- Get the browsers used in the last 30 days
- Get the number of visitors using Chrome
- Get the sessions by traffic source
- The Google Analytics Real Time API
Google offers a great npm package: googleapis. We’re going to use that as the base building block of our API interaction.
Authentication is a big part of interacting with an API. Check out this post on how to authenticate to the Google APIs. In this article I’m going to assume you read that, and you know how to perform a JWT authentication.
Environment variables
Once you download the JSON Key file from Google, put the client_email and private_key values as environment variables, so that they will be accessible through
process.env.CLIENT_EMAILprocess.env.PRIVATE_KEY
Add the user to Google Analytics
Since we’re using the Service to Service API in these examples, you need to add the client_email value to your Google Analytics profile. Go to the Admin panel and click User Management, either on a property or on a view.

And add the email you found in the client_email key in the JSON file:

Import the Google library
const { google } = require('googleapis')
Remember the {} around the google object, as we need to destructure it from the googleapis library (otherwise we’d need to call google.google and it’s ugly)
Define the scope
This line sets the scope:
const scopes = 'https://www.googleapis.com/auth/analytics.readonly'
Google Analytics API defines several scopes:
https://www.googleapis.com/auth/analytics.readonlyto view the datahttps://www.googleapis.com/auth/analyticsto view and manage the datahttps://www.googleapis.com/auth/analytics.editto edit the management entitieshttps://www.googleapis.com/auth/analytics.manage.usersto manage the account users and permissionshttps://www.googleapis.com/auth/analytics.manage.users.readonlyto view the users and their permissionshttps://www.googleapis.com/auth/analytics.provisionto create new Google Analytics accounts
You should always pick the scope that grants the least amount of power.
Since we want to only view the reports now, we pick https://www.googleapis.com/auth/analytics.readonly instead of https://www.googleapis.com/auth/analytics.
The Google Analytics Reporting API
Note: you can also use the Google Analytics Reporting API to access those permissions.
It is a trimmed-down version of the Google Analytics API, offering just the scope https://www.googleapis.com/auth/analytics.readonly and https://www.googleapis.com/auth/analytics.
The API is slightly different than the Analytics API however in how it’s used and in which methods it exposes, so we’ll skip that.
Create the JWT
const jwt = new google.auth.JWT(process.env.CLIENT_EMAIL, null, process.env.PRIVATE_KEY, scopes)
Perform a request
Check this code:
const { google } = require('googleapis')
const scopes = 'https://www.googleapis.com/auth/analytics.readonly'
const jwt = new google.auth.JWT(process.env.CLIENT_EMAIL, null, process.env.PRIVATE_KEY, scopes)
const view_id = 'XXXXX'
async function getData() {
const response = await jwt.authorize()
const result = await google.analytics('v3').data.ga.get({
'auth': jwt,
'ids': 'ga:' + view_id,
'start-date': '30daysAgo',
'end-date': 'today',
'metrics': 'ga:pageviews'
})
console.dir(result)
}
getData()
It performs a request to the Google Analytics API to fetch the pageviews number in the last 30 days.
view_id contains the ID of the view. Not your Google Analytics code, but the view ID. You can get that from the admin panel, by clicking View Settings on the view you want to access:

You pass this object to the request:
{
'auth': jwt,
'ids': 'ga:' + view_id,
'start-date': '30daysAgo',
'end-date': 'today',
'metrics': 'ga:pageviews'
}
In addition to the jwt object and the view id, we have 3 parameters.
metrics: tells the API what we want to getstart-date: defines the starting date for the reportend-date: defines the end date for the report
This request is very simple and returns the number of pageviews occurring in the specified time period.
The returned result will be something like:
{
status: 200,
statusText: 'OK',
headers: {...},
config: {...},
request: {...},
data: {
kind: 'analytics#gaData',
id: 'https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXXXXXXXXXXXXXXXX&metrics=ga:pageviews&start-date=30daysAgo&end-date=today',
query: {
'start-date': '30daysAgo',
'end-date': 'today',
ids: 'ga:XXXXXXXXXXXXXXXXXX',
metrics: [ 'ga:pageviews' ],
'start-index': 1,
'max-results': 1000
},
itemsPerPage: 1000,
totalResults: 1,
selfLink: 'https://www.googleapis.com/analytics/v3/data/ga?ids=ga:XXXXXXXXXXXXXXXXXX&metrics=ga:pageviews&start-date=30daysAgo&end-date=today',
profileInfo: {
profileId: 'XXXXXXXXXXXXXXXXXX',
accountId: 'XXXXXXXXXXXXXXXXXX',
webPropertyId: 'UA-XXXXXXXXXXX--XX',
internalWebPropertyId: 'XXXXXXXXXXXXXXXXXX',
profileName: 'XXXXXXXXXXXXXXXXXX',
tableId: 'ga:XXXXXXXXXXXXXXXXXX'
},
containsSampledData: false,
columnHeaders: [
{
name: 'ga:pageviews',
columnType: 'METRIC',
dataType: 'INTEGER'
}
],
totalsForAllResults: { 'ga:pageviews': '3000' },
rows: [ [ '114426' ] ] }
}
With this You can access the pageviews count in response.data.rows[0][0].
Metrics
This example was simple. We just asked for this data:
{
'start-date': '30daysAgo',
'end-date': 'today',
'metrics': 'ga:pageviews'
}
There is a whole lot of data we can use.
The Dimensions & Metrics Explorer is an awesome tool to discover all the options.
Those terms are two concepts of Google Analytics.
Dimensions are attributes, like City, Country or Page, the referral path or the session duration.
Metrics are quantitative measurements, like the number of users or the number of sessions.
Some examples of metrics:
- get the pageviews
ga:pageviews - get the unique users
ga:users - get the sessions
ga:sessions - get the organic searches
ga:organicSearches
Let’s build some examples with those metrics.
Common code
Here is the common code used in the examples below. Put the snippet in the authorize() callback.
'use strict'
const { google } = require('googleapis')
const scopes = 'https://www.googleapis.com/auth/analytics.readonly'
const jwt = new google.auth.JWT(process.env.CLIENT_EMAIL, null, process.env.PRIVATE_KEY, scopes)
async function getData() {
const defaults = {
'auth': jwt,
'ids': 'ga:' + process.env.VIEW_ID,
}
const response = await jwt.authorize()
/* custom code goes here, using `response` */
}
getData()
The defaults object will be reused in the examples using the spread operator, which is a handy way of handling defaults values in JavaScript.
Get the number of today sessions
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': 'today',
'end-date': 'today',
'metrics': 'ga:sessions'
})
console.dir(result.data.rows[0][0])
Get the number of today sessions coming from organic sources (Search Engines)
Add the filters property:
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': 'today',
'end-date': 'today',
'metrics': 'ga:sessions',
'filters': 'ga:medium==organic',
})
Get the number of yesterday sessions
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': 'yesterday',
'end-date': 'yesterday',
'metrics': 'ga:sessions'
})
console.dir(result.data.rows[0][0])
Get the number of sessions in the last 30 days
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': '30daysAgo',
'end-date': 'today',
'metrics': 'ga:sessions'
})
console.dir(result.data.rows[0][0])
Get the browsers used in the last 30 days
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': '30daysAgo',
'end-date': 'today',
'dimensions': 'ga:browser',
'metrics': 'ga:sessions'
})
console.dir(result.data.rows.sort((a, b) => b[1] - a[1]))
[
[ 'Chrome', '994' ],
[ 'Safari', '548' ],
[ 'Firefox', '442' ],
[ 'Android Webview', '113' ],
[ 'Opera', '56' ],
[ 'Safari (in-app)', '41' ],
[ 'Edge', '36' ],
[ 'Internet Explorer', '4' ]
]
Get the number of visitors using Chrome
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': '30daysAgo',
'end-date': 'today',
'dimensions': 'ga:browser',
'metrics': 'ga:sessions',
'filters': 'ga:browser==Chrome',
})
console.dir(result.data.rows[0][1])
Get the sessions by traffic source
const result = await google.analytics('v3').data.ga.get({
...defaults,
'start-date': '30daysAgo',
'end-date': 'today',
'dimensions': 'ga:source',
'metrics': 'ga:sessions'
})
console.dir(result.data.rows.sort((a, b) => b[1] - a[1]))
[
[ 'google', '1343' ],
[ '(direct)', '731' ],
[ 'medium.com', '624' ],
[ 't.co', '987' ],
[ 'reddit.com', '65' ]
]
The Google Analytics Real Time API
The Google Analytics Real Time API is [May 2018] in private beta, and it’s not publicly accessible. Check this page.
download all my books for free
- javascript handbook
- typescript handbook
- css handbook
- node.js handbook
- astro handbook
- html handbook
- next.js pages router handbook
- alpine.js handbook
- htmx handbook
- react handbook
- sql handbook
- git cheat sheet
- laravel handbook
- express handbook
- swift handbook
- go handbook
- php handbook
- python handbook
- cli handbook
- c handbook
subscribe to my newsletter to get them
Terms: by subscribing to the newsletter you agree the following terms and conditions and privacy policy. The aim of the newsletter is to keep you up to date about new tutorials, new book releases or courses organized by Flavio. If you wish to unsubscribe from the newsletter, you can click the unsubscribe link that's present at the bottom of each email, anytime. I will not communicate/spread/publish or otherwise give away your address. Your email address is the only personal information collected, and it's only collected for the primary purpose of keeping you informed through the newsletter. It's stored in a secure server based in the EU. You can contact Flavio by emailing flavio@flaviocopes.com. These terms and conditions are governed by the laws in force in Italy and you unconditionally submit to the jurisdiction of the courts of Italy.