Skip to content

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 analytics word 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.

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

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.

Google Analytics Settings

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

Add a new user

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:

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:

The view id

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.

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:

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.


→ Here's my latest YouTube video

→ Get my Node.js Handbook

→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter

JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025

Bootcamp 2025

Join the waiting list