google_analytics_v4_api 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +65 -6
- data/lib/google_analytics_v4_api/account.rb +8 -3
- data/lib/google_analytics_v4_api/client.rb +9 -22
- data/lib/google_analytics_v4_api/property.rb +15 -6
- data/lib/google_analytics_v4_api/report.rb +26 -0
- data/lib/google_analytics_v4_api/report_response.rb +36 -0
- data/lib/google_analytics_v4_api/report_response_row.rb +35 -0
- data/lib/google_analytics_v4_api/request.rb +45 -0
- data/lib/google_analytics_v4_api/version.rb +1 -1
- data/lib/google_analytics_v4_api.rb +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 516d5859258748f1f4749df54b064cc3caf1b9707028041fd0db0084a75d719d
|
4
|
+
data.tar.gz: 0030de2106fff16d2ad13e7feb9c98af718fa0c55b04c30a9eecd462ff8df08a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bee4ad056696d0829191e46f6187c0d5a29cfeaebc5ad7fba3ea3b0766aa7d004b1b99ec26f854f4f7cf6d636c94f1f3b097e2ad5991413e7507be3e545443c
|
7
|
+
data.tar.gz: 060b03b7c94203270e627dcc35ae8e1262ccbb467040b5221c86518c4815b16a5239d3c77699ea43a8b5b511160d948143a4069aaa3b67b8af8d398e14ef4be6
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Google Analytics v4 API Ruby Gem
|
2
2
|
This is a simple wrapper to interact with the Google Analytics v4 API (currently in beta) with Ruby.
|
3
|
-
It's based on the [API guide](https://developers.google.com/analytics/devguides/config/admin/v1/rest
|
3
|
+
It's based on the [Admin API guide](https://developers.google.com/analytics/devguides/config/admin/v1/rest) and the
|
4
|
+
[Reports API guide](https://developers.google.com/analytics/devguides/reporting/data/v1/basics?authuser=1#report_response)
|
4
5
|
|
5
6
|
## Usage
|
6
7
|
Add this gem to your Gemfile:
|
@@ -10,21 +11,79 @@ gem 'google_analytics_v4_api'
|
|
10
11
|
|
11
12
|
You will need a way to get a user's valid (and fresh) token (I personally use the `gem omnioauth`), and then:
|
12
13
|
|
14
|
+
### Management API
|
13
15
|
```rb
|
14
16
|
client = GoogleAnalyticsV4Api::Client.new(token)
|
15
17
|
# List all the accounts
|
16
|
-
client.accounts
|
18
|
+
accounts = client.accounts
|
17
19
|
# Or get one particular account
|
18
|
-
client.account("
|
20
|
+
account = client.account("accounts/24696xxx")
|
19
21
|
|
20
22
|
# List all the properties for a particular account
|
21
|
-
client.properties("accounts/24596xxx")
|
23
|
+
properties = client.properties("accounts/24596xxx")
|
22
24
|
# Or get one particular property
|
23
|
-
client.property("properties/33783xxx")
|
25
|
+
property = client.property("properties/33783xxx")
|
26
|
+
|
27
|
+
# Or simply call the properties for an Account object
|
28
|
+
properties = account.properties
|
29
|
+
# Or one particular property
|
30
|
+
property = account.property("properties/33783xxx")
|
24
31
|
```
|
25
32
|
|
26
|
-
|
33
|
+
### Data API
|
34
|
+
```rb
|
35
|
+
filter = {
|
36
|
+
"andGroup": {
|
37
|
+
"expressions": [
|
38
|
+
{
|
39
|
+
"filter": {
|
40
|
+
"fieldName": "countryId",
|
41
|
+
"stringFilter": {
|
42
|
+
"value": "CL"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
},
|
46
|
+
{
|
47
|
+
"filter": {
|
48
|
+
"fieldName": "pagePath",
|
49
|
+
"stringFilter": {
|
50
|
+
"matchType": "CONTAINS",
|
51
|
+
"value": "events",
|
52
|
+
"caseSensitive": false
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
report = GoogleAnalyticsV4Api::Report.new(
|
60
|
+
dimensions: ['pagePath', 'countryId'],
|
61
|
+
metrics: ['sessions', 'screenPageViews'],
|
62
|
+
dimension_filter: filter,
|
63
|
+
start_date: Date.today - 30, #optional, 30 days ago by default
|
64
|
+
end_date: Date.today - 1) #optional, today by default
|
65
|
+
|
66
|
+
response = property.run_report(report)
|
67
|
+
|
68
|
+
# Get raw data from the response
|
69
|
+
response.raw_dimension_headers
|
70
|
+
=> [{"name"=>"pagePath"}, {"name"=>"countryId"}]
|
71
|
+
response.raw_metric_headers
|
72
|
+
=> [{"name"=>"sessions", "type"=>"TYPE_INTEGER"}, {"name"=>"screenPageViews", "type"=>"TYPE_INTEGER"}]
|
73
|
+
response.rows.first
|
74
|
+
=> {"dimensionValues"=>[{"value"=>"/events"}, {"value"=>"CL"}], "metricValues"=>[{"value"=>"58"}, {"value"=>"78"}]}
|
75
|
+
|
76
|
+
# Or get a simplified version of the response
|
77
|
+
response.dimension_headers
|
78
|
+
=> ["pagePath", "countryId"]
|
79
|
+
response.metric_headers
|
80
|
+
=> ["sessions", "screenPageViews"]
|
81
|
+
response.parsed_rows.first.data
|
82
|
+
=> {"pagePath"=>"/events", "countryId"=>"CL", "sessions"=>58, "screenPageViews"=>78}
|
27
83
|
|
84
|
+
```
|
85
|
+
Dimensions and Metrics are available [here](https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema)
|
86
|
+
Information about Filters is available [here](https://developers.google.com/analytics/devguides/reporting/data/v1/basics#dimension_filters)
|
28
87
|
|
29
88
|
## Development
|
30
89
|
|
@@ -6,19 +6,24 @@ module GoogleAnalyticsV4Api
|
|
6
6
|
class Account
|
7
7
|
attr_accessor :name, :createTime, :updateTime, :displayName, :regionCode
|
8
8
|
|
9
|
-
def initialize(attributes = {})
|
9
|
+
def initialize(client, attributes = {})
|
10
|
+
@client = client
|
10
11
|
attributes.each do |k, v|
|
11
12
|
self.send("#{k}=", v)
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
16
|
def properties
|
17
|
+
@client.properties(name)
|
18
|
+
end
|
16
19
|
|
20
|
+
def property(property_name)
|
21
|
+
@client.property(property_name)
|
17
22
|
end
|
18
23
|
|
19
|
-
def self.parse_list(body)
|
24
|
+
def self.parse_list(client, body)
|
20
25
|
JSON.parse(body)["accounts"].map do |attrs|
|
21
|
-
GoogleAnalyticsV4Api::Account.new(attrs)
|
26
|
+
GoogleAnalyticsV4Api::Account.new(client, attrs)
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
@@ -1,20 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'json'
|
4
|
-
require "net/http"
|
5
|
-
require "uri"
|
6
|
-
|
7
3
|
module GoogleAnalyticsV4Api
|
8
4
|
class Client
|
9
5
|
|
10
|
-
|
6
|
+
attr_accessor :access_token
|
11
7
|
|
12
8
|
def initialize(access_token)
|
13
9
|
@access_token = access_token
|
14
10
|
end
|
15
11
|
|
16
12
|
def accounts
|
17
|
-
@accounts ||= GoogleAnalyticsV4Api::Account.parse_list get("/accounts")
|
13
|
+
@accounts ||= GoogleAnalyticsV4Api::Account.parse_list(self, get("/accounts"))
|
18
14
|
end
|
19
15
|
|
20
16
|
def account(account_name)
|
@@ -22,7 +18,10 @@ module GoogleAnalyticsV4Api
|
|
22
18
|
end
|
23
19
|
|
24
20
|
def properties(account_name)
|
25
|
-
@properties ||=
|
21
|
+
@properties ||= Hash.new do |h, key|
|
22
|
+
h[key] = GoogleAnalyticsV4Api::Property.parse_list(self, get("/properties", { filter: "parent:#{key}"}))
|
23
|
+
end
|
24
|
+
@properties[account_name]
|
26
25
|
end
|
27
26
|
|
28
27
|
def property(property_name)
|
@@ -31,25 +30,13 @@ module GoogleAnalyticsV4Api
|
|
31
30
|
return property unless property.nil?
|
32
31
|
end
|
33
32
|
|
34
|
-
GoogleAnalyticsV4Api::Property.parse get("/#{property_name}")
|
33
|
+
GoogleAnalyticsV4Api::Property.parse(self, get("/#{property_name}"))
|
35
34
|
end
|
36
35
|
|
37
36
|
private
|
38
37
|
def get(path, params = {})
|
39
|
-
|
40
|
-
url += "?#{URI.encode_www_form params}" unless params.empty?
|
41
|
-
uri = URI(url)
|
42
|
-
|
43
|
-
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
|
44
|
-
request = Net::HTTP::Get.new uri
|
45
|
-
request["Authorization"] = "Bearer #{@access_token}"
|
46
|
-
request["Content-Type"] = "application/json"
|
47
|
-
|
48
|
-
http.request request
|
49
|
-
end
|
50
|
-
raise GoogleAnalyticsV4Api::Error.new(response) unless response.is_a?(Net::HTTPSuccess)
|
51
|
-
|
52
|
-
response
|
38
|
+
Request.get(access_token: @access_token, path: path, params: params).body
|
53
39
|
end
|
40
|
+
|
54
41
|
end
|
55
42
|
end
|
@@ -6,21 +6,30 @@ module GoogleAnalyticsV4Api
|
|
6
6
|
class Property
|
7
7
|
attr_accessor :name, :propertyType, :createTime, :updateTime, :parent, :displayName, :industryCategory, :timeZone, :currencyCode, :serviceLevel, :deleteTime, :expireTime, :account
|
8
8
|
|
9
|
-
def initialize(attributes = {})
|
9
|
+
def initialize(client, attributes = {})
|
10
|
+
@client = client
|
10
11
|
attributes.each do |k, v|
|
11
12
|
self.send("#{k}=", v)
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
+
def account
|
17
|
+
@client.account(parent)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_report(report)
|
21
|
+
response = Request.post(access_token: @client.access_token, path: "/#{name}:runReport", payload: report.to_json)
|
22
|
+
ReportResponse.new(response)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse_list(client, body)
|
16
26
|
JSON.parse(body)["properties"].map do |attrs|
|
17
|
-
GoogleAnalyticsV4Api::Property.new(attrs)
|
27
|
+
GoogleAnalyticsV4Api::Property.new(client, attrs)
|
18
28
|
end
|
19
29
|
end
|
20
30
|
|
21
|
-
def self.parse(body)
|
22
|
-
GoogleAnalyticsV4Api::Property.new(JSON.parse(body))
|
31
|
+
def self.parse(client, body)
|
32
|
+
GoogleAnalyticsV4Api::Property.new(client, JSON.parse(body))
|
23
33
|
end
|
24
|
-
|
25
34
|
end
|
26
35
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module GoogleAnalyticsV4Api
|
7
|
+
class Report
|
8
|
+
attr_accessor :date_ranges, :dimensions, :metrics, :dimension_filter
|
9
|
+
|
10
|
+
def initialize(start_date: nil, end_date: nil, dimensions: [], metrics: [], dimension_filter: {})
|
11
|
+
@date_ranges = [{ "startDate": start_date || (Date.today - 30), "endDate": end_date || Date.today }]
|
12
|
+
@dimensions = dimensions.map { |dimension| { "name": dimension } }
|
13
|
+
@metrics = metrics.map { |metric| { "name": metric } }
|
14
|
+
@dimension_filter = dimension_filter
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json
|
18
|
+
{
|
19
|
+
"dateRanges": @date_ranges,
|
20
|
+
"dimensions": @dimensions,
|
21
|
+
"metrics": @metrics,
|
22
|
+
"dimensionFilter": @dimension_filter
|
23
|
+
}.to_json
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module GoogleAnalyticsV4Api
|
7
|
+
class ReportResponse
|
8
|
+
|
9
|
+
attr_accessor :body, :raw_dimension_headers, :raw_metric_headers, :rows, :row_count, :metadata, :kind
|
10
|
+
|
11
|
+
def initialize(body)
|
12
|
+
@body = JSON.parse body
|
13
|
+
@raw_dimension_headers = @body["dimensionHeaders"]
|
14
|
+
@raw_metric_headers = @body["metricHeaders"]
|
15
|
+
@rows = @body["rows"]
|
16
|
+
@row_cont = @body["rowCount"]
|
17
|
+
@metadata = @body["metadata"]
|
18
|
+
@kind = @body["kind"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def dimension_headers
|
22
|
+
@dimension_headers ||= @raw_dimension_headers.map { |header| header["name"] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def metric_headers
|
26
|
+
@metric_headers ||= @raw_metric_headers.map { |header| header["name"] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def parsed_rows
|
30
|
+
@rows.map do |row|
|
31
|
+
ReportResponseRow.new(row, @raw_dimension_headers, @raw_metric_headers)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module GoogleAnalyticsV4Api
|
7
|
+
class ReportResponseRow
|
8
|
+
|
9
|
+
attr_accessor :data
|
10
|
+
|
11
|
+
def initialize(row, raw_dimension_headers, raw_metric_headers)
|
12
|
+
# "dimensionHeaders"=>[{"name"=>"pagePath"}, {"name"=>"countryId"}],
|
13
|
+
# "metricHeaders"=>[{"name"=>"sessions", "type"=>"TYPE_INTEGER"}, {"name"=>"screenPageViews", "type"=>"TYPE_INTEGER"}],
|
14
|
+
# a row: {"dimensionValues"=>[{"value"=>"/events"}, {"value"=>"CL"}], "metricValues"=>[{"value"=>"62"}, {"value"=>"82"}]}
|
15
|
+
@raw_row = row
|
16
|
+
@data = {}
|
17
|
+
raw_dimension_headers.each_with_index do |dimension_header, index|
|
18
|
+
@data[dimension_header["name"]] = row["dimensionValues"][index]["value"]
|
19
|
+
end
|
20
|
+
raw_metric_headers.each_with_index do |metric_header, index|
|
21
|
+
@data[metric_header["name"]] = cast(row["metricValues"][index]["value"], metric_header["type"])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def cast(value, type)
|
26
|
+
words = type.split("_")
|
27
|
+
return value unless words[0] == 'TYPE'
|
28
|
+
return value.to_i if words[1] == "INTEGER"
|
29
|
+
return value.to_f if words[1].in? %w(FLOAT SECONDS MILLISECONDS MINUTES HOURS STANDARD CURRENCY FEET MILES METERS KILOMETERS)
|
30
|
+
|
31
|
+
value
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
module GoogleAnalyticsV4Api
|
7
|
+
class Request
|
8
|
+
|
9
|
+
ADMIN_URL = "https://analyticsadmin.googleapis.com/v1beta"
|
10
|
+
DATA_URL = "https://analyticsdata.googleapis.com/v1beta"
|
11
|
+
|
12
|
+
def self.get(access_token:, url: ADMIN_URL, path:, params: {})
|
13
|
+
url = "#{url}#{path}"
|
14
|
+
url += "?#{URI.encode_www_form params}" unless params.empty?
|
15
|
+
uri = URI(url)
|
16
|
+
|
17
|
+
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
|
18
|
+
request = Net::HTTP::Get.new uri
|
19
|
+
request["Authorization"] = "Bearer #{access_token}"
|
20
|
+
request["Content-Type"] = "application/json"
|
21
|
+
|
22
|
+
http.request request
|
23
|
+
end
|
24
|
+
raise GoogleAnalyticsV4Api::Error.new(response) unless response.is_a?(Net::HTTPSuccess)
|
25
|
+
|
26
|
+
response
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.post(access_token:, url: DATA_URL, path:, payload: nil)
|
30
|
+
url = URI("#{url}#{path}")
|
31
|
+
|
32
|
+
https = Net::HTTP.new(url.host, url.port)
|
33
|
+
https.use_ssl = true
|
34
|
+
|
35
|
+
request = Net::HTTP::Post.new(url)
|
36
|
+
request["Authorization"] = "Bearer #{access_token}"
|
37
|
+
request["Content-Type"] = "application/javascript"
|
38
|
+
request.body = payload
|
39
|
+
|
40
|
+
response = https.request(request)
|
41
|
+
response.read_body
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -4,5 +4,9 @@ module GoogleAnalyticsV4Api
|
|
4
4
|
autoload :Client, "google_analytics_v4_api/client"
|
5
5
|
autoload :Account, "google_analytics_v4_api/account"
|
6
6
|
autoload :Property, "google_analytics_v4_api/property"
|
7
|
+
autoload :Request, "google_analytics_v4_api/request"
|
8
|
+
autoload :Report, "google_analytics_v4_api/report"
|
9
|
+
autoload :ReportResponse, "google_analytics_v4_api/report_response"
|
10
|
+
autoload :ReportResponseRow, "google_analytics_v4_api/report_response_row"
|
7
11
|
autoload :Error, "google_analytics_v4_api/error"
|
8
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_analytics_v4_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gustavo Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A very humble wrapper for the Google Analytics V4 API to be used in conjuntion
|
14
14
|
with OAuth2
|
@@ -33,6 +33,10 @@ files:
|
|
33
33
|
- lib/google_analytics_v4_api/client.rb
|
34
34
|
- lib/google_analytics_v4_api/error.rb
|
35
35
|
- lib/google_analytics_v4_api/property.rb
|
36
|
+
- lib/google_analytics_v4_api/report.rb
|
37
|
+
- lib/google_analytics_v4_api/report_response.rb
|
38
|
+
- lib/google_analytics_v4_api/report_response_row.rb
|
39
|
+
- lib/google_analytics_v4_api/request.rb
|
36
40
|
- lib/google_analytics_v4_api/version.rb
|
37
41
|
homepage: https://github.com/dailytics/google_analytics_v4_api
|
38
42
|
licenses:
|