Now we are able to interact with the Google Analytics API.

We’ll generate the stats we’ll later use to create the User Interface.

To start with, we are interested in the following data:

  • Get today’s visits. Organic / total
  • Get yesterday’s visits. Organic / total
  • Get last 30 days visits. Organic / total

Get daily visits

To get data from the Google API, we use the Google Analytics Reporting API v4, offered by the googleapis library via the analyticsreporting object.

We initialize it using

const analyticsreporting = google.analyticsreporting({
	version: 'v4',
	auth: jwt
})

where jwt is the JSON Web Token we defined previously.

Then we call it, using

const res = await analyticsreporting.reports.batchGet({
  requestBody: {
    reportRequests: [{
      viewId: VIEW_ID_HERE,
      dateRanges: [{
        startDate: START_DATE_HERE,
        endDate: END_DATE_HERE
      }],
      metrics: [{
        expression: 'ga:sessions'
      }]
    }]
  }
})

This syntax is specific to the Google API, and I got it from the examples provided in its documentation.

VIEW_ID_HERE is a placeholder for the view ID. Every time we call this API we must pass a view id, which is what we got in the id property of the sites list in the previous lesson.

START_DATE_HERE and END_DATE_HERE are placeholders for a date object, which must be specified in the form YYYY-MM-DD or using special names like today or yesterday, which the Google API understands.

The res value contains the result, and we’ll need to dig a bit to get the value we are looking for:

return res.data.reports[0].data.totals[0].values[0]

You can freely explore the other properties of res if you want to take a look.

We can fill those by packaging this code in a function:

async function getDailyData(viewId, startDate, endDate) {
  const analyticsreporting = google.analyticsreporting({
    version: 'v4',
    auth: jwt
  })

  const res = await analyticsreporting.reports.batchGet({
    requestBody: {
      reportRequests: [{
        viewId: viewId,
        dateRanges: [{
          startDate: startDate,
          endDate: endDate
        }],
        metrics: [{
          expression: 'ga:sessions'
        }]
      }]
    }
  })
  return res.data.reports[0].data.totals[0].values[0]
}

which we can call using

async function getData() {
  console.log(await getDailyDataV4('102158511', 'today', 'today'))
}

getData()

Now let’s add one more parameter, which we initialize to false if not set, called isOrganic. If set to true, we’ll tell Google to send us only the organic results:

async function getDailyData(viewId, startDate, endDate, organic = false) {
  const analyticsreporting = google.analyticsreporting({
    version: 'v4',
    auth: jwt
  })

  let filter = ''
  if (organic) {
    filter = 'ga:medium==organic'
  }

  const res = await analyticsreporting.reports.batchGet({
    requestBody: {
      reportRequests: [{
        viewId: viewId,
        dateRanges: [{
          startDate: startDate,
          endDate: endDate
        }],
        metrics: [{
          expression: 'ga:sessions'
        }],
        filtersExpression: filter
      }]
    }
  })
  return res.data.reports[0].data.totals[0].values[0]
}

So with this code we can now get today’s and yesterday’s visits for a single view id, filtered by organic, or total:

async function getData() {
	const viewId = '102158511'
  const data = {
		today: {
			total: await getDailyData(viewId, 'today', 'today'),
			organic: await getDailyData(viewId, 'today', 'today', true),
    },
		yesterday: {
			total: await getDailyData(viewId, 'yesterday', 'yesterday'),
			organic: await getDailyData(viewId, 'yesterday', 'yesterday', true),
    },
  }

  console.log(data)
}

Let’s transform this code to get the data of all the sites we enabled. In getData(), we get the id of each property:

const list = await getPropertiesList()

I create a function getDataOfItem() to get the data of a single site:

const getDataOfItem = async item => {
  return {
    property: item,
    today: {
      total: (await getDailyData(item.id, 'today', 'today')),
      organic: await getDailyData(item.id, 'today', 'today', true),
    },
    yesterday: {
      total: await getDailyData(item.id, 'yesterday', 'yesterday'),
      organic: await getDailyData(item.id, 'yesterday', 'yesterday', true),
    }
  }
}

We iterate on the properties list using map(), and we call this function for each site:

const result = await Promise.all(list.map(item => getDataOfItem(item)))

In this way, we end up with an array that has an entry for each site, and for each site we have all the stats for today and yesterday.

You might wonder why we prepend await and put the mapping inside Promise.all() .

This is because getDataOfItem() is an async function, and as such it returns a promise. Every function returns a promise, so until we can get the result, every promise must resolve, and this is done using Promise.all().

Then we await the result of Promise.all(), since itself returns a promise.

If this is all highly confusing, please give a read to https://flaviocopes.com/javascript-promises/.

Here’s the full code:

async function getData() {
  const list = await getPropertiesList()

  const getDataOfItem = async item => {
    return {
      property: item,
      today: {
        total: (await getDailyData(item.id, 'today', 'today')),
        organic: await getDailyData(item.id, 'today', 'today', true),
      },
      yesterday: {
        total: await getDailyData(item.id, 'yesterday', 'yesterday'),
        organic: await getDailyData(item.id, 'yesterday', 'yesterday', true),
      }
    }
  }

  const result = await Promise.all(list.map(item => getDataOfItem(item)))
	console.log(result)
}

When we run this program in the console we’ll get an object representation similar to

[ { property: { name: 'flaviocopes.com', id: '102158511' },
    today: { total: '1409', organic: '1069' },
    yesterday: { total: '3429', organic: '2365' } },
  { property: { name: 'nodehandbook.com', id: '180512092' },
    today: { total: '13', organic: '0' },
    yesterday: { total: '51', organic: '2' } } ]

The complete code of this project at this point is available at https://glitch.com/edit/#!/node-course-project-analytics-dashboard-b?path=server.js:49:2


Go to the next lesson