Best practice to discover all website profiles for given account

222 views
Skip to first unread message

RG

unread,
May 10, 2012, 7:10:30 AM5/10/12
to google-analytic...@googlegroups.com
Hi, 

I'm trying to implement a basic setup process where the user of my 
Cocoa app chooses from a drop down list which Google Analytics website 
profile to use based on the Google account they used to sign in. 

What is the best way to discover all website profiles for the user's 
Google account? 


From my understanding I have to run 3 separate queries (using the Objective-C API in this example): 

(1) Query for all management accounts `[GTLQueryAnalytics 
queryForManagementAccountsList]` 

(2) Based on (1), query for all web properties `[GTLQueryAnalytics 
queryForManagementWebpropertiesListWithAccountId:XYZ]` 

(3) Based on (2), query for all website profiles `[GTLQueryAnalytics 
queryForManagementProfilesListWithAccountId:XYZ webPropertyId:ABC]` 

I've implemented 2 + 3 with batch queries. 

Is this the most efficient way to discover all profiles or is there 
another, recommended way? 

Thanks, 
Rico 

Chris Harrington

unread,
May 11, 2012, 8:02:00 AM5/11/12
to Google Analytics Management API
I'd change (3) to be "query all web profiles for account" instead of
"for web property"

J

unread,
May 11, 2012, 11:19:41 AM5/11/12
to google-analytic...@googlegroups.com
Rico,

I had the same requirements and I implemented it the same way you described.  I'd also like to know if this is the best way to do this.

BTW - what are batch queries?

J

RG

unread,
May 16, 2012, 8:18:02 AM5/16/12
to google-analytic...@googlegroups.com
Batch queries are available in the Objective-C api to group several unrelated queries:


However, I'm running into problems when a batch contains 20 or more sub-queries (error "User rate limit exceeded"). I have not been able to solve that problem yet...

-Rico

Eduardo Cereto Carvalho

unread,
May 16, 2012, 5:11:18 PM5/16/12
to google-analytic...@googlegroups.com
I'm sorry I don't know much about Objective-C but you can do one single query to get all that data.

GET https://www.googleapis.com/analytics/v3/management/accounts/~all/webproperties/~all/profiles?pp=1&key={YOUR_API_KEY}
http://code.google.com/apis/explorer/#_s=analytics&_v=v3&_m=management.profiles.list&accountId=~all&webPropertyId=~all 

You can use "~all" for both WebProperties and Accounts and query the profile list api. 

I'm not sure if it's what you're looking for. I hope it's helpfull

Eduardo Cereto Carvalho

J

unread,
Jun 6, 2012, 12:29:49 PM6/6/12
to google-analytic...@googlegroups.com
Eduardo,

I had no idea this was possible.  I'm pretty sure this was undocumented before but I see it now: https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtProfileGuide

This is definitely way more efficient!  

RG - I believe this is what you're looking for.

Thanks again!

J

unread,
Jun 6, 2012, 12:55:08 PM6/6/12
to google-analytic...@googlegroups.com
Upon further testing, this single query actually doesn't work for me because it doesn't return enough information about the account & web property.

For my app, I'm displaying the account hierarchy to the user in a tree like fashion (similar to how Google Analytics displays them):

* Account Name (e.g. "David's Blog")
   |
   ------> Web Property ID - Web Property URL (e.g. "UA-1234567-1 - http://davidblog.com")
               |
               ---------> Profile Name (e.g. "All Traffic")
               |
               ---------> Profile Name (e.g. "USA Traffic")

Unfortunately, the single query only returns the "accountId" and "webPropertyId", which is therefore insufficient if I want to display the tree to the user.

Does anyone know if it's possible to have this single profiles query return account name and web property id/URL?

Nick

unread,
Jun 6, 2012, 1:02:29 PM6/6/12
to google-analytic...@googlegroups.com
Hi,

If you want to get all the account, and webproperty information, then you will have to traverse the entire management hierarchy using multiple queries.

-Nick

J

unread,
Jun 6, 2012, 1:09:33 PM6/6/12
to google-analytic...@googlegroups.com
Damn, that's what I'm doing now and it works fine but it's just not very efficient (user has to wait while I make all of these calls) especially when a user has a lot of accounts/web properties/profiles.

Also, I tend to get the user rate limit error whenever a user has a lot of accounts/web properties/profiles:

Code=[403] Msg=[Quota Error: User Rate Limit Exceeded] Errors=[[{"domain":"global","message":"Quota Error: User Rate Limit Exceeded","reason":"userRateLimitExceeded"}]]

The odd thing is is that if I try again, it usually works the 2nd time.  Any ideas why I'm getting this error?  I'm not supplying "userIp" so therefore user rate limits shouldn't apply to me right?

Nick

unread,
Jun 6, 2012, 1:16:33 PM6/6/12
to google-analytic...@googlegroups.com
Yes,

It might be slower on the first request, but you might try some aggressive client side caching to reduce having to look up all this info in the future.

For example if a user just wants to switch profiles, you should not need to do another API query.
Also if a user wants to switch web properties, you would only need to do 1 query to the profiles end point, to get all the profiles for the new web property.

And then finally you might even consider having a favorite profiles feature where if a user wants to toggle between common profiles, there are no addition API queries,

In terms of quota, bu default, every API (HTTP) request has an IP address. In the APIs console, the default is set to 1qps per IP. So you can up it in the APIs console to a max of 10 per IP.

Hope this helps,
-Nick

Jamie Tsao

unread,
Jun 6, 2012, 1:21:03 PM6/6/12
to google-analytic...@googlegroups.com
Hi Nick,

Thanks for the suggestions.

As for quota, I had no idea that API requests were limited by the QPS setting even if I didn't send the "userIp" param.  Good to know - I'll definitely bump that number up.

Thanks!
Jamie
--
SumAll
Jamie Tsao

J

unread,
Jul 25, 2012, 11:45:45 AM7/25/12
to google-analytic...@googlegroups.com
Hi Nick,

I bumped our QPS setting to 10 (the max) but we're still seeing the "User Rate Limit Exceeded" error.  This usually happens when a customer has a lot of accounts/profiles since our app is making an API call for each entity of the hierarchy.  Your suggestions on caching won't help because this is the initial scenario when the user is trying to connect their GA account for the first time.  We have to retrieve all accounts/webproperties/profiles in order to show them so they can select a profile.

Can a new API endpoint be exposed so that this entire hierarchy is returned in one call.  Individual calls seem very inefficient and is causing these rate limit errors.

Here's an instance from our logs (as you can see, our app is traversing the hierarchy and making API calls but it eventually fails):

Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA accounts. Dur=[153ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA web properties. GAAcct=[616571] Dur=[113ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[616571] GAWebProperty=[UA-616571-34] Dur=[130ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[616571] GAWebProperty=[UA-616571-36] Dur=[161ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[616571] GAWebProperty=[UA-616571-45] Dur=[162ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[616571] GAWebProperty=[UA-616571-48] Dur=[114ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA web properties. GAAcct=[16199019] Dur=[93ms] 
Jul 25 07:19:54 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[16199019] GAWebProperty=[UA-16199019-1] Dur=[63ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA web properties. GAAcct=[19533941] Dur=[79ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[19533941] GAWebProperty=[UA-19533941-2] Dur=[107ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA web properties. GAAcct=[19836368] Dur=[97ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[19836368] GAWebProperty=[UA-19836368-1] Dur=[96ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[19836368] GAWebProperty=[UA-19836368-11] Dur=[105ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[19836368] GAWebProperty=[UA-19836368-2] Dur=[103ms]
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[19836368] GAWebProperty=[UA-19836368-3] Dur=[66ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[19836368] GAWebProperty=[UA-19836368-9] Dur=[103ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA web properties. GAAcct=[26551614] Dur=[94ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA profiles. GAAcct=[26551614] GAWebProperty=[UA-26551614-1] Dur=[90ms] 
Jul 25 07:19:55 localhost S=[App] Env=[prod] T=[play-thread-2] INFO  U=[5008c28ee4b0845436b959cc] ~ Successfully retrieved GA web properties. GAAcct=[26949035] Dur=[88ms] 
Jul 25 07:19:56 localhost S=[App] Env=[prod] T=[play-thread-2] ERROR U=[5008c28ee4b0845436b959cc] ~ Error while invoking GA API: Code=[403] Msg=[Quota Error: User Rate Limit Exceeded] Errors=[[{"domain":"global","message":"Quota Error: User Rate Limit Exceeded","reason":"userRateLimitExceeded"}]] Dur=[95ms] 

J

unread,
Aug 1, 2012, 11:06:41 AM8/1/12
to google-analytic...@googlegroups.com
Can someone from the GA team help with this?

Given the way the API is currently structured, I don't see how I can avoid this problem if I want to display the full list of accounts -> web properties -> profiles to the user (like how Google Analytics does it when you first log in).  

Nick

unread,
Aug 1, 2012, 1:39:59 PM8/1/12
to google-analytic...@googlegroups.com
Hi,

So you probably should not display the entire list of web properties and profiles. It doesn't really make sense to make 100's of queries for a person to only select 1 value.

Best case scenario is you query for all the users accounts. They select an account, which then runs a query for all the web properties of that account. They select a web property which then runs a query for all the profiles for that web property.

You can then save all the names + IDs and reuse them in the future so the user doesn't have to reselect.

-Nick
Jamie
Reply all
Reply to author
Forward
0 new messages