Creating a custom display for Google's Analytics Embed Library

This post is more than 2 years old.

I've blogged a few times now about Google's Analytics Embed library. I really dig it as it makes working with their Analytics API pretty darn simple. It really opens up the ability to create interesting mashups and custom dashboards on your sites with just plain JavaScript. Recently, a reader asked me a question about how he could have more control over the data displayed by the library.

His question involved formatting of the "TABLE" display supported by the library. This is a format I had not used myself yet so I built up a quick demo (and as the reader supplied some code it made it a bit easier). Let's look at the code and then I'll show the result.

<!DOCTYPE html>
<html>
<head>
  <title>Embed API Demo</title>
</head>
<body>

<!-- Step 1: Create the containing elements. -->

<section id="auth-button"></section>

<h2>RaymondCamden.com</h2>
<section id="timeline"></section>

<!-- Step 2: Load the library. -->

<script>
(function(w,d,s,g,js,fjs){
  g=w.gapi||(w.gapi={});g.analytics={q:[],ready:function(cb){this.q.push(cb)}};
  js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
  js.src='https://apis.google.com/js/platform.js';
  fjs.parentNode.insertBefore(js,fjs);js.onload=function(){g.load('analytics')};
}(window,document,'script'));
</script>

<script>
gapi.analytics.ready(function() {

  // Step 3: Authorize the user.

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

  gapi.analytics.auth.authorize({
    container: 'auth-button',
    clientid: CLIENT_ID,
	userInfoLabel:""
  });

  // Step 5: Create the timeline chart.
  var timeline = new gapi.analytics.googleCharts.DataChart({
    reportType: 'ga',
    query: {
      'dimensions': 'ga:date',
      'metrics': 'ga:sessions,ga:avgSessionDuration',
      'start-date': '30daysAgo',
      'end-date': 'yesterday',
     'ids': "ga:31405"
    },
    chart: {
      type: 'TABLE',
      container: 'timeline'
    }
  });

  gapi.analytics.auth.on('success', function(response) {
  	//hide the auth-button
  	document.querySelector("#auth-button").style.display='none';
  	
    timeline.execute();

  });

});
</script>
</body>
</html>

I'm assuming you are somewhat familiar with my older posts, but if not, the basic idea here is that the Embed library will handle authentication and it provides rendering capabilities. You can see the DataChart call there handling both a query (what data to fetch) and how to render it (a table). Here is the result:

shot1

Nice, but what if you wanted more control over the rendering? Specifically, the user wanted to change the seconds column into a report that showed the minutes instead. Unfortunately, you don't get the ability to modify the format of the table. Fortunately, Google makes it easy to get the data manually and do whatever the heck you want. Let's look at an updated version of the script.

<!DOCTYPE html>
<html>
<head>
	<title>Embed API Demo</title>
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
	<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
	<script src="moment.min.js"></script>
</head>
<body>


<div class="container">
	
	<section id="auth-button"></section>
	
	<h2>RaymondCamden.com</h2>
	<div id="status"></div>
	<table id="dataTable" class="table">
		<thead><tr><th>Date</th><th>Sessions</th><th>Avg. Session Duration</th></tr></thread>
		<tbody></tbody>
	</table>

</div>

<script>
(function(w,d,s,g,js,fjs){
  g=w.gapi||(w.gapi={});g.analytics={q:[],ready:function(cb){this.q.push(cb)}};
  js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
  js.src='https://apis.google.com/js/platform.js';
  fjs.parentNode.insertBefore(js,fjs);js.onload=function(){g.load('analytics')};
}(window,document,'script'));
</script>

<script>
var $tbody;
var $status;
var intl = false;

$(document).ready(function() {
	
	if(window.Intl) intl = true;
	
	$tbody = $("#dataTable tbody");
	$status = $("#status");
	$status.html("<i>Please stand by - loading data...</i>");

	gapi.analytics.ready(function() {
	
	
		var CLIENT_ID = '818125206534-g1r0datdtu9serq2pf9cp5vkuih3h8pv.apps.googleusercontent.com';
		
		gapi.analytics.auth.authorize({
			container: 'auth-button',
			clientid: CLIENT_ID,
			userInfoLabel:""
		});
	
		gapi.analytics.auth.on('success', function(response) {
			//hide the auth-button
			document.querySelector("#auth-button").style.display='none';
			
			gapi.client.analytics.data.ga.get({
				'ids': 'ga:31405',
				'metrics': 'ga:sessions,ga:avgSessionDuration',
				'start-date': '30daysAgo',
				'end-date': 'yesterday',
				'dimensions':'ga:date'
			}).execute(function(results) {
				$status.html("");
				renderData(results.rows);
			});
		
	
		});
	
	});
	
});


function formatDate(str) {
	var year = str.substring(0,4);
	var month = str.substring(4,6);
	var day = str.substring(6,8);
	if(intl) {
		var d = new Date(year,month-1,day); 
		return new Intl.DateTimeFormat().format(d);
	} 
	return month + "/" + day + "/" + year;
}

function formatNumber(str) {
	if(intl) return new Intl.NumberFormat().format(str);
	return str;
}

function formatTime(str) {
	var dur = moment.duration(parseInt(str,10), 'seconds');
	var minutes = dur.minutes();
	var seconds = dur.seconds();
	return minutes + " minutes and " + seconds + " seconds";
}

function renderData(data) {
	var s = "";
	for(var i=0;i<data.length;i++) {
		s += "<tr><td>" + formatDate(data[i][0]) + "</td>";
		s += "<td>" + formatNumber(data[i][1]) + "</td>";
		s += "<td>" + formatTime(data[i][2]) + "</td></tr>";
	}
	$tbody.html(s);
}
</script>
</body>
</html>

The biggest change here is that now I ask for the data so that I can do whatever I want with it. You can see this in the gapi.client.analytics.data.ga.get call. Once I have the data, I'm free to format it as I want. I decided to get a bit fancy.

First, I made use of Intl to format the dates and numbers nicely. This is a cool web standard (see my article here - Working with Intl) that is incredibly easy to use. It doesn't work on iOS yet, but luckily you can do 'snap to' with CSS in iOS which is far more important than internationalization.

To handle the minute display, I made use of the awesome MomentJS library. It has a duration API that makes showing the parts of a span of time very easy. I'm not terribly happy with how I showed it - but obviously you could modify this to your needs. Here is the result.

shot2

There ya go. Hopefully this helps. I'd share an online version but it is currently tied to my web property so it wouldn't work for you. To be clear, you can easily change the property, or add support for letting the user select their property.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Šime Vidas posted on 9/18/2015 at 6:28 AM

Can this API be used (in client-side JS) to show your website’s stats to all your visitors, or would one have to do that on the server (assuming the site has a Node backend)?

Comment 2 (In reply to #1) by Raymond Camden posted on 9/18/2015 at 10:50 AM

No, it is 100% tied to you logging in. For what you want you would need to use the "old" API and do it server side, which isn't terribly hard either, just not as slick as this. ;)

Comment 3 by Rick Durand posted on 10/2/2015 at 12:49 AM

Mr. Camden, thank you for sharing these great examples. I was wondering if it would be possible to learn how to render percentages (%) and cost per conversion ($) as well. At the moment, percentages and dollar figures are not rounded. Is there a better way to illustrate these figures?

Comment 4 (In reply to #3) by Raymond Camden posted on 10/2/2015 at 12:58 AM

If you can build a demo like I did, I can work on fixing it.

Comment 5 (In reply to #4) by Rick Durand posted on 10/2/2015 at 1:39 AM

Excellent, thank you. Would it be possible to email you the demo links? The demo domain origin is private, unfortunately. I could also post the code somewhere, if that would be better. Thank you again for your time.

Comment 6 (In reply to #5) by Raymond Camden posted on 10/2/2015 at 1:41 AM

If you could add me to the account it would be quicker as I could use your IDs. If you can't, just post the code online and change the IDs to an empty value I can modify myself.

Comment 7 (In reply to #6) by Rick Durand posted on 10/2/2015 at 2:17 AM

Thank you, Mr. Camden. I've posted the information here: http://lawnetic.com/dashboa...

Please pardon the mess, I'm not very code savvy :-)

Comment 8 (In reply to #7) by Raymond Camden posted on 10/2/2015 at 1:45 PM

See this JSBin:

http://jsbin.com/savone/edi...

The first new function renders the percentage, the second does the currency. Note you have to specify a locale/currency type, which makes sense as you can't just change "1" from USD to Euros as they aren't the same.

Comment 9 (In reply to #8) by Rick Durand posted on 10/2/2015 at 10:28 PM

Great!!! I'll give it a try, thank you.

Comment 10 by Héctor León posted on 10/20/2015 at 1:44 PM

Hi Raymond, awesome examples, thanks so much you got me nearest to fix my problem.
I want to hide the Account selector (because i don't want to let user change the views to other sites)
but what if the user still have not permissions to see the site data ? right now Analytics auto-assign him, his first active account and display the chart. That sucks, i mean, would be better a message/alert like this "You have no permission to see the charts of this site, talk with the owner" or something like that.

PD: I speak english very bad, hope you can understand me :), again thanks for the post really helpful

Comment 11 (In reply to #10) by Raymond Camden posted on 10/20/2015 at 3:06 PM

It would definitely be possible to handle this type of error (current user can't see site X), but I don't have code prepared to demonstrate that now. Sorry.

Comment 12 (In reply to #11) by Héctor León posted on 10/21/2015 at 7:32 AM

don't worry, thanks anyway, but you know where can i find a solution ?

I am reading the Embed Api and this link https://developers.google.c...

but still nothing :(

Comment 13 (In reply to #12) by Raymond Camden posted on 10/21/2015 at 10:58 AM

I believe they use a Google Group for support?

Comment 14 by Akash Pal posted on 5/18/2016 at 1:28 PM

is there a way to get the google analytics data using Core Reporting API? I cant make out how to obtain the data. Without using a server.

Comment 15 (In reply to #14) by Raymond Camden posted on 5/18/2016 at 2:16 PM

I'm not quite sure I understand you. This example *is* getting data.

Comment 16 (In reply to #15) by Akash Pal posted on 5/18/2016 at 5:23 PM

Actually i want to get the data directly from google analytics by making a request. So that i can use that data to render graphs within a mobile application.
I was able to do the same with embed api however the google requires me to specify a localhost or a url only then i can obtain the data.

So is it possible to obtain the data directly from google analytics by making an api call?

Comment 17 (In reply to #16) by Raymond Camden posted on 5/18/2016 at 5:24 PM

Yes- they support a REST API. I haven't used it in a while, but it is doable.

Comment 18 (In reply to #17) by Akash Pal posted on 5/18/2016 at 5:28 PM

I am actually concerned about how the authentication would be handled. I was looking at the query parameters which enables me to get various type of data but how do I make a request so that i get the data back in some format.

Comment 19 (In reply to #18) by Raymond Camden posted on 5/18/2016 at 7:00 PM

Please see the APIs as it discusses how to authenticate. Start here: https://developers.google.c...

Comment 20 by Jonathan Vasiliou posted on 5/26/2017 at 5:14 PM

Raymond if I show you some code could you help me with problem I am having. I mean I can explain it but, don't want to lose you in the process lol.

Comment 21 (In reply to #20) by Raymond Camden posted on 5/26/2017 at 5:49 PM

Sorry, but typically that type of work is a paid engagement and I'm completely booked up right now.

Comment 22 by Miki Rait posted on 10/8/2017 at 9:29 AM

how change language for months in reports ?

Comment 23 (In reply to #22) by Raymond Camden posted on 10/8/2017 at 11:20 AM

I'm using the Intl standard which your browser may not support. If so - you can switch to a library. Moment.js has this support.