Node.js:Google Analytics API:我如何使用;服务帐户;?

Node.js:Google Analytics API:我如何使用;服务帐户;?,node.js,google-api,google-analytics-api,service-accounts,Node.js,Google Api,Google Analytics Api,Service Accounts,我正在创建一个LED grid ticker,它运行在一个平台上,通过使用Node.js的Google Analytics API收集Google分析数据。它将汇总多个网站的统计数据,然后在网格上滚动统计数据 我可以使用帮助通过列出帐户项目,特别是帐户id、属性id和视图id来保存手动工作。我在这方面遇到了错误(见下文) 这似乎是服务帐户的工作。在设置了一个Google云项目,然后设置了一个服务帐户之后,我添加了下载授权中包含的电子邮件地址,作为属性用户(读取/分析权限),适用于Google A

我正在创建一个LED grid ticker,它运行在一个平台上,通过使用Node.js的Google Analytics API收集Google分析数据。它将汇总多个网站的统计数据,然后在网格上滚动统计数据

我可以使用帮助通过列出帐户项目,特别是帐户id、属性id和视图id来保存手动工作。我在这方面遇到了错误(见下文)

这似乎是
服务帐户的工作。在设置了一个Google云项目,然后设置了一个服务帐户之后,我添加了下载授权中包含的电子邮件地址,作为属性用户(读取/分析权限),适用于Google Analytics管理设置。有了它,我可以成功地检索已知视图ID的分析数据(在Google Analytics admin中手动查找,ID显示在视图设置页面上),如下所示:

'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();
analytics.management.accounts.list({'auth': client}, function(error, response) {
    console.log(error);
    console.log(response);
});
这是一个很好的进展,但我在尝试使用列表视图所需的id时开始遇到身份验证错误(如果知道帐户id,也会出现相同的错误)

我猜答案是我需要使用OAuth,但是如果是,如何使用?服务帐户是否不再是一个选项?当服务帐户和硬件设备没有通常的OAuth来回用户交互时,我不确定如何处理这个问题。也许我只是在上面使用的JWT客户端中设置了一些错误

UDPATE:

为以后阅读此文章的人添加了信息:在确保正确设置了阅读权限后,我可以用以下内容列出Google Analytics帐户:

'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();
analytics.management.accounts.list({'auth': client}, function(error, response) {
    console.log(error);
    console.log(response);
});

注意:这不符合我在上面使用的承诺模式,但给出了node.js googleapis模块如何工作的想法。

当使用Google Analytics api的服务帐户时。您需要确保在帐户级别添加权限。我不知道为什么它必须是帐户级别,我只知道它不能以任何其他方式正常工作

当您授予服务帐户访问权限时。你是在客户层面做的吗?从管理api中读取帐户应该没有问题。试试这个,它更快,你也可以发布错误。啊哈!这些是在视图级别授权的。我将在接下来的一小时内测试并发布错误。谢谢你的这个想法@DalmTo:在检查服务帐户并设置每个Google Analytics帐户的访问权限(不仅仅是视图)后,错误消失了。如果你以答案的形式发表评论,我肯定会给你分数。谢谢你的帮助,这是正确的。可以使用设置的视图特定权限进行视图查询(需要在脚本中手动输入视图ID)。获取帐户列表,导致属性和视图列表,需要在帐户中设置权限,而不仅仅是在视图中设置权限。顺便说一句,如果您发布此项目,我会喜欢链接,我很乐意与您共享,并且会在我第一次完成后与您共享。谢谢你提到这件事。