<a class="container" href="/auth/google">Log In with Google</a>
In this tutorial, you are going to learn how to enable Google Analytics API and display that data in a Nodejs application.
Google Analytics is the go-to means to analyze and report incoming user traffic on a website. It has a dashboard that you can utilize to find all the reports and data. But what if you want to display some of that data on your website, or manipulate it in some other way? It is an open world, and people all over the world love stats. I love sharing stats of my monthly views/subscribers of my mailing list too. That is what you are going to do learn in this article.
In this tutorial, you are going to learn how to enable Google Analytics API and display that data in a Nodejs application. To keep things simple and usable, I am going to walk you through step by step. Another thing to note before you proceed, you can hook your authentication library or logic if you want to.
Table of Contents
v8.x.x
or higher installed along with npm/yarn as the package managerLet us begin by setting up the server. Install the following dependencies that will help you create a server using the Express framework. Also, do not forget to initialize your empty project with package.json
file first.
# initialize project
npm init --yes
# install dependencies
npm install --save express moment connect-ensure-login cookie-parser dotenv express-session googleapis
After installing those dependencies create a new file called index.js
and add the following snippet of code to kickstart a demo server to verify if everything is working.
const express = require('express')
const port = 3000
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/', (req, res) => {
res.sendFile(__dirname + '/views/index.html')
})
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`)
})
Create a new directory called views and make sure this directory is located at the root of your Node project. Inside this directory, create a new file called index.html. This file is going to be the home page of the application. For now, add some boilerplate code to it.
<!DOCTYPE html>
<html>
<head>
<title>Google Analytics Data Visualization</title>
<meta name="description" content="Google Analytics Data Visualization" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
header {
text-align: center;
}
</style>
</head>
<body>
<header>
<h1>Google Analytics Data Visualization with a Nodejs Server</h1>
</header>
</body>
</html>
Now go the terminal window, run the command node index.js
. This will trigger the server. After this, if you do not get any errors, visit the URL <a href="http://localhost:3000" target="_blank">http://localhost:3000</a>
and you will get the following result.
To enable server-to-server interactions with any Google API, the preferred method is to a Service Account. The Google Cloud Platform API console is the directory where you can manage all of the APIs provided by Google.
To enable one, you will need to set up a way to authenticate the Google Analytics for the user to use with this application interface we are building. To get started, create a new project on the Google API console. Make sure you are logged in with your Google ID to proceed with the following steps successfully. Visit console.developers.google.com. Click on the Select a project drop-down menu.
Next step will open a screen that will ask you for the name of the project or if you want to associate this project to a specific organization. For the project, choose something you can identify later on, like analytics-nodejs
. Then click on the button Create.
After the project gets created, you are now required to enable the API key for Google Drive API. On the Dashboard screen as shown below, click on the button Enable APIS and Services.
You have to enable two APIs from this screen. Search for Google Analytics Reporting API and Google Analytics API as shown below.
Select each of them and once you are redirected towards the API’s dedicated page, click on the button Enable.
After enabling both of them, you have to set up a way to create and store authentication credentials in the Node app. There are three ways to authenticate with Google APIs:
You are going to use OAuth 2 method in this demo. To create credentials, click the menu button on the left sidebar with the same name. The following screen will welcome you.
Click on the button Create Credentials and select the second option from the drop-down menu that just popped up, called OAuth client ID. This option will allow the application to access a user’s data with their permission.
Next, it will prompt you to configure the consent screen. Click on the button that says Configure consent screen, as shown below.
It will redirect you to the following screen. Fill up the Application name in the form as shown below and click on the **Save **button.
It will now redirect you to the following screen. The process to get OAuth credentials starts. Select the Application Type to Web application. Then let the name be the suggested default. Under the section, Authorized redirect URIs, enter.
After that, click the button Create and you will get a pop up giving the Client ID and Client Secret. To save them, create a new file at the root the Node project and name it .env
. This file is going to keep this sensitive piece of information. I do suggest that do not commit this file if you are going to save this project on Github.
CLIENT_ID=XXXX
CLIENT_SECRET=XXXX
PORT=3000
# replace the Xs with your credentials and values
Replace the Xs with the real values that you get from the screen, as shown below.
That’s it for getting credentials for utilizing Google Analytics API services. You can now use the credential values in your Nodejs app to write the strategy to authenticate a user with a Google ID.
To set up a Node server, you have already made a small working skeleton. Let us proceed by extending this skeleton. Import the dependencies that are required to make OAuth work. In the below snippet, after importing the dependencies that you installed earlier, you are also going to set up some middleware functions.
const express = require('express')
const moment = require('moment')
const google = require('googleapis')
const expressSession = require('express-session')
const cookieParser = require('cookie-parser')
require('dotenv').config()
const port = process.env.PORT || 3000
const app = express()
const googleAccounts = google.analytics('v3')
const googleAnalytics = google.analyticsreporting('v4')
let viewSelected
const clientID = process.env.CLIENT_ID
const clientSecret = process.env.CLIENT_SECRET
const callbackURL = 'http://localhost:3000/login/google/return'
const oauth2Client = new google.auth.OAuth2(clientID, clientSecret, callbackURL)
const url = oauth2Client.generateAuthUrl({
access_type: 'online',
scope: 'https://www.googleapis.com/auth/analytics.readonly'
})
app.use(express.static('views'))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cookieParser())
app.use(expressSession({ secret: 'as!883@bnr
The cookies and session middleware functions are being used to save the user authentication data by creating a session in the browser. To access the analytics and Google's OAuth user consent, you are going to use the npm dependency called ```googleapis```. It is the official library that Google offers to work with their API. The ```clientID``` and the ```clientSecret``` are the same values that you obtained in the previous step. Using ```dotenv``` module, they can be imported as environment variables. The callback URL is what the API response is going to redirect on success.
The variable ```oauth2Client``` in the preceding snippet takes all three OAuth values required to get the user's consent. The most important thing here to notice is ```scope``` and the value inside ```oauth2Client.generateAuthUrl``` method.
The scope determines how you want to access the Google Analytics API. This API has several scopes such as the one you have defined in the above snippet, and the few more like the following:
* ```<a href="https://www.googleapis.com/auth/analytics" target="_blank">https://www.googleapis.com/auth/analytics</a>``` is used to view and manage data
* ```<a href="https://www.googleapis.com/auth/analytics.edit" target="_blank">https://www.googleapis.com/auth/analytics.edit</a>``` is used to edit entities
The ```scope``` you are accessing is only to view the data; hence, the suffix ```readonly```. You can always pick the scope that suits your application's use case.
## Define Routes
To make this application work, it needs to have an interface. You are going to use static HTML files to keep things simple. Define the following routes in the same ```index.js``` file. You have already defined the index route to serve the home page of the application using the existing view file ```index.html```. The next routes are defined in the following snippet are related to authenticating a user and handing redirect URL.
app.get(‘/auth/google’, (req, res) => {
res.redirect(url)
})
app.get(‘/login/google/return’, (req, res) => {
oauth2Client.getToken(req.query.code, (err, tokens) => {
viewSelected = ''
if (!err) {
oauth2Client.setCredentials({
access_token: tokens.access_token
})
res.redirect('/setcookie')
} else {
console.log('Error: ' + err)
}
})
})
app.get(‘/setcookie’, (req, res) => {
res.cookie('google-auth', new Date())
res.redirect('/success')
})
app.get(‘/success’, (req, res) => {
if (req.cookies['google-auth']) {
res.sendFile(__dirname + '/views/success.html')
} else {
res.redirect('/')
}
})
app.get(‘/clear’, (req, res) => {
viewSelected = ''
res.redirect('/success')
})
On success, the cookie will be set the application will take the user to a new route called```/success```. Create a file ```views/success.html``` with the following code. The ```viewSelected``` holds the value of the analytics report associated with one of the multiple **Properties and Apps** you might have setup. The ```clear``` URL will be hit when none of the value is selected from **Properties and Apps**.
<head>
<title>Google Analytics Data Visualization</title>
<meta name="description" content="Google Analytics Data Visualization" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
header,
main {
text-align: center;
}
</style>
</head>
<body>
<header>
<h1>Google Analytics Data Visualization</h1>
</header>
<main>
<p id="deets">
<select style="display: none"></select>
</p>
<p><a href="/clear">Switch view</a> | <a href="/logoff">Log off</a></p>
</main>
<script
src="https://code.jquery.com/jquery-2.2.1.min.js"
integrity="sha256-gvQgAFzTH6trSrAWoH1iPo9Xc96QxSZ3feW6kem+O00="
crossorigin="anonymous"
></script>
<script src="/success.js"></script>
</body>
It is associated with a script called ```success.js``` that is responsible for displaying charts. For the chart API, Google Charts is the perfect use case for this demo.
$(function() {
$.get('/getData', function(datum) {
if (datum == 'An error occurred') {
$('<span></span>')
.text('Error: ' + datum)
.appendTo('p#deets')
} else if (datum.type == 'views') {
$('select').css('display', 'block')
$('select').append('<option value=""> Select a view')
datum.results.forEach(function(view) {
$('select').append('<option value="' + view.id + '"> ' + view.name)
})
} else {
$('<div></div>')
.text('Stats:')
.appendTo('p#deets')
$('p#deets').append(
'<h4>Views</h4><img src="//chart.googleapis.com/chart?chxp=0,0&chxl=0:|A month ago|Now|1:|0|' +
datum[1] +
'&chbh=17,1,0&chxt=x,y&cht=bvs&chs=600x125&chco=c0c0c0&chd=t:' +
datum[0] +
'&chds=0,' +
datum[1] +
'" />'
)
}
})
$('select').on('change', function(event) {
var active = $('select').val()
if (active != 'null') {
$.get('/getData?' + $.param({ view: active }), function() {
window.location.reload()
})
}
})
})
Next, define the route ```/getData``` where the business logic behind what happens when the user selected a view or when no view is selected. The selection of view here is one of the multiple **Properties and Apps**.
app.get(‘/getData’, function(req, res) {
if (req.query.view) {
viewSelected = req.query.view
}
if (!viewSelected) {
googleAccounts.management.profiles.list(
{
accountId: '~all',
webPropertyId: '~all',
auth: oauth2Client
},
(err, data) => {
if (err) {
console.error('Error: ' + err)
res.send('An error occurred')
} else if (data) {
let views = []
data.items.forEach(view => {
views.push({
name: view.webPropertyId + ' - ' + view.name + ' (' + view.websiteUrl + ')',
id: view.id
})
})
res.send({ type: 'views', results: views })
}
}
)
} else {
let now = moment().format('YYYY-MM-DD')
let aMonthAgo = moment()
.subtract(1, 'months')
.format('YYYY-MM-DD')
let repReq = [
{
viewId: viewSelected,
dateRanges: [
{
startDate: aMonthAgo,
endDate: now
}
],
metrics: [
{
expression: 'ga:hits'
}
],
dimensions: [
{
name: 'ga:day'
}
]
}
]
googleAnalytics.reports.batchGet(
{
headers: {
'Content-Type': 'application/json'
},
auth: oauth2Client,
resource: {
reportRequests: repReq
}
},
(err, data) => {
if (err) {
console.error('Error: ' + err)
res.send('An error occurred')
} else if (data) {
let views = []
let max = 0
data.reports[0].data.rows.forEach(view => {
views.push(view.metrics[0].values[0])
if (parseInt(view.metrics[0].values[0]) > parseInt(max)) max = view.metrics[0].values[0]
})
res.send([views, max])
}
}
)
}
})
app.get(‘/logoff’, (req, res) => {
res.clearCookie('google-auth')
res.redirect('/')
})
The last URL ```/logoff``` is to sign out the user from the application. Lastly, edit the ```index.html``` file. Add the following segment after the ```header```. This will act as a bare minimum button to login with a Google account.
<a class="container" href="/auth/google">Log In with Google</a>
## Running the application
Everything is setup now. Let us run the application. Go to the terminal window, run the command ```node index.js``` to start the server, and visit the URL ```<a href="http://localhost:3000" target="_blank">http://localhost:3000</a>``` in the browser window. The following screen will welcome you.
![](https://blog.crowdbotics.com/content/images/2019/06/ss12-1.png)
Click the login button, and it will redirect you to the sign in with a Google ID.
![](https://blog.crowdbotics.com/content/images/2019/06/ss13-1.png)
Enter the login ID and password for the Google ID, and you will be redirected to the following page. First, it will ask for your permission as the user to allow the application to read the data.
![](https://blog.crowdbotics.com/content/images/2019/06/ss14-1.png)
![](https://blog.crowdbotics.com/content/images/2019/06/ss15-Redacted.png)
Next, you will be given a ```select``` menu like below to select the Analytics app and view its data. The below image demonstrates the content of ```success.html``` web page.
![](https://blog.crowdbotics.com/content/images/2019/06/ss16-1.png)
If you click on the **Log off** button, it will redirect you back to the home page, also known as the ```index``` route. It will log out the user and clear the cookie as stated in the ```/logoff``` route in ```index.js``` file.
## Conclusion
You have successfully integrated Google Analytics API with a Nodejs server and visualize a specific amount of data. The challenge is now to either modify or elaborate the strategy we discussed in this tutorial and implement with your own ideas. Maybe use a frontend library like [Reactjs](https://morioh.com/p/0dc8259c513c "Reactjs").
If you need to take a look at the code for this tutorial, you can refer to [**this Github repo.**](https://github.com/crowdbotics-apps/nodejs-googleanaylti-5310 "**this Github repo.**")
**Thanks for reading** ❤
If you liked this post, share it with all of your programming buddies!
Follow us on [**Facebook**](https://www.facebook.com/nodejstutorial4u "**Facebook**") | [**Twitter**](https://twitter.com/moriohdotcom "**Twitter**")
### Further reading
☞ [The Complete Node.js Developer Course (3rd Edition)](http://learnstartup.net/p/BJQWO5_Wnx "The Complete Node.js Developer Course (3rd Edition)")
☞ [Angular & NodeJS - The MEAN Stack Guide](http://learnstartup.net/p/Skf7ILFw3l "Angular & NodeJS - The MEAN Stack Guide")
☞ [NodeJS - The Complete Guide (incl. MVC, REST APIs, GraphQL)](http://learnstartup.net/p/KCK49_imV "NodeJS - The Complete Guide (incl. MVC, REST APIs, GraphQL)")
☞ [Best 50 Nodejs interview questions from Beginners to Advanced in 2019](https://morioh.com/p/2215cdcde314 "Best 50 Nodejs interview questions from Beginners to Advanced in 2019")
☞ [Node.js 12: The future of server-side JavaScript](https://morioh.com/p/b63d09a87c24 "Node.js 12: The future of server-side JavaScript")
☞ [An Introduction to Node.js Design Patterns](https://morioh.com/p/e88fd7f65f24 "An Introduction to Node.js Design Patterns")
☞ [Basic Server Side Rendering with Vue.js and Express](https://morioh.com/p/2cc634ed25e9 "Basic Server Side Rendering with Vue.js and Express")
☞ [Fullstack Vue App with MongoDB, Express.js and Node.js](https://morioh.com/p/53cab5146c8e "Fullstack Vue App with MongoDB, Express.js and Node.js")
☞ [How to create a full stack React/Express/MongoDB app using Docker](https://morioh.com/p/e4da2400bc31 "How to create a full stack React/Express/MongoDB app using Docker")
, resave: true, saveUninitialized: true }))
// ... rest of the code remains the same
The cookies and session middleware functions are being used to save the user authentication data by creating a session in the browser. To access the analytics and Google’s OAuth user consent, you are going to use the npm dependency called googleapis
. It is the official library that Google offers to work with their API. The clientID
and the clientSecret
are the same values that you obtained in the previous step. Using dotenv
module, they can be imported as environment variables. The callback URL is what the API response is going to redirect on success.
The variable oauth2Client
in the preceding snippet takes all three OAuth values required to get the user’s consent. The most important thing here to notice is scope
and the value inside oauth2Client.generateAuthUrl
method.
The scope determines how you want to access the Google Analytics API. This API has several scopes such as the one you have defined in the above snippet, and the few more like the following:
<a href="https://www.googleapis.com/auth/analytics" target="_blank">https://www.googleapis.com/auth/analytics</a>
is used to view and manage data<a href="https://www.googleapis.com/auth/analytics.edit" target="_blank">https://www.googleapis.com/auth/analytics.edit</a>
is used to edit entitiesThe scope
you are accessing is only to view the data; hence, the suffix readonly
. You can always pick the scope that suits your application’s use case.
To make this application work, it needs to have an interface. You are going to use static HTML files to keep things simple. Define the following routes in the same index.js
file. You have already defined the index route to serve the home page of the application using the existing view file index.html
. The next routes are defined in the following snippet are related to authenticating a user and handing redirect URL.
app.get('/auth/google', (req, res) => {
res.redirect(url)
})
app.get('/login/google/return', (req, res) => {
oauth2Client.getToken(req.query.code, (err, tokens) => {
viewSelected = ''
if (!err) {
oauth2Client.setCredentials({
access_token: tokens.access_token
})
res.redirect('/setcookie')
} else {
console.log('Error: ' + err)
}
})
})
app.get('/setcookie', (req, res) => {
res.cookie('google-auth', new Date())
res.redirect('/success')
})
app.get('/success', (req, res) => {
if (req.cookies['google-auth']) {
res.sendFile(__dirname + '/views/success.html')
} else {
res.redirect('/')
}
})
app.get('/clear', (req, res) => {
viewSelected = ''
res.redirect('/success')
})
On success, the cookie will be set the application will take the user to a new route called/success
. Create a file views/success.html
with the following code. The viewSelected
holds the value of the analytics report associated with one of the multiple Properties and Apps you might have setup. The clear
URL will be hit when none of the value is selected from Properties and Apps.
<!DOCTYPE html>
<html>
<head>
<title>Google Analytics Data Visualization</title>
<meta name="description" content="Google Analytics Data Visualization" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
header,
main {
text-align: center;
}
</style>
</head>
<body>
<header>
<h1>Google Analytics Data Visualization</h1>
</header>
<main>
<p id="deets">
<select style="display: none"></select>
</p>
<p><a href="/clear">Switch view</a> | <a href="/logoff">Log off</a></p>
</main>
<script
src="https://code.jquery.com/jquery-2.2.1.min.js"
integrity="sha256-gvQgAFzTH6trSrAWoH1iPo9Xc96QxSZ3feW6kem+O00="
crossorigin="anonymous"
></script>
<script src="/success.js"></script>
</body>
</html>
It is associated with a script called success.js
that is responsible for displaying charts. For the chart API, Google Charts is the perfect use case for this demo.
$(function() {
$.get('/getData', function(datum) {
if (datum == 'An error occurred') {
$('<span></span>')
.text('Error: ' + datum)
.appendTo('p#deets')
} else if (datum.type == 'views') {
$('select').css('display', 'block')
$('select').append('<option value=""> Select a view')
datum.results.forEach(function(view) {
$('select').append('<option value="' + view.id + '"> ' + view.name)
})
} else {
$('<div></div>')
.text('Stats:')
.appendTo('p#deets')
$('p#deets').append(
'<h4>Views</h4><img src="//chart.googleapis.com/chart?chxp=0,0&chxl=0:|A month ago|Now|1:|0|' +
datum[1] +
'&chbh=17,1,0&chxt=x,y&cht=bvs&chs=600x125&chco=c0c0c0&chd=t:' +
datum[0] +
'&chds=0,' +
datum[1] +
'" />'
)
}
})
$('select').on('change', function(event) {
var active = $('select').val()
if (active != 'null') {
$.get('/getData?' + $.param({ view: active }), function() {
window.location.reload()
})
}
})
})
Next, define the route /getData
where the business logic behind what happens when the user selected a view or when no view is selected. The selection of view here is one of the multiple Properties and Apps.
app.get('/getData', function(req, res) {
if (req.query.view) {
viewSelected = req.query.view
}
if (!viewSelected) {
googleAccounts.management.profiles.list(
{
accountId: '~all',
webPropertyId: '~all',
auth: oauth2Client
},
(err, data) => {
if (err) {
console.error('Error: ' + err)
res.send('An error occurred')
} else if (data) {
let views = []
data.items.forEach(view => {
views.push({
name: view.webPropertyId + ' - ' + view.name + ' (' + view.websiteUrl + ')',
id: view.id
})
})
res.send({ type: 'views', results: views })
}
}
)
} else {
let now = moment().format('YYYY-MM-DD')
let aMonthAgo = moment()
.subtract(1, 'months')
.format('YYYY-MM-DD')
let repReq = [
{
viewId: viewSelected,
dateRanges: [
{
startDate: aMonthAgo,
endDate: now
}
],
metrics: [
{
expression: 'ga:hits'
}
],
dimensions: [
{
name: 'ga:day'
}
]
}
]
googleAnalytics.reports.batchGet(
{
headers: {
'Content-Type': 'application/json'
},
auth: oauth2Client,
resource: {
reportRequests: repReq
}
},
(err, data) => {
if (err) {
console.error('Error: ' + err)
res.send('An error occurred')
} else if (data) {
let views = []
let max = 0
data.reports[0].data.rows.forEach(view => {
views.push(view.metrics[0].values[0])
if (parseInt(view.metrics[0].values[0]) > parseInt(max)) max = view.metrics[0].values[0]
})
res.send([views, max])
}
}
)
}
})
app.get('/logoff', (req, res) => {
res.clearCookie('google-auth')
res.redirect('/')
})
The last URL /logoff
is to sign out the user from the application. Lastly, edit the index.html
file. Add the following segment after the header
. This will act as a bare minimum button to login with a Google account.
<main>
<a class="container" href="/auth/google">Log In with Google</a>
</main>
Everything is setup now. Let us run the application. Go to the terminal window, run the command node index.js
to start the server, and visit the URL <a href="http://localhost:3000" target="_blank">http://localhost:3000</a>
in the browser window. The following screen will welcome you.
Click the login button, and it will redirect you to the sign in with a Google ID.
Enter the login ID and password for the Google ID, and you will be redirected to the following page. First, it will ask for your permission as the user to allow the application to read the data.
Next, you will be given a select
menu like below to select the Analytics app and view its data. The below image demonstrates the content of success.html
web page.
If you click on the Log off button, it will redirect you back to the home page, also known as the index
route. It will log out the user and clear the cookie as stated in the /logoff
route in index.js
file.
You have successfully integrated Google Analytics API with a Nodejs server and visualize a specific amount of data. The challenge is now to either modify or elaborate the strategy we discussed in this tutorial and implement with your own ideas. Maybe use a frontend library like Reactjs.
If you need to take a look at the code for this tutorial, you can refer to this Github repo.
Thanks for reading ❤
If you liked this post, share it with all of your programming buddies!
#node-js #web-development #web-service #javascript