Google Analytics API Python Error 403 - Insufficient Permissions - python

I've set my analytics api and credentials, downloaded the client_secrets.json and copied the client_email.
Then, I went to my Google Analytics account > property > view > admin > User Management and added that email as a new user with read permissions.
This went just fine, no error or whatsoever.
Now, when I try to make use of the api via python, i get this error:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://analyticsreporting.googleapis.com/v4/reports:batchGet?alt=json returned "User does not have sufficient permissions for this profile.". Details: "User does not have sufficient permissions for this profile.">
I'm going crazy with this. Don't know what's going on and how to fix it.
Code:
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
KEY_FILE_LOCATION = 'client_secrets.json'
VIEW_ID = 'view_id' #exampe '12341234'
def initialize_analyticsreporting():
credentials = ServiceAccountCredentials.from_json_keyfile_name(
KEY_FILE_LOCATION, SCOPES)
analytics = build('analyticsreporting', 'v4', credentials=credentials)
return analytics
def get_report(analytics):
return analytics.reports().batchGet(
body={
'reportRequests': [
{
'viewId': VIEW_ID,
'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'today'}],
'metrics': [{'expression': 'ga:sessions'}],
'dimensions': [{'name': 'ga:country'}]
}]
}
).execute()
def print_response(response):
"""Parses and prints the Analytics Reporting API V4 response.
Args:
response: An Analytics Reporting API V4 response.
"""
for report in response.get('reports', []):
columnHeader = report.get('columnHeader', {})
dimensionHeaders = columnHeader.get('dimensions', [])
metricHeaders = columnHeader.get('metricHeader', {}).get('metricHeaderEntries', [])
for row in report.get('data', {}).get('rows', []):
dimensions = row.get('dimensions', [])
dateRangeValues = row.get('metrics', [])
for header, dimension in zip(dimensionHeaders, dimensions):
print(header + ': ', dimension)
for i, values in enumerate(dateRangeValues):
print('Date range:', str(i))
for metricHeader, value in zip(metricHeaders, values.get('values')):
print(metricHeader.get('name') + ':', value)
def main():
analytics = initialize_analyticsreporting()
response = get_report(analytics)
print_response(response)
if __name__ == '__main__':
main()
Can someone help me please?
Thanks!

User does not have sufficient permissions for this profile.
Means that the user you are currently authenticating with does not have permissions to access the account you are trying to access.
You need to add the user via the Google analytics admin as you have done. Make sure you added it at the account level.
I would suggest that you double check that you added the correct user email address, and then check that you are using the correct view id.
User doesn't have any google analytics accounts easy solution
You miss typed something.

Related

Getting 'HttpError 401' when attempting to use Google Drive API with delegated credentials

I'm attempting to look at the files for all the users in my org using the Google API in Python. I have a service account with domain-wide delegation. I'm attempting to create delegated credentials for each user so that I can look at their files.
However, when I run the code below, on this line in the for loop:
results = drive_service.files().list(
pageSize=10, fields="").execute()
I get this error:
googleapiclient.errors.HttpError: <HttpError 401 when requesting https://www.googleapis.com/drive/v3/files?pageSize=10&fields=nextPageToken%2C+files%28id%2C+name%29&alt=json returned "Invalid Credentials". Details: "[{'domain': 'global', 'reason': 'authError', 'message': 'Invalid Credentials', 'locationType': 'header', 'location': 'Authorization'}]">
The same line above that does not use delegated credentials works fine, (so I know I have the necessary scopes and the Drive API is enabled) so I think something is wrong with del_creds. I have triple checked that domain wide delegation is enabled. Any help is appreciated!
SCOPES = ['https://www.googleapis.com/auth/admin.directory.user', 'https://www.googleapis.com/auth/admin.directory.user.security', 'https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/drive.readonly']
CREDS = 'service-account-credentials.json'
def main():
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
creds = service_account.Credentials.from_service_account_file(
CREDS, scopes=SCOPES, subject='--my-email--')
service = build('admin', 'directory_v1', credentials=creds)
# Call the Admin SDK Directory API
#print('Getting the first 10 users in the domain')
request = service.users().list(customer='--customer-code--',
orderBy='email')
response = request.execute()
users = response.get('users', [])
while request:
request = service.users().list_next(previous_request=request, previous_response=response)
if request:
response = request.execute()
users.extend(response.get('users', []))
drive_service = build('drive', 'v3', credentials=creds)
results = drive_service.files().list(
pageSize=10, fields="").execute()
items = results.get('files', [])
if not users:
print('No users in the domain.')
else:
for user in users:
email = user['primaryEmail']
del_creds = creds.with_subject(email)
drive_service = build('drive', 'v3', credentials=del_creds)
# Call the Drive v3 API
results = drive_service.files().list(
pageSize=10, fields="").execute()
items = results.get('files', [])
if not items:
print('No files found.')
return
print('Files:')
for item in items:
print(u'{0} ({1})'.format(item['name'], item['id']))
I figured it out. It turns out the first user in the list is suspended, and therefore does not have access to their Google drive files. Other users work just fine.
That begs the question, though, of how I'm supposed to look at the files of suspended users (as I'm pretty sure those files still exist).

How to authorize a Google APIs without user interaction?

I am trying to run automated daily API calls to Google Analytics API
The problem is that when I run the command to establish the connection, a window pops up in my browser
where I have to click to allow the access to my project.
Is there any was to dodge this step, since this step requires a visual interface and action in my browser I cannot seem to automate it to run in the background daily.
Any suggestions?
You need to go into the google cloud console, enable the API, and set up a service account with the proper keys. https://developers.google.com/analytics/devguides/reporting/core/v4/quickstart/service-py
You should look into using a service account. Service accounts are like dummy users, you can preauthorize the service account access to your Google analytics account by taking the service account email address and adding it as a user on the account you wish to access. By doing this the code will not need to be authorized by a user as you are seeing currently.
Service accounts should only be used on accounts that you the developer own, it shouldn't be used to access another user's account, for that you should be using Oauth2.
The official tutorial can be found here Hello Analytics Reporting API v4; Python quickstart for service accounts
"""Hello Analytics Reporting API V4."""
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
KEY_FILE_LOCATION = '<REPLACE_WITH_JSON_FILE>'
VIEW_ID = '<REPLACE_WITH_VIEW_ID>'
def initialize_analyticsreporting():
"""Initializes an Analytics Reporting API V4 service object.
Returns:
An authorized Analytics Reporting API V4 service object.
"""
credentials = ServiceAccountCredentials.from_json_keyfile_name(
KEY_FILE_LOCATION, SCOPES)
# Build the service object.
analytics = build('analyticsreporting', 'v4', credentials=credentials)
return analytics
def get_report(analytics):
"""Queries the Analytics Reporting API V4.
Args:
analytics: An authorized Analytics Reporting API V4 service object.
Returns:
The Analytics Reporting API V4 response.
"""
return analytics.reports().batchGet(
body={
'reportRequests': [
{
'viewId': VIEW_ID,
'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'today'}],
'metrics': [{'expression': 'ga:sessions'}],
'dimensions': [{'name': 'ga:country'}]
}]
}
).execute()
def print_response(response):
"""Parses and prints the Analytics Reporting API V4 response.
Args:
response: An Analytics Reporting API V4 response.
"""
for report in response.get('reports', []):
columnHeader = report.get('columnHeader', {})
dimensionHeaders = columnHeader.get('dimensions', [])
metricHeaders = columnHeader.get('metricHeader', {}).get('metricHeaderEntries', [])
for row in report.get('data', {}).get('rows', []):
dimensions = row.get('dimensions', [])
dateRangeValues = row.get('metrics', [])
for header, dimension in zip(dimensionHeaders, dimensions):
print(header + ': ', dimension)
for i, values in enumerate(dateRangeValues):
print('Date range:', str(i))
for metricHeader, value in zip(metricHeaders, values.get('values')):
print(metricHeader.get('name') + ':', value)
def main():
analytics = initialize_analyticsreporting()
response = get_report(analytics)
print_response(response)
if __name__ == '__main__':
main()
You will need to create Service account credentials on Google developer console the credentials you are using now will not work. Here is a video on How to create Google Oauth2 Service account credentials.
Remember to enable the Google analytics Reporting api under libraries.

Google Analytics fetch view I'd using API

I'm trying to build a support analytics tool which will let the end-user to create a dashboard of his own using data from multiple sources, one such source is Google Analytics. I used Google Analytics Core reporting API to fetch the data. However as of now, I'm manually inserting the view I'd of my user account to fetch the data. Since I'm building it for end users, I need to be able to programmatically(using API) to fetch the view i'd of a user account when they are authorizing my app using oauth. I have seen tools like databox which have achieved this so wondering how to replicate the same. Here's the code snippet I'm using
import argparse
from apiclient.discovery import build
import httplib2
from oauth2client import client
from oauth2client import file
from oauth2client import tools
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
CLIENT_SECRETS_PATH = 'client_secrets.json' # Path to client_secrets.json file.
VIEW_ID = 'xxxxxx' #manually inserted view I'd here
def initialize_analyticsreporting():
"""Initializes the analyticsreporting service object.
Returns:
analytics an authorized analyticsreporting service object.
"""
# Parse command-line arguments.
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[tools.argparser])
flags = parser.parse_args([])
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(
CLIENT_SECRETS_PATH, scope=SCOPES,
message=tools.message_if_missing(CLIENT_SECRETS_PATH))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid run through the native client
# flow. The Storage object will ensure that if successful the good
# credentials will get written back to a file.
storage = file.Storage('analyticsreporting.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=httplib2.Http())
# Build the service object.
analytics = build('analyticsreporting', 'v4', http=http)
return analytics
def get_report(analytics):
# Use the Analytics Service Object to query the Analytics Reporting API V4.
return analytics.reports().batchGet(
body={
'reportRequests': [
{
'viewId': VIEW_ID,
'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'today'}],
'metrics': [{'expression': 'ga:sessions'}]
}]
}
).execute()
def print_response(response):
"""Parses and prints the Analytics Reporting API V4 response"""
for report in response.get('reports', []):
columnHeader = report.get('columnHeader', {})
dimensionHeaders = columnHeader.get('dimensions', [])
metricHeaders = columnHeader.get('metricHeader', {}).get('metricHeaderEntries', [])
rows = report.get('data', {}).get('rows', [])
for row in rows:
dimensions = row.get('dimensions', [])
dateRangeValues = row.get('metrics', [])
for header, dimension in zip(dimensionHeaders, dimensions):
print (header + ': ' + dimension)
for i, values in enumerate(dateRangeValues):
print ('Date range (' + str(i) + ')')
for metricHeader, value in zip(metricHeaders, values.get('values')):
print (metricHeader.get('name') + ': ' + value)
def main():
analytics = initialize_analyticsreporting()
response = get_report(analytics)
print_response(response)
if __name__ == '__main__':
main()
I figured out the answer myself. We have to use Management API to fetch all View Id's of a particular account and pass that as a parameter to core reporting api for getting the metrics/dimensions.

Google Analytics core reporting API, fetch and dump

I'm trying to write a google analytics connector in a lambda function using python to fetch and store all the metrics and dimensions values that the Google Core Reporting API provides. As of now, I'm able to query the individual metrics/dimensions values from the api but unsure how to dump all the data as json as it only returns values which I'm asking for.
"""Hello Analytics Reporting API V4."""
import argparse
from apiclient.discovery import build
import httplib2
from oauth2client import client
from oauth2client import file
from oauth2client import tools
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
CLIENT_SECRETS_PATH = 'client_secrets.json' # Path to client_secrets.json file.
VIEW_ID = 'xxxxxxx'
def initialize_analyticsreporting():
"""Initializes the analyticsreporting service object.
Returns:
analytics an authorized analyticsreporting service object.
"""
# Parse command-line arguments.
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[tools.argparser])
flags = parser.parse_args([])
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(
CLIENT_SECRETS_PATH, scope=SCOPES,
message=tools.message_if_missing(CLIENT_SECRETS_PATH))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid run through the native client
# flow. The Storage object will ensure that if successful the good
# credentials will get written back to a file.
storage = file.Storage('analyticsreporting.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=httplib2.Http())
# Build the service object.
analytics = build('analyticsreporting', 'v4', http=http)
return analytics
def get_report(analytics):
# Use the Analytics Service Object to query the Analytics Reporting API V4.
return analytics.reports().batchGet(
body={
"reportRequests": [
{
"viewId": VIEW_ID,
"metrics": []
}]
}
).execute()
def print_response(response):
"""Parses and prints the Analytics Reporting API V4 response"""
for report in response.get('reports', []):
columnHeader = report.get('columnHeader', {})
dimensionHeaders = columnHeader.get('dimensions', [])
metricHeaders = columnHeader.get('metricHeader', {}).get('metricHeaderEntries', [])
rows = report.get('data', {}).get('rows', [])
for row in rows:
dimensions = row.get('dimensions', [])
dateRangeValues = row.get('metrics', [])
for header, dimension in zip(dimensionHeaders, dimensions):
print (header + ': ' + dimension)
for i, values in enumerate(dateRangeValues):
print ('Date range (' + str(i) + ')')
for metricHeader, value in zip(metricHeaders, values.get('values')):
print (metricHeader.get('name') + ': ' + value)
def main():
analytics = initialize_analyticsreporting()
response = get_report(analytics)
print_response(response)
if __name__ == '__main__':
main()
Existing code snippet for fetching data and the current output it produces
Date range (0)
ga:visits: 6
Instead of this, I'm trying to get all the 500+ metrics that Google Analytics provides.
As of now, I'm able to query the individual metrics/dimensions values
from the api but unsure how to dump all the data as json as it only
returns values which I'm asking for.
Yes that's how the API works: you need to query for specific dimensions and metrics and you only get what you asked for.
I'm trying to get all the 500+ metrics that Google Analytics provides.
Out of the box you can't: GA API limits you to querying 7 dimensions + 10 metrics at a time (see below v3 documentation, same applies to v4):
https://developers.google.com/analytics/devguides/reporting/core/v3/reference#largeDataResults
"allowing a maximum of 7 dimensions and 10 metrics in any one API request"
The workaround is to use a custom dimension as identifier such as User ID + session ID through which you can identify uniquely each session, and thus run multiple API queries to gather more dimensions/metrics, and then re-aggregate the data based on that custom dimension.
Here is a library that explains in more details:
https://github.com/aiqui/ga-download

Making a request to the Google Analtycis API responds with Login Required

I get data from the Google Analytics API v3
https://www.googleapis.com/analytics/v3/data/ga?ids=ga:181335694&metrics=ga:sessions&start-date=7daysAgo&end-date=today
Once I run the browser is throwing an error
{
"error":{
"errors":[
{
"domain":"global",
"reason":"required",
"message":"Login Required",
"locationType":"header",
"location":"Authorization"
}
],
"code":401,
"message":"Login Required"
}
}
How to resolve this error?
Once I run python code I get the Google Analytics api, but I run in browser is throwing error for login is required how to resolve it.
There are two types of data when we are talking about Google APIs.
Public data data that is not owned by anyone and everyone can look at
Private data which is owned by a user and you must have permission to access it.
"Login Required",
Means exactly that you must be authenticated in order to access the data you are trying to access. You need the permission of the owner of that data. You cant just take that get string and kick it off in a browser you need an access token in order to do that. You get an access token from the authentication flow.
Since you mentioned python you should be following the hello analytics tutorial which will show you how to set up your project and authenticate your script so that you can get access to the data you need.
import argparse
from apiclient.discovery import build
import httplib2
from oauth2client import client
from oauth2client import file
from oauth2client import tools
def get_service(api_name, api_version, scope, client_secrets_path):
"""Get a service that communicates to a Google API.
Args:
api_name: string The name of the api to connect to.
api_version: string The api version to connect to.
scope: A list of strings representing the auth scopes to authorize for the
connection.
client_secrets_path: string A path to a valid client secrets file.
Returns:
A service that is connected to the specified API.
"""
# Parse command-line arguments.
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[tools.argparser])
flags = parser.parse_args([])
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(
client_secrets_path, scope=scope,
message=tools.message_if_missing(client_secrets_path))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid run through the native client
# flow. The Storage object will ensure that if successful the good
# credentials will get written back to a file.
storage = file.Storage(api_name + '.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=httplib2.Http())
# Build the service object.
service = build(api_name, api_version, http=http)
return service
def get_first_profile_id(service):
# Use the Analytics service object to get the first profile id.
# Get a list of all Google Analytics accounts for the authorized user.
accounts = service.management().accounts().list().execute()
if accounts.get('items'):
# Get the first Google Analytics account.
account = accounts.get('items')[0].get('id')
# Get a list of all the properties for the first account.
properties = service.management().webproperties().list(
accountId=account).execute()
if properties.get('items'):
# Get the first property id.
property = properties.get('items')[0].get('id')
# Get a list of all views (profiles) for the first property.
profiles = service.management().profiles().list(
accountId=account,
webPropertyId=property).execute()
if profiles.get('items'):
# return the first view (profile) id.
return profiles.get('items')[0].get('id')
return None
def get_results(service, profile_id):
# Use the Analytics Service Object to query the Core Reporting API
# for the number of sessions in the past seven days.
return service.data().ga().get(
ids='ga:' + profile_id,
start_date='7daysAgo',
end_date='today',
metrics='ga:sessions').execute()
def print_results(results):
# Print data nicely for the user.
if results:
print 'View (Profile): %s' % results.get('profileInfo').get('profileName')
print 'Total Sessions: %s' % results.get('rows')[0][0]
else:
print 'No results found'
def main():
# Define the auth scopes to request.
scope = ['https://www.googleapis.com/auth/analytics.readonly']
# Authenticate and construct service.
service = get_service('analytics', 'v3', scope, 'client_secrets.json')
profile = get_first_profile_id(service)
print_results(get_results(service, profile))
if __name__ == '__main__':
main()

Categories