8-bit-sheep / googleAnalyticsR

Use the Google Analytics API from R
https://8-bit-sheep.com/googleAnalyticsR/
Other
259 stars 76 forks source link

ga_adwords_list failing to parse data correctly #322

Open millett-a opened 4 years ago

millett-a commented 4 years ago

What goes wrong

Trying to pull in a list of all the GA adwords accounts connected to a property, and nothing gets returned

Steps to reproduce the problem

I just ran the code with my accountID and proprtyID passed into the function

Expected output

Some sort of table with info about the adwords accounts?

Actual output

Error message: Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 4, 11 Error: API Data failed to parse.
Wrote diagnostic object to 'gar_parse_error.rds', use googleAuthR::gar_debug_parsing('gar_parse_error.rds') to debug the data_parse_function.

Before you run your code, please run:

options(googleAuthR.verbose=2) and copy-paste the console output here.
Check it doesn't include any sensitive info like auth tokens or accountIds - you can usually just edit those out manually and replace with say XXX

'API Data failed to parse' diagnostics

If you have an error starting with:

API Data failed to parse.

remotes::install_github("MarkEdmondson1234/googleAuthR")
googleAuthR::gar_debug_parsing("gar_parse_error.rds")
List of 3
 $ request       :List of 4
  ..$ req_url     : chr "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}/entityAdWordsLinks/"
  ..$ request_type: chr "GET"
  ..$ the_body    : NULL
  ..$ customConfig: NULL
 $ response      :List of 3
  ..$ data_parse_args: list()
  ..$ data_parse_func:function (x)  
  ..$ content        :List of 5
  .. ..$ kind        : chr "analytics#entityAdWordsLinks"
  .. ..$ totalResults: int 4
  .. ..$ startIndex  : int 1
  .. ..$ itemsPerPage: int 1000
  .. ..$ items       :'data.frame': 4 obs. of  7 variables:
  .. .. ..$ id             : chr [1:4] "zyTiEGh5SMm0VXhDz8r14Q" "5lniu7bQSVODuZwtYfcSbw" "GPfKzN44TbqKNZIgJ61FgA" "Eaxnz8hHSRu_ycLwUhESSA"
  .. .. ..$ kind           : chr [1:4] "analytics#entityAdWordsLink" "analytics#entityAdWordsLink" "analytics#entityAdWordsLink" "analytics#entityAdWordsLink"
  .. .. ..$ selfLink       : chr [1:4] "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}/entityAdWords"| __truncated__ "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}/entityAdWords"| __truncated__ "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}/entityAdWords"| __truncated__ "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}/entityAdWords"| __truncated__
  .. .. ..$ entity         :'data.frame':   4 obs. of  1 variable:
  .. .. .. ..$ webPropertyRef:'data.frame': 4 obs. of  6 variables:
  .. .. .. .. ..$ id                   : chr [1:4] "{{PropertyID}}" "{{PropertyID}}" "{{PropertyID}}" "{{PropertyID}}"
  .. .. .. .. ..$ kind                 : chr [1:4] "analytics#webPropertyRef" "analytics#webPropertyRef" "analytics#webPropertyRef" "analytics#webPropertyRef"
  .. .. .. .. ..$ href                 : chr [1:4] "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}" "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}" "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}" "https://www.googleapis.com/analytics/v3/management/accounts/{{AccountID}}/webproperties/{{PropertyID}}"
  .. .. .. .. ..$ accountId            : chr [1:4] "{{AccountID}}" "{{AccountID}}" "{{AccountID}}" "{{AccountID}}"
  .. .. .. .. ..$ internalWebPropertyId: chr [1:4] "{{ViewID}}" "{{ViewID}}" "{{ViewID}}" "{{ViewID}}"
  .. .. .. .. ..$ name                 : chr [1:4] "{{PropertyName}}" "{{PropertyName}}" "{{PropertyName}}" "{{PropertyName}}"
  .. .. ..$ adWordsAccounts:List of 4
  .. .. .. ..$ :'data.frame':   1 obs. of  3 variables:
  .. .. .. .. ..$ kind              : chr "analytics#adWordsAccount"
  .. .. .. .. ..$ customerId        : chr "{{CustomerID1}}"
  .. .. .. .. ..$ autoTaggingEnabled: logi TRUE
  .. .. .. ..$ :'data.frame':   1 obs. of  3 variables:
  .. .. .. .. ..$ kind              : chr "analytics#adWordsAccount"
  .. .. .. .. ..$ customerId        : chr "{{CustomerID2}}"
  .. .. .. .. ..$ autoTaggingEnabled: logi TRUE
  .. .. .. ..$ :'data.frame':   2 obs. of  3 variables:
  .. .. .. .. ..$ kind              : chr [1:2] "analytics#adWordsAccount" "analytics#adWordsAccount"
  .. .. .. .. ..$ customerId        : chr [1:2] "{{CustomerID3}}" "{{CustomerID4}}”
  .. .. .. .. ..$ autoTaggingEnabled: logi [1:2] TRUE TRUE
  .. .. .. ..$ :'data.frame':   7 obs. of  3 variables:
  .. .. .. .. ..$ kind              : chr [1:7] "analytics#adWordsAccount" "analytics#adWordsAccount" "analytics#adWordsAccount" "analytics#adWordsAccount" ...
  .. .. .. .. ..$ customerId        : chr [1:7] "{{CustomerID5}}” "{{CustomerID6}}” "{{CustomerID7}}” "{{CustomerID8}}” ...
  .. .. .. .. ..$ autoTaggingEnabled: logi [1:7] TRUE TRUE TRUE TRUE TRUE TRUE ...
  .. .. ..$ name           : chr [1:4] “{{AdwordsName1}}“ "{{AdwordsName2}}” "{{AdwordsName3}}” "AdWords Link 1 - {{PropertyName}}"
  .. .. ..$ profileIds     :List of 4
  .. .. .. ..$ : chr [1:2] "{{ProfileID1}}" "{{ProfileID2}}"
  .. .. .. ..$ : chr "{{ProfileID1}}"
  .. .. .. ..$ : chr [1:2] "{{ProfileID2}}" "{{ProfileID1}}"
  .. .. .. ..$ : chr [1:2] "{{ProfileID2}}" "{{ProfileID1}}"
 $ authentication:List of 1
  ..$ token:Classes 'Gargle2.0', 'Token2.0', 'Token', 'R6' <Gargle2.0>
  Inherits from: <Token2.0>
  Public:
    app: oauth_app
    cache: function () 
    cache_path: {{error_file_path}}
    can_refresh: function () 
    clone: function (deep = FALSE) 
    credentials: list
    email: {{email}}
    endpoint: oauth_endpoint
    hash: function () 
    init_credentials: function () 
    initialize: function (email = gargle_oauth_email(), app = gargle_app(), package = "gargle", 
    load_from_cache: function () 
    package: googleAnalyticsR
    params: list
    print: function (...) 
    private_key: NULL
    refresh: function () 
    revoke: function () 
    sign: function (method, url) 
    validate: function ()  
 - attr(*, "class")= chr "gar_parse_error"

Session Info

Please run sessionInfo() so we can check what versions of packages you have installed googleAnalyticsR_0.8.0

millett-a commented 4 years ago

Anything I replaced will be marked with {{brackets}}

millett-a commented 4 years ago

I took a look at this, and I think the issue comes from the adwords data having multiple Link Groups, and some of those Link Groups have more than one Linked Accounts. In my example above, I have 4 groups, one group has 7 accounts, one has 2 and the remaining only have one account (for 11 accounts total). I think that's where the error "Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 4, 11" is getting its numbers When I use ga_adwords_list on a property that only has one Link Group, it works fine

millett-a commented 4 years ago

I believe that in the end, the only function I changed was the parse_ga_adwords_list function to be the following:

parse_ga_adwords_list <- function(x){

aaa <- Reduce(bind_rows, x$items$adWordsAccounts) o <- x %>% management_api_parsing("analytics#entityAdWordsLinks")# %>% n.times <- as_vector(lapply(x$items$adWordsAccounts, nrow)) o <- o[rep(seq_len(nrow(o)), n.times),] %>% cbind(aaa) %>% select(-adWordsAccounts, -entity.webPropertyRef.kind, -entity.webPropertyRef.href, -kind)

if(is.null(o)){ return(data.frame()) }

o

}

MarkEdmondson1234 commented 4 years ago

This is great thanks, makes sense it's altering the parsing of that function.

MarkEdmondson1234 commented 4 years ago

Give it a go now with the GitHub dev version

millett-a commented 4 years ago

It's working for all of my use cases. Thanks for adding this into the package!

millett-a commented 4 years ago

We need to check if the adwords info is null sooner (otherwise it breaks seq_len(nrow(o)) parse_ga_adwords_list <- function(x){

aaa <- Reduce(bind_rows, x$items$adWordsAccounts) o <- x %>% management_api_parsing("analytics#entityAdWordsLinks")

if(is.null(o)){ return(data.frame()) }

n.times <- as_vector(lapply(x$items$adWordsAccounts, nrow)) o <- o[rep(seq_len(nrow(o)), n.times),] %>% cbind(aaa) %>% select(-adWordsAccounts, -entity.webPropertyRef.kind, -entity.webPropertyRef.href, -kind)

o

}