Reputation: 1278
I'm creating an LED grid ticker run on a Raspberry Pi that will collect Google Analytics data via the Google Analytics API using Node.js. It will tally up counts from multiple websites then scrolling the stats across the grid.
I could use help listing account items via the Management API, specifically account id, property ids, and view ids to save on manual work. I'm getting errors in this area (see below).
This seemed like the job for a Service Account
. After setting up a Google Cloud project here, then setting up a service account here, I added the email address contained within the downloaded authorization as a property user (read/analyze permissions) where applicable in Google Analytics admin settings. With this, I can successfully retrieve Analytics data for a known view ID (looked up manually in Google Analytics admin, ID shown on a view settings page), with this:
'use strict';
//////////////
// includes //
//////////////
var google = require('googleapis');
var fs = require('fs');
var Promise = require('promise');
//////////////
// settings //
//////////////
//the service account auth file downloaded from Google Cloud
var serviceAccountInfoPath = './secrets.json';
//view id with 'ga:' prefix
//I want this to soon be an array of ids looked up by an authenticated API requested
var viewID = 'ga:999999999';
////////
// go //
////////
// go get it all
var go = function() {
loadServiceAccountInfo()
.then(function(serviceAccountInfo) {
return getJwtClient(serviceAccountInfo);
})
.then(function(jwtClient) {
var client = jwtClient;
var analytics = google.analytics('v3');
return getThisYearViewAnalytics(client, analytics, viewID);
})
.then(function(result) {
console.log('total users: ' + result.totalsForAllResults["ga:users"]);
console.log('total sessions: ' + result.totalsForAllResults["ga:pageviews"]);
console.log('total pageviews: ' + result.totalsForAllResults["ga:sessions"]);
})
.catch(function(error) {
console.log("go promise chain failed", error);
});
};
// load the Google service account login details
var loadServiceAccountInfo = function() {
return new Promise(function(resolve, reject) {
fs.readFile(serviceAccountInfoPath, 'utf8', function(error, serviceAccountInfoData) {
if(error) {
console.log('loadServiceAccountInfo failed: ' + error);
reject(error);
} else {
var serviceAccountInfo = JSON.parse(serviceAccountInfoData);
resolve(serviceAccountInfo);
}
});
});
};
//return a an authenticated Google API client
var getJwtClient = function(serviceAccountInfo) {
return new Promise(function(resolve, reject) {
var jwtClient = new google.auth.JWT(serviceAccountInfo.client_email, null, serviceAccountInfo.private_key, ['https://www.googleapis.com/auth/analytics.readonly'], null);
jwtClient.authorize(function (error, tokens) {
if (error) {
console.log('getJwtClient failed: ' + error);
reject(error);
} else {
resolve(jwtClient);
}
});
});
};
//this is a test query to get the last year of data for a single view id
var getThisYearViewAnalytics = function(client, analytics, viewID) {
return new Promise(function(resolve, reject) {
analytics.data.ga.get({
'auth': client,
'ids': viewID,
'metrics': 'ga:sessions,ga:pageviews,ga:users',
'start-date': '365daysAgo',
'end-date': 'today',
},
function (error, response) {
if (error) {
console.log('getThisYearViewAnalytics failed: ' + error);
reject(error);
} else {
resolve(response);
}
});
});
};
//ready, set, go!
go();
This is good progress, but I start running into authentication errors when attempting to list accounts, with id(s) needed to list views (which also gives the same errors if you knew the account id).
I'm guessing that the answer is that I need to use OAuth, but if so, how? Is a service account no longer an option? I'm not sure how I would proceed with this when the service account and hardware device don't have usual OAuth back-and-forth user interaction to work with. Perhaps I'm just setting something wrong in the JWT Client being used above?
UDPATE:
Added info for those who read this in the future: After making sure read permissions were properly set, I was able to list Google Analytics accounts with this:
analytics.management.accounts.list({'auth': client}, function(error, response) {
console.log(error);
console.log(response);
});
Note: This does not follow the promise pattern I was using above, but gives the idea of how node.js googleapis module works.
Upvotes: 1
Views: 1077
Reputation: 117301
When using a service account with the Google Analytics api. You need to be sure that you add the permission at the account level. I don't know why it needs to be the account level I just know that it doesn't work right any other way.
Upvotes: 1