IMG-LOGO

Google Analytics API Tutorial using JavaScript

andy - 18 Oct, 2017 16450 Views 27 Comment

In this tutorial, you will learn how to access Google Analytics API using javascript. We will use Oauth2 to access user account analytics and a combination of Google Analytics version 3 to get the list of account summaries and version 4 to query the analytics accounts such as a number of visitors, sessions, bounce rates etc.

To start with, we need to go to the following url to get the Oauth Client ID for our project.

https://console.developers.google.com

If you do not have a Google Account, you will need to register it first. Once registered you can go to above link and create a new project. You can name it, for example, Web Analytics. Once the project has been created, you will need to enable Google Analytics Reporting and Analytics API. If you go to Dashboard menu, there should be an option for you to enable APIs. Simply perform a search and type in Analytics.

Once those have been enabled, you can now create a credential. Go to the Credentials menu and select the OAuth Client ID type.

It will pop up a selection of application type for you to choose. In this example, we are going to select Web Application. If you have not set the consent screen, simply click the Configure consent screen to proceed further. Just make sure in the product name you do not include any keyword Google as it will violate the Google's terms.

Once this has been set up, you should be able to select your application type. In the Authorized Javascript Origins, make sure you type in the correct URL path. In this example, as I am showing the example on my site, so I entered https://bytutorial.com. If you test in your local computer, usually it will be http://localhost. Then click the Create button.

You should see the created Oauth 2 Client ID like below.

Let starts with the codes now. I have divided the tutorial into 3 files. They are:

  • google-analytics-api-tutorial.html
  • google-analytics.js
  • style.css

Here is the full code of the html page.

<!DOCTYPE html>
<html>
<head>
<title>Google Analytics API Tutorial< using Javascript</title>
 <meta name="description" content="Learn how to query Google Analytics API using Javascript - ByTutorial.com">
<link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="transparent-wrapper">
	<div id="wait-box">
		<div><img src="images/loading-bubble.gif"/></div>
		<div>Please wait....</div>
	</div>
	
</div>
<div id="login-box" class="hidden">
	<p>Please login on your google account.</p>
	<button id="btnLogin" onclick="byTutorialAnalytics.handleAuthClick()" class="button">Login</button>
</div>

<div id="account-panel" class="hidden">
	<h1>Google Analytics Panel</h1>
	<table class="tbl" cellpadding="0" cellspacing="0">
		<tr>
			<td>Site: </td>
			<td><select id="cboAccount"></select></td>
		</tr>
		<tr>
			<td>Period: </td>
			<td><select id="cboPeriod">
					<option value="today">Today</option>
					<option value="yesterday">Yesterday</option>
					<option value="7daysago">Last Week</option>
					<option value="14daysago">Last Two Weeks</option>
					<option value="28daysago"">Last Four Weeks</option>
				</select>
			</td>
		</tr>
		<tr>
			<td>Data Type: </td>
			<td>
				<div><input type="checkbox" data-id="ga:users" class="chk-data" checked="true"/> ga:users</div>
				<div><input type="checkbox" data-id="ga:newUsers" class="chk-data" checked="true"/> ga:newUsers</div>
				<div><input type="checkbox" data-id="ga:hits" class="chk-data" checked="true"/> ga:hits</div>
				<div><input type="checkbox" data-id="ga:sessions" class="chk-data" checked="true"/> ga:sessions</div>
				<div><input type="checkbox" data-id="ga:visits" class="chk-data" checked="true"/> ga:visits</div>
				<div><input type="checkbox" data-id="ga:bounces" class="chk-data" checked="true"/> ga:bounces</div>
			</td>
		</tr>
		<tr>
			<td></td>
			<td><button id="btnQuery" onclick="byTutorialAnalytics.queryAnalytics()" class="button">Query</button> <button id="btnReset" onclick="byTutorialAnalytics.reset()" class="button">Reset</button> <button id="btnLogout" onclick="byTutorialAnalytics.handleSignoutClick()" class="button">Log off</button></td>
		</tr>
		<tr>
			<td></td>
			<td></td>
		</tr>
	</table>
	
	<div id="result" class="hidden">
		<h2>Query Result</h2>
		<div id="query-result" class="result-box"></div>
		
		<h2>JSON Result</h2>
		<div id="json-result" class="result-box"></div>
	</div>
	
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="google-analytics.js"></script>
<script async defer src="https://apis.google.com/js/api.js" 
      onload="this.onload=function(){};byTutorialAnalytics.handleClientLoad()" 
      onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body>
</html>

If you see above HTML code, you will notice at the end of the last script which points to https://apis.google.com, you will notice it will call a function called handleClientLoad. This function will load the Google API library and check if the user has already given an access permission. If it has not then, it will display a login box otherwise it will display the analytics panel like below.

I have added a list of data types available such as ga:users, ga:newUsers, ga:hits, etc. For more information about the list of metric expression available, you can check on the following link.

https://developers.google.com/analytics/devguides/reporting/core/dimsmets

In addition, I have included a filter parameter for report periods such as today, yesterday, last week etc. You can find more information about start date and end date filter in the following link.

https://developers.google.com/analytics/devguides/reporting/core/v3/reference

Here is the javascript code. I have included some comments and hopefully it is clear enough and feel free to post a comment if you have any question.

/******************** GLOBAL VARIABLES ********************/
var SCOPES = ['https://www.googleapis.com/auth/analytics.readonly'];
var CLIENT_ID = 'REPLACE_WITH_YOUR_CLIENT_ID.apps.googleusercontent.com';
var API_KEY = '';

var byTutorialAnalytics = {
	
	/******************** AUTHENTICATION ********************/
	handleClientLoad: function() {
		// Load the API client and auth2 library
		gapi.load('client:auth2', byTutorialAnalytics.initClient);
	},

	//authorize apps
	initClient: function() {
		gapi.client.init({
			//apiKey: API_KEY, //THIS IS OPTIONAL AND WE DONT ACTUALLY NEED THIS, BUT I INCLUDE THIS AS EXAMPLE
			clientId: CLIENT_ID,
			scope: SCOPES.join(' ')
		}).then(function () {
		  // Listen for sign-in state changes.
		  gapi.auth2.getAuthInstance().isSignedIn.listen(byTutorialAnalytics.updateSigninStatus);
		  // Handle the initial sign-in state.
		  byTutorialAnalytics.updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
		});
	},

	//check the return authentication of the login is successful, we display the account panel box and hide the login box.
	updateSigninStatus: function(isSignedIn) {
		if (isSignedIn) {
			$("#login-box").hide();
			$("#account-panel").removeClass("hidden").show();
			byTutorialAnalytics.queryAccounts();
		} else {
			$("#login-box").removeClass("hidden").show();
		}
	},

	handleAuthClick: function(event) {
		gapi.auth2.getAuthInstance().signIn();
	},

	handleSignoutClick: function(event) {
		if(confirm("Are you sure you want to logout?")){
			gapi.auth2.getAuthInstance().signOut();
			$("#account-panel, #result").hide();
			$(".result-box").html("");
		}
	},
	/******************** END AUTHENTICATION ********************/
	
	//function to query google analytics account
	queryAccounts: function () {
		byTutorialAnalytics.showLoading();
		// Load the Google Analytics client library.
		gapi.client.load('analytics', 'v3').then(function() {
			// Get a list of all Google Analytics accounts for this user
			var request = gapi.client.analytics.management.accountSummaries.list();
			request.execute(byTutorialAnalytics.handleAccountSummaryResponse);
		});
	},
	
	//handle the response of account summary
	handleAccountSummaryResponse: function (response) {
	  if (response && !response.error) {
		if (response.items) {
		  byTutorialAnalytics.buildAccountSummariesCombo(response.items);
		}
	  } else {
		console.log('There was an error: ' + response.message);
		byTutorialAnalytics.hideLoading();
	  }
	},
	
	//build the account summaries combo box
	buildAccountSummariesCombo: function(accounts) {
	  for (var i = 0, account; account = accounts[i]; i++) {
		if(account.webProperties.length > 0 && account.webProperties[0].profiles.length > 0){
			$("#cboAccount").append("<option value='" + account.webProperties[0].profiles[0].id + "'>" + account.name + "</option>");
		}
	  }
	  $("#account-panel").removeClass("hidden").show();
	  byTutorialAnalytics.hideLoading()
	},
	
	//function to query google analytics data 
	queryAnalytics: function () {
		var id = $("#cboAccount").val();
		var expressions = [];
		
		//we loop through the checkbox and append it to expression array
		$(".chk-data").each(function(item,index){
			if($(this).is(":checked")){
				var expressionData = {
					expression: $(this).attr("data-id")
				}
				expressions.push(expressionData);
			}
		});
		
		//get the report query by passing the period time and expression daa.
		byTutorialAnalytics.showLoading();
		//if it is yesterday comparison, we have to set end date to yesterday otherwise it will combine today and yesteray
		var toDate = $("#cboPeriod").val() != "yesterday" ? "today" : "yesterday";
		
		byTutorialAnalytics.getReportQuery(id, $("#cboPeriod").val(), toDate, expressions).then(function(response){
			var formattedJson = JSON.stringify(response.result, null, 2);
			$('#json-result').html(formattedJson);
			$("#result").removeClass("hidden").show();
			
			//show result in table
			if(response.result.reports.length > 0){
				var sb = "<table cellpadding='0' cellspacing='0' class='tbl'>";
				for(var i = 0; i < response.result.reports[0].columnHeader.metricHeader.metricHeaderEntries.length; i++){
					sb += "<tr>";
					sb += "<td>" + response.result.reports[0].columnHeader.metricHeader.metricHeaderEntries[i].name + "</td>";
					sb += "<td>" + response.result.reports[0].data.rows[0].metrics[0].values[i] + "</td>";
					sb += "</tr>";
				}
				sb += "</table>";
				$("#query-result").html(sb);
			}
			byTutorialAnalytics.hideLoading();
		});
	},

	reset: function(){
		$(".result-box").html("");
		$("#result").hide();
	},
	
	//get the analytics query reports, we are using version 4.0
	getReportQuery: function (id, sDate, eDate, dataMetrics){
		return new Promise(function(resolve, reject){
			gapi.client.request({
			  path: '/v4/reports:batchGet',
			  root: 'https://analyticsreporting.googleapis.com/',
			  method: 'POST',
			  body: {
				reportRequests: [
				  {
					viewId: id,
					dateRanges: [
					  {
						startDate: sDate,
						endDate: eDate
					  }
					],
					metrics: dataMetrics
				  }
				]
			  }
			}).then(function(response){
				if(response != null){
					resolve(response);
				}else{
					reject(Error("Error getting the data"));
				}
			})
		});
	},

	//show the transparent waiting progress wrapper
	showLoading: function (){
		$("#transparent-wrapper").show();
	},
	
	//hide the transparent waiting progress wrapper
	hideLoading: function(){
		$("#transparent-wrapper").hide();
	}
}

Just a note, when querying account summaries list, you have to use version 3, as version 4 does not support this functionality yet at the time this article is written.

And finally, here is the stylesheet css code.

/* remove the html and body margin and padding and align the body content to centre. */
html, body{
	margin:0;
	padding:0;
	font-family: Arial, Helvetica;
	font-size:15px;
	text-align:center;
}
button, select{
	padding:5px;
	border-radius:5px;
}

/* transparent loading wrapper background */
#transparent-wrapper
{
    display: none; 
    position: fixed;
    top: 0%; 
    left: 0%; 
    width: 100%; 
    height: 100%; 
    background-color: #000; 
    z-index: 1001;
    -moz-opacity: 0.35; 
    opacity: .35; 
    filter: alpha(opacity=35);
}

#wait-box{
	z-index:1002;
	position:absolute;
	top:50%;
	left:50%;
	width:400px;
	height:200px;
	margin-top:-100px;
	margin-left:-200px;
	text-align:center;
	background:#fff;
	border:solid 1px #cc;
	border-radius:3px;
}

/* content wrapper, we align back the content to left */
#account-panel{
	width:980px;
	text-align:left;
	margin:0 auto;
	padding:20px;
	margin-top:20px;
	border:solid 1px #ccc;
	border-radius:5px;
}

/* class for hide an object */
.hidden{
	display:none;
}

/* center the login box */
#login-box{
	width:250px;
	text-align:center;
	margin:0 auto;
	margin-top:50px;
	border:solid 1px #ccc;
	padding:20px;
	border-radius:5px;
	background:#e2ecfb;
}

button{
	cursor:pointer;
}

table.tbl td{
	padding:5px 10px;
}

.result-box{
	background:#d8e5fa;
	padding:20px;
	border:solid 1px #264984;
	border-radius:5px;
}

.result-box table.tbl{
	border-left:solid 1px #ccc;
	border-top:solid 1px #ccc;
}

.result-box table.tbl td{
	border-bottom:solid 1px #ccc;
	border-right:solid 1px #ccc;
}

Demo Files

You can download the example demo files in here.

Download

If you have any question about above codes, feel free to post your comment below.

Comments

EB
24 Nov, 2017
Hello Andy, Thanks for this concise tutorial. Is there a way to use this to display the number of visits on a site? I need to get the number of views on our site but I don't want to get the login prompt to the visitor.
andy
30 Nov, 2017
Hi EB, When you say the number of visits, did you mean live visitors? There is an option called ga:visits there in the checkbox list. Please see the following reference to use. https://developers.google.com/analytics/devguides/reporting/core/dimsmets#cats=user,session,traffic_sources
Sandra
29 Jan, 2018
Hi Andy, Thank you very much for your tutorial. It is just fabulous! I've tried to do that on my web server but it seems like we need to put the CLIENT ID in the google-analytics.js script. And yet it doesn't work… (website and data doesn't appear) When I come on your demo page, everything seems to work and I do not have to give you my client id. How did you do that? It would be so great to automate that… Thank you again, Andy! :) Sandra
andy
29 Jan, 2018
Hi Sarah, There are two things which are important, first is the Client ID and the second is the authorized javascript origin. Just make sure you have entered correctly the authorized javascript origin URL address. For example in my case, as I am doing a demo for bytutorial.com URL site, I entered this domain name into the authorized javascript origin. This will make sure when the script is run, Google will perform a check against the URL script from whether they do match or not. If it does not match, you will get an error. Try see your web console and see what exactly the error message you had.
Sandra
29 Jan, 2018
Thank you for your answer Andy, Normally, I had correctly create a Client ID and put my URL website in the authorized javascript origin. The content.googleapis respond with a 403 error. Do you think it is a mistake from the Client ID ? I have no idea how to resolve this errors. Sorry for disturbing… Thank you very much.
andy
29 Jan, 2018
Hi Sandra, it is hard to say without to see the actual page you created. Where do you get the wording content.googleapis, as I think this is not part of the analytics.js file.
Sandra
29 Jan, 2018
Ok, I didn't see it but we have to go in console.developper.google to activate Analytics API. :) Thank you Andy and have a good day !
andy
30 Jan, 2018
That's good then, you finally sort it out ;-)
Avisha Bhiryani
01 Feb, 2018
Your tutorial is great.But can I still use the same for my react JS project?
andy
01 Feb, 2018
Hi Avisha, Yes you definitely can, as all the logic are done completely in javascript.
Srihari
03 Feb, 2018
Hi Andy, Thank you for this fabulous tutorial. Is it possible to retrieve event data from google analytics and store it in a localhost database? I just tried to post the data when clicking the button and the same is tracked in my google analytics. But I wanted to make use of that data so that I can use it for my further analysis.
andy
05 Feb, 2018
Well, you definitely can store it in the local database if you want. I do not see anything wrong with it. I just wonder whether it is worth the effort as you can easily analyze your data in Google Analytics. This example code is good and handy only for reviewing the quick statistic of your current site.
Blake Warner
26 Jun, 2018
Thank you for putting this out. I have learned quite a bit about google reports api. I am building my own wordpress plugin and am having an issue changing the query metrics and re-submitting the query request method. I get an error saying there are too many metric parameters. I see that your app can re-submit. I seems to me that the request needs to be cleared as if it is the first time making the request to google. Can you shed some light on this? Thanks
andy
26 Jun, 2018
Hi Blake, Could you try using the tutorials file I have created and just passing the parameters you have? See if you receive the same error message. Just curious, what metric parameters you have passed?
sandip
26 Sep, 2018
I cant fetch site name and data i have added key and id. but somehow i cant fetch site names. can you please help me how to do that.
andy
26 Sep, 2018
Have you entered the correct url for Authorized JavaScript origins?
unnakb
05 Nov, 2018
Hi Andy, I have enabled the API for Google Analytics Reporting API. I created a client ID with 'Authorised JavaScript origins' as 'https://storage.googleapis.com'. In the analytics.js, I replaced the client ID with that of mine. And then I placed all of your demo files in a folder 'google-analytics-api-tutorial' inside my google cloud bucket. I have set the permissions of all the files in that folder to be 'User - allUsers - Reader'. In the chrome browser, when I try to open the webpage http://storage.googleapis.com//google-analytics-api-tutorial/google-analytics-api-tutorial.html, I only see a blank page. May I know what am I missing.
andy
06 Nov, 2018
Hi Unnakb, Could you check on the web console log and see if there is any error? There should be a javascript error if there is an issue.
isr
04 Jan, 2019
hi, i have the same problem. The console error is: uncaught exception: [object Object]
Savi
21 Dec, 2018
When I run the demo, it ask login. Please share the login details to run the demo.
andy
23 Dec, 2018
Hi Savi, please follow the tutorial steps to create your own api app account.
Galjonit
08 May, 2019
Hi Andy, Can you please upload a detailed explanation of the code in the google-analytics.js file or share any link which I can refer ?
andy
08 May, 2019
Hi Galjonit, I included in comments on most of the methods or function in the javascript. Is there any particular section that you are not quite sure?
JB
08 Jul, 2020
Hi Andy, Many thanks for this awesome tutorial. Everything works just fine. I have an issue though, I try to get data such as ga:sourceMedium and ga:language, but it appears these aren't metrics, I therefore have an issue with the payload ("message": "Unknown metric(s): ga:sourceMedium, ga:language "status": "INVALID_ARGUMENT") How can I get this type of data as well? I tried to add a "dimension" argument in the query, but it didn't work. Any help would be greatly appreciated. Regards
andy
26 Jul, 2020
Hi JB, I never used those two attribute arguments. It it is complained as invalid argument, it could either those argument is not available with the version you use. Is the documentation in Google mention this information exists?
jashwanth
27 Nov, 2021
Thank you for this tutorials my problem is when load the page i get the site name but , the id , kind and name are not displayed on web page instead they are showing on console(network) . my other problem is when I click on query it keeps loading and displays this In Query Result 'blank no result' In JSON Result { "reports": [ { "columnHeader": { "metricHeader": { "metricHeaderEntries": [ { "name": "ga:users", "type": "INTEGER" } ] } }, "data": { "totals": [ { "values": [ "0" ] } ] } } ] }
Antoine
23 Apr, 2022
Hello, Can you do an update for Google Identity auth ? It's the new Google Analytics 4 auth. https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#gapi-asyncawait Thanks !
Write Comment
0 characters entered. Maximum characters allowed are 1000 characters.

Related Articles