Google Analytics Data API - HTML to Apps Script: gapi is not defined - javascript

I am trying to execute a Report with the Google Analytics Data API. I built the request using Google's documentation and I get this script. The script works well if I execute it directly with the "Try this method" option in the documentation:
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for analyticsdata.properties.runReport
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/code-samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/analytics https://www.googleapis.com/auth/analytics.readonly"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("YOUR_API_KEY");
return gapi.client.load("https://analyticsdata.googleapis.com/$discovery/rest?version=v1beta")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.analyticsdata.properties.runReport({
"property": "properties/295880876",
"resource": {
"metrics": [
{
"name": "sessions"
},
{
"name": "conversions"
},
{
"name": "totalRevenue"
}
],
"dimensions": [
{
"name": "week"
},
{
"name": "year"
}
],
"dateRanges": [
{
"startDate": "2021-01-01",
"endDate": "today"
}
]
}
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>
Now I want to run this Script in Apps Script and import the Data to a spreadsheet. However as this is a HTML, if I want to run it as a JS and delete the script tags and content I receive "gapi is not defined".
It is clear that I still have to load https://apis.google.com/js/api.js somehow, but how?
Thanks for your help!

I believe your goal is as follows.
You want to use "Method: properties.runReport" with Google Apps Script.
When I saw your showing script, it seems that it is used for Javascript. In this case, Javascript is different from Google Apps Script. I think that this might be the reason for your issue.
In order to achieve your goal, in the current stage, Advanced Google services can be used. So, in this answer, I would like to propose using AnalyticsData with the Advanced Google services of Google Apps Script.
The sample script is as follows.
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet. And, please enable "AnalyticsData" at Advanced Google services. And, please set your property ID to ### of const property = "properties/###";.
function myFunction() {
// Retrieve values from Google Analytics Data API (GA4)
const property = "properties/###"; // Please set your property ID.
const resource = {
"metrics": [
{
"name": "sessions"
},
{
"name": "conversions"
},
{
"name": "totalRevenue"
}
],
"dimensions": [
{
"name": "week"
},
{
"name": "year"
}
],
"dateRanges": [
{
"startDate": "2021-01-01",
"endDate": "today"
}
]
};
const obj = AnalyticsData.Properties.runReport(resource, property);
// Put values to Spreadsheet.
const header = [...obj.dimensionHeaders.map(({ name }) => name), ...obj.metricHeaders.map(({ name }) => name)];
const values = [header, ...obj.rows.map(({ dimensionValues, metricValues }) => [...dimensionValues.map(({ value }) => value), ...metricValues.map(({ value }) => value)])];
const sheetName = "Sheet1"; // Please set the sheet name.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName)
sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}
When you run this script, the values are retrieved from "properties.runReport", and the retrieved values are put into the Spreadsheet.
Note:
I cannot know the final result you expect from Now I want to run this Script in Apps Script and import the Data to a spreadsheet.. So, in the above sample script, the retrieved values are put to "Sheet1" as the header of week,year,sessions,conversions,totalRevenue. If you want to change this, please modify this for your actual situation.
Reference:
Method: properties.runReport

Related

Javascript Browser WebExtension API Manifest v3 - Service Worker and chrome.storage.local API issue

I'm implementing a small extension for Copy as cURL feature (as done by the Network tab of DevTools) and I would like to use Manifest v3. According to the documentation and to the contribution of the community, Service Worker at a certain time stops to live so some variables cannot retrieve the needed information from the active tab.
For managing this, I'm using chrome.storage.local.set and .get functions in order to keep the needed information also after the Service Worker stops to live. When I run the extension test, I don't receive any error, but, despite I retrieve the stored variables by the chrome.storage API, sometimes I continue to not retrieve the values anymore also when the Service Worker should be alive. For example:
when I connect to a website, I can retrieve and copy the correct data also in 1 min, then, if I continue to Copy (without refreshing the page), I don't get the parameters (i.e., GET headers).
sometimes, if I open a new tab, insert an address and quickly press Copy as cURL, of my extension, headers are not copied, and I need to refresh the page (not by clicking refresh button of browser but click on URL then ENTER) for getting them.
Maybe the issue is not related to the Time-to-live of the Service Worker because I can keep a page opened for a lot of minutes and it gives me the right parameters. I don't know where my approach is failing. The code of this small implementation is the following:
background.js
"use strict";
/*
Called when the item has been created, or when creation failed due to an error.
We'll just log success/failure here.
*/
function onCreated() {
if (chrome.runtime.lastError) {
console.log(`Error: ${chrome.runtime.lastError}`);
} else {
console.log("Item created successfully");
}
}
/*
Called when the item has been removed.
We'll just log success here.
*/
function onRemoved() {
console.log("Item removed successfully");
}
/*
Called when there was an error.
We'll just log the error here.
*/
function onError(error) {
console.log(`Error: ${error}`);
}
/*
Create all the context menu items.
*/
chrome.contextMenus.create({
id: "tools-copy",
//title: chrome.i18n.getMessage("menuItemToolsCopy"),
title: "Copy",
contexts: ["all"],
}, onCreated);
chrome.contextMenus.create({
id: "tools-copy-curl",
parentId: "tools-copy",
//title: chrome.i18n.getMessage("menuItemToolsCopyAsFFUF"),
title: "Copy as cURL",
contexts: ["all"],
}, onCreated);
const tabData = {};
const getProp = (obj, key) => (obj[key] || (obj[key] = {}));
const encodeBody = body => {
var data = '';
// Read key
for (var key in body.formData) { //body is a JSON object
data += `${key}=${body.formData[key]}&`;
}
data = data.replace(/.$/,"");
var body_data = `'${data}'`;
return body_data;
}
const FILTER = {
types: ['main_frame', 'sub_frame'],
urls: ['<all_urls>'],
};
const TOOLS = {
CURL: 'tools-copy-curl',
};
chrome.webRequest.onBeforeRequest.addListener(e => {
getProp(getProp(tabData, e.tabId), e.frameId).body = e.requestBody;
chrome.storage.local.set({tabData: tabData}, function() {
console.log('HTTP request saved');
});
}, FILTER, ['requestBody']);
chrome.webRequest.onBeforeSendHeaders.addListener(e => {
getProp(getProp(tabData, e.tabId), e.frameId).headers = e.requestHeaders;
chrome.storage.local.set({tabData: tabData}, function() {
console.log('HTTP request saved');
});
}, FILTER, ['requestHeaders']);
chrome.tabs.onRemoved.addListener(tabId => delete tabData[tabId]);
chrome.tabs.onReplaced.addListener((addId, delId) => delete tabData[delId]);
chrome.contextMenus.onClicked.addListener((info, tab) => {
chrome.storage.local.get(["tabData"], function(items) {
const data = items.tabData[tab.id]?.[info.frameId || 0] || {};
if (info.menuItemId === TOOLS.CURL) {
var txt_clip = `curl -u '${info.frameUrl || tab.url}'` +
(data.headers?.map(h => ` -H '${h.name}: ${h.value}'`).join('') || '') +
(data.body? ' --data_raw ' + encodeBody(data.body) : '');
}
chrome.tabs.sendMessage(tab.id,
{
message: "copyText",
textToCopy: txt_clip
}, function(response) {})
});
});
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.message === "copyText") {
navigator.clipboard.writeText(request.textToCopy);
sendResponse({status: true});
}
}
);
manifest.json
{
"manifest_version": 3,
"name": "CopyAsCURL",
"description": "Copy as cURL test example.",
"version": "1.0",
"default_locale": "en",
"background": {
"service_worker": "background.js"
},
"permissions": [
"contextMenus",
"activeTab",
"cookies",
"webRequest",
"tabs",
"clipboardWrite",
"storage"
],
"host_permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["content.js"]
}
],
"icons": {
"16": "icons/menu-16.png",
"32": "icons/menu-32.png",
"48": "icons/menu-48.png"
}
}
I want also to thank #wOxxOm for the support on similar topic.

How to use Calendar.Events.patch in Google Apps Script?

I have searched and searched trying to find the answer to this but from all the examples and answers I've read I can't see what my problem is.
I am trying to update the extended properties of a series of events selected by a user. The IDs of the calendar events (from the Advanced API, not the built in CalendarApp) are stored in an array as they're selected. I'm then passing this array to a function to be looped through and update the extended properties of each event identified in the array.
It simply doesn't work, I just get null returned from the patch call, not even an error that I could work with. Here is a screenshot of logged output, the null at the end if what the patch request returns.
My function is:
function updateLessonsStatus(arrCalIds){
try {
Logger.log(arrCalIds);
arrCalIds.forEach(function(row){
Logger.log(row);
var objEventPatch = {
"resource": {
"extendedProperties": {
"shared": {
"status": "accounted"
}
}
}
};
Logger.log(objEventPatch);
return Calendar.Events.patch(objEventPatch, "primary", row);
//return true;
});
}
catch(err) {
Logger.log(err);
throw err;
}
}
I have also tried setting objEventPatch like this as per Google's Calendar API patch 'Try this API' reference https://developers.google.com/calendar/v3/reference/events/patch :
var objEventPatch = {
"calendarId": "primary",
"eventId": row,
"resource": {
"extendedProperties": {
"shared": {
"status": "accounted"
}
}
}
};
I still get null from Google Apps Script. I can succesfully get and patch events using the IDs I have using the 'Try this API' feature.
There are very few examples of using the advanced APIs with Google Apps Script in Google's documentation and nothing I could find for patch so I have used the Javascript examples to construct what I have written so far.
Can anybody help with what I am doing wrong?
(UPDATED for clarity and included image of null returned logger output)
You are providing one nested object too much
Modify
var objEventPatch = {
"resource": {
"extendedProperties": {
"shared": {
"status": "accounteddd"
}
}
}
};
to
var objEventPatch = {
"extendedProperties": {
"shared": {
"status": "accounteddd"
}
}
};
Side note:
If you want to explore the request response for troubleshooting purposes, I recommend you to perform your request with a call to the request URL with the UrlFetchApp instead of using the prebuilt Calendar service.

Not able to autheticate google cloud vision api . How to autheticate it to use it further

My Code looks like this :-
var vision = require('#google-cloud/vision');
handleSubmit = () =>{
console.log("encoded string submitted=",this.state.files);
this.useVisionCloud();
}
useVisionCloud = () =>{
const client = new vision.ImageAnnotatorClient();
const request_body = {
"requests": [
{
"image": {
"content": this.state.files
},
"features": [
{
"type": "TEXT_DETECTION"
}
]
}
]
};
client.textDetection(request_body).then(response => {
console.log("text got=",response);
// doThingsWith(response);
})
.catch(err => {
console.log("error got=",err);
});
}
I already tried setting environment variable but didn't work .
I have also created service account and downloaded the file.json
but dont know how to use it for authentication
im getting the following error :-
Uncaught Error: {"clientConfig":{},"port":443,"servicePath":"vision.googleapis.com","scopes":["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/cloud-vision"]}You need to pass auth instance to use gRPC-fallback client in browser. Use OAuth2Client from google-auth-library.
on triggering a post request to Google API .
Final Query is :- I am not able to understand how to authenticate API so that i can further use it to detect text in my images
Set the env variable eg:
export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
I would recommend having a separate backend that calls vision api. Then have the javascript code in your browser call your backend.

How to display page visits in my web site using data from Google Analytics?

I have a web site and I want, for every article I publish, to display the number of people who visited that page.
My idea is to show the number of page visits by fetching this data from my Analytics account.
By following the tutorial on Google Analytics to handle reports, I have created a small chunk of code to retrieve a specific page's visits number:
let analytics_api_controller = (function () {
const API_KEY = "<secret>";
const CLIENT_ID = "<secret>";
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({ scope: "https://www.googleapis.com/auth/analytics https://www.googleapis.com/auth/analytics.readonly" })
.then(function () { console.log("Sign-in successful"); },
function (err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey(API_KEY);
return gapi.client.load("https://content.googleapis.com/discovery/v1/apis/analyticsreporting/v4/rest")
.then(function () { console.log("GAPI client loaded for API"); },
function (err) { console.error("Error loading GAPI client for API", err); });
}
function execute() {
return gapi.client.analyticsreporting.reports.batchGet({
"resource": {
"reportRequests": [{
"viewId": "<secret>",
"dateRanges": [{
"startDate": "2018-03-01",
"endDate": "2019-05-01"
}],
"metrics": [{ "expression": "ga:pageviews" }],
"dimensions": [{ "name": "ga:pagePath" }],
"dimensionFilterClauses": [{
"filters": [{
"operator": "EXACT",
"dimensionName": "ga:pagePath",
"expressions": ["/articles/2019/05/10/myarticle.html"]
}]
}]
}]
}
}).then(function (response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
}, function (err) {
console.error("Execute error", err);
});
}
function _viewsPerPage(pageUrl) {
return execute();
}
// Ctor
window.addEventListener("load", function(e) {
gapi.load("client:auth2", function () {
gapi.auth2.init({ client_id: CLIENT_ID });
});
this.window.setTimeout(function() {
authenticate().then(loadClient);
}, 2000);
});
return {
viewsPerPage: _viewsPerPage
};
})();
The setTimeout is something I added to quickly workaround some timing issues (I need to wait for the API to load, something I will properly solve later).
Problem
The code works fine and this is what happens:
The page loads.
The code kicks in and I am asked to sign in to give permission to access my Analytics reports from my Google account.
I give consent.
In F12 tools I manually run: analytics_api_controller.viewsPerPage(), which gives me the report in the console.
The problem is point 2! Every single time I load the page, I am asked to sign in and give permission. This thing is supposed to go in production, so every user will be prompted to access my Analytics info? I assume if they try they'll fail...
Why am I asked to sign in to use this API?
Am I using the correct API to solve this issue?
I think I am not really understanding how I am supposed to use the Google Analytics API. What am I doing wrong? How should this objective be addressed?
You used a Client-side Application that requires the users to login to access your google analytics data. You should use a Service Application that allows your app to login and access your google analytics data (server-side).
PHP quickstart for service accounts

Retrieve latest Commit links and message with GitHub Api and Ember

I have reproduced my case with this jsbin http://emberjs.jsbin.com/xeninaceze/edit?js,output
Github API allows me to get the list of events by author:
API Link - api.github.com/users/:user/events
I can access to the commit message filtering the events “PushEvent”, and it s perfectly fine because i cam stream my latest commit message.
var gitactivitiesPromise = function() {
return new Ember.RSVP.Promise(function (resolve) {
Ember.$.ajax(eventsAct, {
success: function(events) {
var result = [];
events.filter(function(event) {
return event.type == 'PushEvent';
}).forEach(function(item){
item.payload.commits.map(function(commit){
result.push(store.createRecord('commit', {
message: commit.message,
}));
});
});
resolve(result);
},
error: function(reason) {
reject(reason);
}
});
});
};
The problem is that i want to stream beside the msg also his own url link. html_url
I need to know how i can tackle it? since the commit url links are not in the in the API Link
api.github.com/users/:user/events
But they are in the following api
api.github.com/repos/:user/repo/commits/branch
This makes bit more complicate to access to the latest commits url link html_url
This is a good example of what i am trying to do
http://zmoazeni.github.io/gitspective/#
It streams in the push events the latest commits message with links
It seems to me that all the relevant data is already there:
{
"id": "3414229549",
"type": "PushEvent",
"actor": {
...
"login": "paulirish"
},
"repo": {
...
"name": "GoogleChrome/devtools-docs"
},
"payload": {
...
"commits": [
{
...
"message": "fish shell. really liking it.",
"sha": "1f9740c9dd07f166cb4b92ad053b17dbc014145b"
},
...
You can access the author URL as actor and the repository as repo. With this it's easy to construct the relevant links:
...
.forEach(function(item) {
var repoUrl = 'https://github.com/' + item.repo.name;
var authorUrl = 'https://github.com/' + item.actor.login;
item.payload.commits.map(function(commit) {
result.push(store.createRecord('commit', {
authorUrl: authorUrl,
repositoryUrl: repoUrl,
commitUrl: repoUrl + '/commit/' + commit.sha,
message: commit.message
}));
});
})
...
Updated JSBin: http://emberjs.jsbin.com/feyedujulu/1/edit?js,output

Categories