[wp_ad_camp_5]
Would you like to connect to a Google API using a service account with PHP? You have come to the right place, in this tutorial we are going to go though the steps needed to connect to the Google Analytics API with a service account.
Accessing the Google APIs using a service account is quite useful. Some times you just want to access your own data and not data owned by other users. In this instance there is no reason to use OAuth2 and prompt a user to give you access to there information, its your information you already have access. This is why we use a service account. This tutorial uses the Google Analytics API to walk you though the steps of creating a service account and how to then access your GA data with it.
Contents
What is a Service Account.
A service account will allow your application to access your Google Analytics data without prompting a user for access. A service account is essentially Oauth1. Oauth2 is when a user is prompted to give your application permission to use it. If you are going to only be access your own data then you should be using a Service Account. If you want to access data owned by another user then you should be using Oauth2 and looking at a different tutorial. You can find it here Google Oauth2 PHP
PHP client library
In this tutorial we will be using the newest version of the Google Client library for PHP it can be found on Github. The google-api-php-client client library is updated regularly whenever anything changes. You will need to copy the entire src/Google directory to the directory of your application. I don’t recommend only taking the files that you need unless you really know what you are doing.
Google Developers Console
Before you can access any of the Google APIs you need to first create your application in the Google Developers console. I have a separate tutorial that goes though the steps of creating an application on the Google Developers console you can find it here. Google Cloud Console Once you have completed the basic set up including selecting which API that you want to access. For this tutorial we will be using Google Analytics. Make sure you have filed in both an Email Address and a product name under the consent screen or it wont work.
Creating Service Account
On the Credentials screen you will see a button that says Create new clientid, click on it. In the popup window selected the “Service account” radio button. A file will begin to download you will need this file later. Copy the Email Address that was created for you it should look something like this: 1046123799103-nk421gjc2v8mlr2qnmmqaak04ntb1dbp@developer.gserviceaccount.com
Granting Access
A service account doesn’t need to prompt a user for access because you have to set it up. Go to the Google Analytics website in the Admin section for the Account you want to retrieve data from. This is very important it must be at the account level add this email address as a new user. just give them read access.
The Code
Conclusion
Using a service account to access your Google Analytics data can be every useful if you would like to store some of your data on your system for further processing. By using a service account you remove the need to prompt a user to give your application access, as long as the application email has access in the Google Analytics account this script will with no need for user intervention. You can see this in action at Google Analytics Reporting API
it shows this error every time
Error refreshing the OAuth2 token, message: ‘{ “error” : “invalid_grant” }
plz help me out
it was NTP problem, Solved
I am having the same problem. can you elaborate on how you fixed the NTP problem. I have been banging my head against this for hours.
Assuming you are on a linux server NTP demon should be running if its not restart it.
I fixed my time issue by declaring the timezone for php by putting the following string before the requre_once includes.
date_default_timezone_set(“America/New_York”);
see the php documentation for a complete list of timezones.
http://us3.php.net/manual/en/timezones.america.php
Hi Linda
I read your post, but this does not work anymore! Returns errors as
Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Error refreshing the OAuth2 token, message: ‘{ “error” : “invalid_grant” }” in /Applications/MAMP/htdocs/Google/Google/Auth/OAuth2.php:327 Stack trace: #0 /Applications/MAMP/htdocs/Google/Google/Auth/OAuth2.php(289): Google_Auth_OAuth2->refreshTokenRequest(Array) #1 /Applications/MAMP/htdocs/Google/test.php(26): Google_Auth_OAuth2->refreshTokenWithAssertion(Object(Google_Auth_AssertionCredentials)) #2 {main} thrown in /Applications/MAMP/htdocs/Google/Google/Auth/OAuth2.php on line 327
I think google does not allow to get results without accessing from the browser.
Could you please anything?
Thanks
Umesh
This is brilliant. I have been looking for an answer to get non-permission stats into an admin area for a while now and this works great. I had to modify slightly as I am using an oop MVC framework.
How would i go about gettin say daily results for last 30 days as well?
I am running a jquery plugin morrischarts which has the ability to draw nice line charts for sales figures so i could convert an array of daily hits to the chart.
Many thanks.
You can set the start date to say 30daysAgo and the end date to yesterday. check the documentation on start date and end date Query Parameters Summary
Many thanks again.
This is the code i came up with and it produces a me 2 line charts one with sessions vs users and one with page views as well as total results for pageviews, sessions,users and bounce rate. I encode the data and place inside my morris line charts javascript to produce a nice overview dashboard.
//calulating start date
$gaenddate = date(‘Y-m-d’,strtotime(‘-1 day’));
$gastartdate = date(‘Y-m-d’,strtotime(‘-31 days’));
//Adding Dimensions
$params = array(
‘dimensions’ => ‘ga:userType,ga:date’,
‘sort’ => ‘ga:date’
);
// requesting the data
$data[‘ga’] = $service->data_ga->get(“ga:”.$ganumber, $gastartdate, $gaenddate, “ga:sessions,ga:pageViews,ga:users,ga:bounceRate”, $params );
I have
Warning: file_get_contents(AIzaSyDZIHgXYxV0qLOwSOc2asYzrD14DFvsbic-privatekey.p12): failed to open stream: No such file or directory in C:\wamp\www\GoogleClientApi\googleapitest.php on line 24
and
Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Unable to parse the p12 file. Is this a .p12 file? Is the password correct? OpenSSL error: ‘ in C:\wamp\www\GoogleClientApi\src\Google\Signer\P12.php on line 51
error in localhost.
you need to give it the full directory path to your key file. c:\AIzaSyDZIHgXYxV0qLOwSOc2asYzrD14DFvsbic-privatekey.p12
I tried executing the code locally, I got this error:
Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Unable to load private key’ in /var/www/html/gaoauth/Google/Signer/P12.php:70 Stack trace: #0 /var/www/html/gaoauth/Google/Auth/AssertionCredentials.php(130): Google_Signer_P12->__construct(‘{? “private_ke…’, ‘notasecret’) #1 /var/www/html/gaoauth/Google/Auth/AssertionCredentials.php(107): Google_Auth_AssertionCredentials->makeSignedJwt(Array) #2 /var/www/html/gaoauth/Google/Auth/OAuth2.php(306): Google_Auth_AssertionCredentials->generateAssertion() #3 /var/www/html/gaoauth/index.php(35): Google_Auth_OAuth2->refreshTokenWithAssertion(Object(Google_Auth_AssertionCredentials)) #4 {main} thrown in /var/www/html/gaoauth/Google/Signer/P12.php on line 70
are you sure you are using my code? my code doesn’t use makeSignedJwt. Either way take your code and post it to Stackoverflow.com.
Solved it, thanks, I had to download the p12 key file, after creating a new client id. Thanks for these awesome tutorials once again. 🙂
I’ve had the same problem as you,
Check if your path is good and also if your p12 file has read permission only.
Please anyone help me its urgent and mail me the code on my email id for fetching the data from google analytic regarding the calculating the numbers of view of my side
Hello all,
Thank’s for this tutorial.
How can I download the p12 file ? I don’t understand what you mean by [Location of key file]…
OK
I have found the solution of my problem, sorry…
P12 file is downloaded from the Google Developer console. You save it on your machine some place so that your script can access it.
Hi Linda,
I had just asked a question where you gave me reply to follow this tutorial, will if am stuck in getting this error when running locally:
Fatal error: Uncaught exception ‘Google_IO_Exception’ with message ‘HTTP Error: Unable to connect: ‘fopen(compress.zlib://https://www.googleapis.com/analytics/v3/data/ga?ids=ga%3A89798036&start-date=2014-12-14&end-date=2014-12-14&metrics=ga%3Ausers%2Cga%3Asessions&dimensions=ga%3AuserType): …….
Can you please guide me, where I am failing to do something.
Thanks,
Sharad Soni
Hi Linda,
I have solved the issue by adding the following line:
$client->setClassConfig(“Google_Http_Request”, “disable_gzip”, true);
I don’t know is it a good practice to disable the gzip or not but it worked.
Secondly, I would like to add some validation on iterating the rows:
if (is_array($data->getRows()) || is_object($data->getRows())) {
foreach ($data->getRows() as $row) {
print “”.$row[0].””.$row[1].””.$row[2].””;
}
}
Wrapped under if condition, as if it returns no rows in my case (date was not proper) there should not be any error.
You can disable it if you want I dont think it will hurt anything. I just wonder why you are having problems with it. I have never seen that error before.
I would check your fire wall to make sure your not blocking Googles servers. That looks like an issue with the client library.
Hi Linda!
Thanks for tutorial! But I have a problem :
I have a lot of accounts in GA, where I am just a watcher, not admin. So I can’t grant access to my service account email. How can I get stats from this accounts?
Thank you!
Then you cant use a service account. You will need to use Oauth2.
A service account email address has to be added to the Account though the Google Analytics Website, if you don’t own the account you cant add it. You could try and contact the owner see if they are willing to add it for you.
Hi. I’ve run into three (probably noob) questions that i didn’t see addressed in the comments so far:
1. Double checking that the src/Google folder should just be copied and included right along with my plugin files. Is that right? It doesn’t need to be saved on the server? or loaded into a php library or some such?
2. How do I save the key outside the web root? i can place it outside public_html, but then how do I write the address to link to it? in the other examples in the comments, you have “c:” as the start to this, does that mean that i should keep it stored locally on my machine? how would i use my script from other machines?
3. How are people accessing the error codes? do these appear in console or on the site directly if something is broken?
I very much appreciate your help!
Defiantly not noob questions 🙂
Thanks! by error code i’m referring to all the “FATAL ERROR” and “WARNING” messages that people are referencing in the comments. My script just causes the content of my page to disappear and i get no clue about what went wrong. Makes it super tough to troubleshoot.
I was able to find the error messages in the error_log.
I am still running into a 403 (user does not have sufficient permissions) error and wonder if I need to change the ga number in this line:
$data = $service->data_ga->get(“ga:89798036”, “2014-12-14”, “2014-12-14”, “ga:users,ga:sessions”, $params );
Is that ‘89798036’ specific to your google analytics request? Should i change it for my request?
thanks!
That was exactly my problem. switched “ga:89798036” to “ga:MyViewID” and everything worked like a charm. thanks!
Hi Linda can you help me?:
Fatal error: Uncaught exception ‘Google_Cache_Exception’ with message ‘Could not create storage directory: /tmp/Google_Client/84’ in /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php:154
Stack trace:
#0 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php(139): Google_Cache_File->getCacheDir(‘3eba0df1a8a7011…’, true)
#1 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php(134): Google_Cache_File->getCacheFile(‘3eba0df1a8a7011…’, true)
#2 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php(95): Google_Cache_File->getWriteableCacheFile(‘3eba0df1a8a7011…’)
#3 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Auth/OAuth2.php(322): Google_Cache_File->set(‘3eba0df1a8a7011…’, ‘{“access_token”…’)
#4 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/index in /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php on line 154
(update 27.11.2015) Sorry Linda but from GIT HUB i cant find anymore the autoload.php file?!
Thanks for the heads up. It looks like they have either removed it or moved it. I haven’t been able to find it either. There examples are just pointing to
Which doesn’t appear to exist either. In the attempt to save some time I added an issue request where is autoload.php? #716
Apperntly we need to grab the v1-master branch not the master branch.
https://github.com/google/google-api-php-client/tree/v1-master/src/Google
Hi Linda,
I got an error that /autoload.php couldn’t be found. I found it somewhere in github and put it in the right directory, but now it gives me:
PHP Fatal error: Class ‘GuzzleHttp\Collection’ not found in /usr/lib/php/google-api-php-client/src/Google/Client.php on line 93
I’m wondering what’s up. I thought I had the very latest version of the api, so why aren’t things working?
They have made a change to use composer. you need to grab https://github.com/google/google-api-php-client/tree/v1-master to find the autoload.php file.
Hi Linda,
Impossible to make it work.
I have all step up, but i get a white page as result (Internal Error 500).
I have set the p12 path like this :
$key_file_location = ‘/var/www/vhosts/domain.fr/httpdocs/mydirtest/Leadomatic-v2-88952f987f74.p12’;
Is that ok?
path looks fine to me. Internal server error normall means there is something wrong on googles side. Try making a different request.
Hi Linda can you help me please?:
I just seem to get a Server error 500 when I run the code.
Could this be my server? I’m not sure whats missing.
Hi Linda
My aim is to fetch all my labels(INBOX, SENT, SPAM etc) and mail count in corresponding labels.
I created a service account. But i want to get all my labels from abin.john@altd.in mail. The following is my code
type) && $data->type == ‘service_account’) {
$user_to_impersonate = ‘abin.john@altd.in’;
$cred = new Google_Auth_AssertionCredentials(
$Email_address, // it’s the client email
array(‘https://www.googleapis.com/auth/gmail.readonly’, ‘https://www.googleapis.com/auth/drive’), // it’s google gmail scope
$data->private_key, // here is the private key
‘notasecret’,
‘http://oauth.net/grant_type/jwt/1.0/bearer’,
$user_to_impersonate
);
}
$client = new Google_Client();
$client->setAssertionCredentials($cred);
if (!$client->getAuth()->isAccessTokenExpired()) {
return false;
}
else {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service_token = json_decode($client->getAccessToken());
$drive_service = new Google_Service_Drive($client);
$files_list = $drive_service->files->listFiles(array())->getItems();
$service = new Google_Service_Gmail($client);
// Print the labels in the user’s account.
$results = $service->users_labels->listUsersLabels();
echo “”;print_r($results);exit;
it shows an error
Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Error refreshing the OAuth2 token, message: ‘ in /var/www/teletracker/files/google_service_account/google-api-php-client-1.1.7/src/Google/Auth/OAuth2.php on line 364
Google_Auth_Exception: Error refreshing the OAuth2 token, message: ‘{ “error” : “unauthorized_client”, “error_description” : “Unauthorized client or scope in request.” }’ in /var/www/teletracker/files/google_service_account/google-api-php-client-1.1.7/src/Google/Auth/OAuth2.php on line 364
Could you please help me?
Unfortunately i cant be much help i have never gotten service accounts and gmail to work
That’s depressing. I’m trying to do something similar to Abin John and cannot get it working either. Anyone else out there able to get service accounts and gmail to work?
I have never gotten it to work.
That’s depressing. I’m trying to do something similar to Abin John and cannot get it working either. Anyone else out there able to get service accounts and gmail to work? Okay – spent a little more time on this and actually got gmail api working with a service account today! i wrote up a bit about it in case anyone is interested: http://sahmwebdesign.com/gmail-api-via-service-accounts/
Hi Linda Lawton ! nice stuff
I’m run cron job for play store particular app review. So we need require service account to getting app review ? because i’m trying to get using https://www.googleapis.com/androidpublisher/v2/applications/your_package_name/reviews?
access_token=your_auth_token but give error ‘Login Required’ …pls suggest thanks !!!
I am not sure that service accounts work with google play serves api. You are going to have to pre authorize it some how and its not something i have access to so i cant test it.
You might want to try asking on Stackoverflow.com for help
Hello,
I’ve created a web-site where every user can upload documents that are automatically loaded into a specific google drive space for each user, without needing to enter credentials every time. The gmail user of each user must already exist or I create it for the occasion, but it must be accessible through a graphical interface. Therefore, I use the google drive APIs and create, for each user, a service account and the credentials needed to connect to the existing user to load the files in this drive space.
There is an initial page where the user confirms, once, at the beginning, the project (website)’s access to the user. It runs one time and then never again. This is the code:
//PAGE 1
define(‘DRIVE_SCOPE’, ‘https://www.googleapis.com/auth/drive’);
$redirect_uri = ‘http://’ . $_SERVER[‘HTTP_HOST’] . $_SERVER[‘PHP_SELF’];
session_start();
$auth_file = “path of client_secret_xxxxxxx.json”;
$client = new Google_Client();
$client->setAuthConfig($auth_file);
$client->setRedirectUri($redirect_uri);
$client->setIncludeGrantedScopes(true);
$client->addScope(DRIVE_SCOPE);
$service = new Google_Service_Drive($client);
if (isset($_GET[‘code’])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET[‘code’]);
$client->setAccessToken($token);
// store in the session also
$_SESSION[‘upload_token’] = $token;
// redirect back to the example
//header(‘Location: ‘ . filter_var($redirect_uri, FILTER_SANITIZE_URL));
exit(“Authentication made!”);
}
// set the access token as part of the client
if (!empty($_SESSION[‘upload_token’])) {
$client->setAccessToken($_SESSION[‘upload_token’]);
if ($client->isAccessTokenExpired()) {
unset($_SESSION[‘upload_token’]);
}
else {
$authUrl = $client->createAuthUrl();
}
if (isset($authUrl))
header(‘Location: ‘ . filter_var($authUrl, FILTER_SANITIZE_URL));
Then there is a page I call when I want to do an operation of any kind: upload, download, read, etc. This is the authentication code that runs before the operation:
//PAGE 2
define(‘DRIVE_SCOPE’, ‘https://www.googleapis.com/auth/drive’);
$email = “gmail account of user”
$client = new Google_Client();
// set the scope(s) that will be used
$client->addScope(DRIVE_SCOPE);
// this is needed only if you need to perform
// domain-wide admin actions, and this must be
// an admin account on the domain; it is not
// necessary in your example but provided for others
$client->setSubject($email);
// set the authorization configuration using the 2.0 style
$auth_file = “path of service-account.json”;
$client->setAuthConfig($auth_file);
Until recently it worked regularly, I created several users like this! It still works for users already created!
For some time now, when I create a new user:
– when I run the authentication page, I get an error:
Error: invalid_scope
You don’t have permission to access some scopes. Your project is trying to access scopes that need to go through the verification process. {invalid = [https://www.googleapis.com/auth/drive]} If you need to use one of these scopes, submit a verification request.
If I join the “Risky Apps” group, this problem resolves, but not what follows.
– When I try to do any operation on the drive, page 2 authentication does not return any error, but when it comes to perform the specific operation, even a simple “file list”, I get the following error:
{“Error”: “unauthorized_client”, “error_description”: “Client is unauthorized to retrieve access tokens using this method.” }
In short, I can not do anything on the gmail user drive.
I found that if, on page2, comment the line “$client->setSubject ($email);” or I put the service account mail address, the procedure works, but it works in the service account drive, not in the gmail account.
I would like the procedure to work and work in an existing gmail account, as it did before! Definitely Google has introduced some changes … Is this something that can be solved?
Thank you.
You need to go though the verification process for your application before you are going to be able to use it for anything other than your own gmail account.
Hi Linda,
Thanks for the tutorial.
Does it work the similar way for creating/updating contacts using service account. I could find only one tutorial for this and that’s not working either. It’s giving me a bad request error.
Here’s the link to that tutorial comment that I’ve posted.
https://www.webfoobar.com/index.php/node/75#comment-198
Do you happen to know how to work this around for contacts API.? It’d be really helpful.
Thanks
Remember a service account is not you. So if it did work you would only be adding contacts to the Service accounts google contacts account. There is no way to share permissions to your personal Google contacts account so service accounts do not work with this api.
You will need to go though Oauth2.
Hi ,
what is ‘Location of key file’ here? i have multiple sheets in one google spreadsheet (e.g. sheet1, sheet2, sheet3,….). so, what is the solution of this problem.
Please help me out.
keyfile is the file that you download from Google developer console. It has nothing to do with the sheets within a Google sheet that your going to have to check the api documentation for.
Hi
I am using v 2.2.1 for google-api-php-client and i am getting below error, do i have to declare any class, and how?
Fatal error: Class ‘Google_Auth_AssertionCredentials’ not found in \google-api-php-client-master\test.php on line 28
Please let me know , how to fix this?
I would post a question on stack overflow showing your code someone should be able to help