Over a million developers have joined DZone.

Using the Google Analytics Embed API to Build a Dashboard

· Performance Zone

Download Forrester’s “Vendor Landscape, Application Performance Management” report that examines the evolving role of APM as a key driver of customer satisfaction and business success, brought to you in partnership with BMC.

About a year and a half ago I created a demo (Proof of Concept – Dashboard for Google Analytics) of a Google Analytics Dashboard. This demo was entirely client-side based and made use of the API libraries Google created. For the most part, the process was fairly simple. After I figured out how to authenticate the user and query the data, I spent more time making it look pretty than actually working with the API, which is a good thing. More recently I discovered the new Analytics Embed API. The cool thing about the Embed API is that it greatly simplifies the authentication/authorization aspect of getting analytics data and even provides built in charting capabilities. I blogged an example (Quick example of the Google Analytics Embed API) and I thought it might be fun to revisit my dashboard concept using this simpler API.

Before I show the code behind this demo, let me share a screen shot so you can see it in action. I switched to a new charting library for this demo (ChartJS) mainly because Google used it themselves in one of their demos. I didn’t spend much time making this pretty – I was going for ‘quick impact’ in terms of visuals. Obviously though it could be better.


Each chart represents one of my properties. Each line represents page views per days, with the darker blue being the most recent page seven days and the lighter gray being the seven days before that.

The code is made up of several parts. The authentication, as I said, is handled almost entirely by the embed API.

gapi.analytics.ready(function() {

  var CLIENT_ID = '818125206534-g1r0datdtu9serq2pf9cp5vkuih3h8pv.apps.googleusercontent.com';

    container: 'auth-button',
    clientid: CLIENT_ID,

  gapi.analytics.auth.on('success', function(response) {
    //hide the auth-button
    console.log("get profiles");
    getProfiles(function(profs) {
      window.profiles = profs;


  Chart.defaults.global.animationSteps = 60;
  Chart.defaults.global.animationEasing = 'easeInOutQuart';
  Chart.defaults.global.responsive = true;
  Chart.defaults.global.maintainAspectRatio = false;


In order to get profiles for my account, I make use of a management API. getProfiles handles fetching, and caching, this result. (I use caching as I had planned, still plan on, adding a few additional filtering options to the report.)

function getProfiles(cb) {
  //do we have a cached version?
  if(sessionStorage["gaProfiles"]) {
    console.log("profiles fetched from cache");

  gapi.client.analytics.management.accounts.list().then(function(res) { 
    var accountId = res.result.items[0].id;
    var profiles = [];
    gapi.client.analytics.management.webproperties.list({'accountId': accountId}).then(function(res) {

    res.result.items.forEach(function(item) {
    if(item.defaultProfileId) profiles.push({id:"ga:"+item.defaultProfileId,name:item.name});
      sessionStorage["gaProfiles"] = JSON.stringify(profiles);    

Note that I do not make use of promises in this block and that’s a mistake. I make use of it a bit later in another function so I need (well, I want) to be consistent. Now for the fun part. For all of my properties, I need to fetch data for each site. I was able to rip code from one of Google’s demos but I quickly ran into rate limit issues. To get around this, I single thread the calls and add a slight delay.

//Credit: https://ga-dev-tools.appspot.com/embed-api/third-party-visualizations/
function query(params) {
  return new Promise(function(resolve, reject) {
    var data = new gapi.analytics.report.Data({query: params});
    data.once('success', function(response) { resolve(response); })
        .once('error', function(response) { reject(response); })

function makeCanvas(id) {
  var container = document.getElementById(id);
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');

  container.innerHTML = '';
  canvas.width = container.offsetWidth;
  canvas.height = container.offsetHeight;

  return ctx;

function processProfiles() {
  console.log("working on profile "+profiles[curProfile].name);

  var now = moment();
  var id = profiles[curProfile].id;

  var thisWeek = query({
    'ids': id,
    'dimensions': 'ga:date,ga:nthDay',
    'metrics': 'ga:pageviews',
    'start-date': moment(now).subtract(8, 'day').format('YYYY-MM-DD'),
    'end-date': moment(now).subtract(1,'day').format('YYYY-MM-DD')

  var lastWeek = query({
    'ids': id,
    'dimensions': 'ga:date,ga:nthDay',
    'metrics': 'ga:pageviews',
    'start-date': moment(now).subtract(15, 'day').subtract(1, 'week')
    'end-date': moment(now).subtract(8, 'day').subtract(1, 'week')

  Promise.all([thisWeek, lastWeek]).then(function(results) {

    var data1 = results[0].rows.map(function(row) { return +row[2]; });
    var data2 = results[1].rows.map(function(row) { return +row[2]; });
    var labels = results[1].rows.map(function(row) { return +row[0]; });

    var totalThisWeek = results[0].totalsForAllResults["ga:pageviews"];
    var totalLastWeek = results[1].totalsForAllResults["ga:pageviews"];
    var percChange = (((totalThisWeek - totalLastWeek) / totalLastWeek) * 100).toFixed(2);
    console.log(totalLastWeek, totalThisWeek, percChange);

    labels = labels.map(function(label) {
      return moment(label, 'YYYYMMDD').format('ddd');

    var data = {
      labels : labels,
      datasets : [
          label: 'Last Week',
          fillColor : 'rgba(220,220,220,0.5)',
          strokeColor : 'rgba(220,220,220,1)',
          pointColor : 'rgba(220,220,220,1)',
          pointStrokeColor : '#fff',
          data : data2
          label: 'This Week',
          fillColor : 'rgba(151,187,205,0.5)',
          strokeColor : 'rgba(151,187,205,1)',
          pointColor : 'rgba(151,187,205,1)',
          pointStrokeColor : '#fff',
          data : data1

    var titleStr = profiles[curProfile].name + " ";
    if(totalLastWeek > 0 && totalThisWeek > 0) {
      if(percChange < 0) {
        titleStr += "<span class='down'>(Down "+Math.abs(percChange) + "%)</span>";
      } else {
        titleStr += "<span class='up'>(Up "+percChange + "%)</span>";      

  $("body").append("<div class='reportContainer'><div class='chartTitleContainer'>"+titleStr+"</div><div class='chartContainer' id='chart-"+curProfile+"-container'></div></div>");

    new Chart(makeCanvas('chart-'+curProfile+'-container')).Line(data);

    if(curProfile+1 < profiles.length) {
      //settimeout to try to avoid GA rate limits

And that’s basically it. As I said, I’d like to add a few options to this. Specifically, the ability to compare the current and past 30 days as well as this year versus the past. I’d also like the ability to dismiss/hide some sites I don’t care about. I could use LocalStorage to remember those properties and hide them automatically.

Want to see the complete code and test it yourself? Check out the online demo here: http://static.raymondcamden.com/ga_embed/test10.html

See Forrester’s Report, “Vendor Landscape, Application Performance Management” to identify the right vendor to help IT deliver better service at a lower cost, brought to you in partnership with BMC.

performance,google analytics reporting suite,api

Published at DZone with permission of Raymond Camden, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}