I wanted to bring statistics from Firebase to my website. To do this, I linked Firebase with Google Analytics in the settings in the "Integrations" tab
From there I copied the Property ID
Enabled Google Analytics Data API in my project
Then I replaced the Property ID with my own in this script and ran the script.
But I got an error:
Unable to detect a Project Id in the current environment. To learn more about authentication and Google APIs, visit:https://cloud.google.com/docs/authentication/getting-started
I suspect the issue is that you have not configured GOOGLE_APPLICATION_CREDENTIALS
You should be following the API Quickstart it shows how to configure the credentials needed to authorize this code.
Once your authorization is configured you should be able to access this. Remember that the service account needs to be granted access to your google analytics account or it wont be able to access the property.
/**
* TODO(developer): Uncomment this variable and replace with your
* Google Analytics 4 property ID before running the sample.
*/
// propertyId = 'YOUR-GA4-PROPERTY-ID';
// Imports the Google Analytics Data API client library.
const {BetaAnalyticsDataClient} = require('#google-analytics/data');
// Using a default constructor instructs the client to use the credentials
// specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
const analyticsDataClient = new BetaAnalyticsDataClient();
// Runs a simple report.
async function runReport() {
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{
startDate: '2020-03-31',
endDate: 'today',
},
],
dimensions: [
{
name: 'city',
},
],
metrics: [
{
name: 'activeUsers',
},
],
});
console.log('Report result:');
response.rows.forEach(row => {
console.log(row.dimensionValues[0], row.metricValues[0]);
});
}
runReport();
Related
I'm trying to follow this document to setup Stripe Connect: https://stripe.com/docs/connect/enable-payment-acceptance-guide?platform=web&ui=checkout#create-account-link
At the account link phase it redirects me to Stripe for creating an account etc - for development purposes I would like to skip this instead of entering real data every time.
I came accross this document for testing Stripe: https://stripe.com/docs/connect/testing
It says there is a way to force skip but I don't see anything pop up. Is there a special value I need to pass in to enable the force skip option?
Here are the code snippets I've been using to test account linking
const stripe = new Stripe(secrets.STRIPE_SECRET_KEY, {
apiVersion: "2022-11-15"
});
export class StripeClient {
/**
* Create a Stripe account for a user. The account will be associated with the ZCal account
*/
static accountCreationRequest = async (): Promise<Stripe.Response<Stripe.Account>> => {
const account: Stripe.Response<Stripe.Account> = await stripe.accounts.create({
type: "standard"
});
return account;
};
static accountLinkRequest = async (stripeAccountId: string): Promise<Stripe.Response<Stripe.AccountLink>> => {
const accountLink: Stripe.Response<Stripe.AccountLink> = await stripe.accountLinks.create({
account: stripeAccountId,
refresh_url: `${config.CLIENT_BASE_URL}/account/integrations`,
return_url: `${config.CLIENT_BASE_URL}/account/integrations`,
type: "account_onboarding"
});
return accountLink;
};
}
The "force skip" line on testing Doc is for OAuth flow, which is unrelated to your Onboarding flow, so first let's ignore it.
When you make your first request to create the account, you can prefill as much information as you want, and it will be automatically populated in the flow later. Here is the full list of fillable fields.
You can pre-fill any information on the account, including personal
and business information, external account information, and more.
Can anyone indicate the right settings to give allow a service account access to a Google calendar?
We have a node.js project that is meant to provide access to the Google calendars it has been given access to, but we can't work out why it can't see the calendars.
At the same time, we were able to trying a different account that has been working in another environment and this worked, but the problem is that no one who previously worked on the project has access to the configuration for it to compare.
The response.data we are getting with the problem account:
{
"kind": "calendar#calendarList",
"etag": "\"p33k9lxxjsrxxa0g\"",
"nextSyncToken": "COias9Pm4vUCEjxvdGurdXRob24tZGV2LXNlcnZpY2UxQG90YxxxdGhvbi1kZXYuaWFtLmdzZXJ2aWNlYWNxb3VudC5jb20=",
"items": []
}
Either way this would suggest the issue is with the configuration of the service account, rather than the code itself, but will share the code anyhow:
import { Auth, calendar_v3 as calendarV3 } from 'googleapis';
const Calendar = calendarV3.Calendar;
async getCalendarApi () {
const jwtClient = new Auth.JWT(
this.keyConfig.clientEmail,
undefined,
this.keyConfig.privateKey.replace(/\\n/g, '\n'),
[
'https://www.googleapis.com/auth/calendar.readonly',
'https://www.googleapis.com/auth/calendar.events'
]
);
const calendarApi = new Calendar({
auth: jwtClient
});
await jwtClient.authorize();
return calendarApi;
}
async init () {
// loads the configuration from our app's configuration file
this.keyConfig = getKeyConfig('google-calendar');
const calendarApi = await this.getCalendarApi();
const response = await calendarApi.calendarList.list();
console.log(JSON.stringify(response.data, undefined, 2));
}
As for the service account, in the Google console, this is the how it was set up:
Open up https://console.cloud.google.com/
Select the appropriate project at the top
Search for 'Google Calendar API' in the search bar
Validate it is enabled
Click 'Manage', which takes me to https://console.cloud.google.com/apis/api/calendar-json.googleapis.com/metrics?project=xxxxxx ('xxxxxx' is the project id, but masked here)
Click on 'Credentials
Click on 'Create Credentials' at the top and select 'service account'
Provide a name of the service account
Click 'Create and Continue'
Add a role: Basic -> Viewer
Click 'Done'
In the 'Credentials' page (https://console.cloud.google.com/apis/credentials?project=xxxxxx) click edit for the account we just created
In the 'keys' section: Add key -> Create New Key and then specify JSON
From the above steps we take the client_email and the private_key field values to user with our nodejs app.
Then in the calendar we want it to access, we add the email address of the service account as a viewer.
Trying all the above still results in the list of calendars visible by the service account to be empty.
Any ideas?
From your explanation and the returned value, I'm worried that in your situation, you might have never inserted the shared Calendar with the service account. If my understanding is correct, how about the following modification?
Modification points:
Insert the shared Calendar to the service account.
In this case, please modify the scope https://www.googleapis.com/auth/calendar.readonly to https://www.googleapis.com/auth/calendar.
async init () {
// loads the configuration from our app's configuration file
this.keyConfig = getKeyConfig('google-calendar');
const calendarApi = await this.getCalendarApi();
const response = await calendarApi.calendarList.insert({resource: {id: "####group.calendar.google.com"}}); // Please set the Calendar ID here. Or {requestBody: {id: "####group.calendar.google.com"}}
console.log(JSON.stringify(response.data, undefined, 2));
}
Retrieve the calendar list using your script.
After the Calendar was inserted to the service account using the above script, you can obtain the shared Calendar in the Calendar list.
Reference:
CalendarList: insert
I'm using normal Gmail account and I have completed all the configuration related to Service account and Enable APIS on cloud.
In order to authorised request I'm using jwt method.
Simple google calendar event gets inserted but when I try to modify event data for google meeting link and attendees.
It throws an error.
My system flow is like , On backend (Nodejs) crone job is running and create Event for calendar.
const CREDENTIALS = require('../../../calendar-meet-auth.json')
// Calendar scope for accessing
const CALENDAR_SCOPE = ['https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.events']
const calendar = google.calendar({ version: "v3" });
const calendarId = CREDENTIALS.calendarId;
// In order to authorized, each request from app
const auth = new google.auth.JWT(
CREDENTIALS.client_email,
null,
CREDENTIALS.private_key,
CALENDAR_SCOPE
);
// Event for Google Calendar
let event = {
'summary': `This is Test meeting scheduling with google meeting link`,
'description': `Please confirm.`,
attendees: [
{ email: 'abc#gmail.com' }
],
conferenceData: {
createRequest: {
requestId: getRandomString(),
conferenceSolutionKey: { type: "hangoutsMeet" },
},
},
'start': {
'dateTime': dateTime['start'],
'timeZone': 'Asia/Kolkata'
},
'end': {
'dateTime': dateTime['end'],
'timeZone': 'Asia/Kolkata'
},
// 'reminders': {
// 'useDefault': true,
// 'overrides': [
// { 'method': 'email', 'minutes': 24 * 60 },
// { 'method': 'popup', 'minutes': 10 },
// ],
// }
};
When it tries to add event , It throws error like .
Error: Service accounts cannot invite attendees without Domain-Wide Delegation of Authority..
Are there any alternatives ways to create Event with Google meet except Gsuit or Google workplace ?
There does not seem to be an issue with the event payload itself.
However, service accounts are not meant to interact with products as other types of users do. Some usage restrictions within Google APIs while authenticated as the service account (without impersonation) are indeed expected.
In the Calendar API case, the caller of the insert method will be the creator/organizer of that event. Therefore the creator/organizer of the event will be the authenticated account.
According to the error returned, it seems that the caller is indeed a service account (without impersonation)
Since using Workspace isn’t an option, you won’t be able to impersonate another managed user with Domain wide delegation.
Depending on your use case, an alternative would be to authenticate as an end user and create the event inviting the other gmail account as your sample code does.
If you decide to do that, refer to this page to create/generate new credentials in your GCP project.
Check out the Calendar quickstart for additional info as well
I want to run a google analytics report using runReport.
I have followed the instructions at https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart-client-libraries and made a copy of the code that uses json-credentials at https://github.com/googleapis/nodejs-analytics-data/blob/main/samples/quickstart_json_credentials.js
I have one Analytics Account with two Properties & Apps - DEV and STAGE.
In each of them I have created a service account with OWNER permissions. After that I created a key and downloaded the generated JSON-file.
I can test and run the API from the "Try this API" link at https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/properties/runReport for both my properties and it works well for both of them. (But then I use OAuth authentication of course).
However when I run the code using the JSON-credentials the DEV always work. The STAGE always fails. I have tried running the code both from my machine as well as from https://shell.cloud.google.com/ with the same result.
The failure message is:
7 PERMISSION_DENIED: User does not have sufficient permissions for this property. To learn more about Property ID, see https://developers.google.com/analytics/devguides/reporting/data/v1/property-id.
I have checked several times that the DEV and STAGE properties are correct and that the I use the JSON-credentials file associated with the correct property.
In STAGE, where calls always fail I have several times created new service accounts (with Basic->Owner credentials), created keys and downloaded JSON-credentials. But all with the same result. STAGE always fails.
I have compared the permissions for the service accounts in DEV and STAGE and they seems to be identical.
I have read and tried tips from other people with "permission denied" issues here at stack overflow but none that solves my issue.
Are there any authorization logs that I read from google console?
I'm kind of stuck now.
The code I run (properties and file name obfuscated):
"use strict";
function main(propertyId = "YOUR-GA4-PROPERTY-ID", credentialsJsonPath = "") {
propertyId = "27..DEV property";
credentialsJsonPath = "./DEVcredentials.json";
// propertyId = "27..STAGE property";
// credentialsJsonPath = "./STAGEcredentials.json";
const { BetaAnalyticsDataClient } = require("#google-analytics/data");
const analyticsDataClient = new BetaAnalyticsDataClient({
keyFilename: credentialsJsonPath,
});
async function runReport() {
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{
startDate: "2020-03-31",
endDate: "today",
},
],
dimensions: [
{
name: "country",
},
],
metrics: [
{
name: "activeUsers",
},
],
});
console.log("Report result:");
response.rows.forEach((row) => {
console.log(row.dimensionValues[0], row.metricValues[0]);
});
}
runReport();
}
process.on("unhandledRejection", (err) => {
console.error(err.message);
process.exitCode = 1;
});
main(...process.argv.slice(2));
User does not have sufficient permissions for this property.
Means that the user who you have authenticated with does not have permissions to access that view. In this case we are talking about properties/${propertyId}
If you are using a service account make sure to grant it permissions at the account level not the view level.
Permissions need to be granted thorough the google analytics website in the admin section
I am using a cloud function written in node.js to list projects this is the index.js file containing the method, When I trigger this function I am getting only 1 project printed. ProjectA -> the cloud function also resides in ProjectA, I have another ProjectB which is not getting printed which is also in ACTIVE mode. I have owner permission for both the projects.
const {Resource} = require('#google-cloud/resource');
const resource = new Resource();
async function getProjects() {
try {
// Lists all current projects
const [projects] = await resource.getProjects();
console.log(`success in getProjects() call`);
// Set a uniform endTime for all the resulting messages
const endTime = new Date();
const endTimeStr = endTime.toISOString();
// sample 2019-11-12T17:58:26.068483Z
for (var i=0; i<projects.length;i++) {
console.log("Total Projects ",projects.length) //Printing as 1 instead of correct 2
// Only publish messages for active projects
if (projects[i]["metadata"]["lifecycleState"] === config.ACTIVE) {
// Construct a Pub/Sub message
console.log(`About to send Pub/Sub message ${projects[i]}}`);
const pubsubMessage = {
"token": config.METRIC_EXPORT_PUBSUB_VERIFICATION_TOKEN,
"project_id": projects[i]["id"],
"end_time": endTimeStr
}
}
}
} catch(err) {
console.error("Error in getProjects()");
console.error(err);
throw err;
}
}
However if i try the google api link
https://cloud.google.com/resource-manager/reference/rest/v1/projects/list#try-it
I am getting 2 projects as response which i have access to.
When you execute a Cloud Function you choose a service account that will execute it, normally it's the "App Engine default service account (project-id#appspot.gserviceaccount.com), that service account should have the "Project Owner" role.
The API call from the API explorer uses an API key that it's tied to your user account no the service account used to execute the Cloud Functions, that's why it shows you all your projects.
To fix your issue just add the service account, that you're using to execute the Cloud Function, to all your Projects with the Project Owner role, although other roles (like Project Viewer) are enough to list it.