ahoy_matey 1.6.1 → 2.0.0
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/.github/ISSUE_TEMPLATE.md +7 -0
- data/CHANGELOG.md +22 -0
- data/CONTRIBUTING.md +40 -0
- data/LICENSE.txt +1 -1
- data/README.md +210 -489
- data/Rakefile +1 -0
- data/ahoy_matey.gemspec +6 -8
- data/app/controllers/ahoy/base_controller.rb +2 -6
- data/app/controllers/ahoy/events_controller.rb +7 -1
- data/app/controllers/ahoy/visits_controller.rb +7 -1
- data/app/jobs/ahoy/geocode_job.rb +10 -0
- data/app/jobs/ahoy/geocode_v2_job.rb +29 -0
- data/config/routes.rb +1 -1
- data/docs/Ahoy-2-Upgrade.md +147 -0
- data/docs/Data-Store-Examples.md +240 -0
- data/lib/ahoy.rb +30 -88
- data/lib/ahoy/base_store.rb +72 -0
- data/lib/ahoy/controller.rb +4 -10
- data/lib/ahoy/database_store.rb +72 -0
- data/lib/ahoy/engine.rb +5 -7
- data/lib/ahoy/model.rb +4 -26
- data/lib/ahoy/{properties.rb → query_methods.rb} +18 -4
- data/lib/ahoy/tracker.rb +60 -38
- data/lib/ahoy/version.rb +1 -1
- data/lib/ahoy/visit_properties.rb +65 -39
- data/lib/generators/ahoy/activerecord_generator.rb +58 -0
- data/lib/generators/ahoy/base_generator.rb +13 -0
- data/lib/generators/ahoy/install_generator.rb +44 -0
- data/lib/generators/ahoy/mongoid_generator.rb +20 -0
- data/lib/generators/ahoy/templates/active_record_event_model.rb +10 -0
- data/lib/generators/ahoy/{stores/templates/active_record_visits_migration.rb → templates/active_record_migration.rb} +19 -21
- data/lib/generators/ahoy/templates/active_record_visit_model.rb +6 -0
- data/lib/generators/ahoy/templates/base_store_initializer.rb +17 -0
- data/lib/generators/ahoy/templates/database_store_initializer.rb +5 -0
- data/lib/generators/ahoy/{stores/templates → templates}/mongoid_event_model.rb +4 -2
- data/lib/generators/ahoy/{stores/templates → templates}/mongoid_visit_model.rb +7 -3
- data/test/query_methods/mongoid_test.rb +23 -0
- data/test/{properties → query_methods}/mysql_json_test.rb +1 -1
- data/test/{properties → query_methods}/mysql_text_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_hstore_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_json_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_jsonb_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_text_test.rb +1 -1
- data/test/test_helper.rb +4 -3
- data/vendor/assets/javascripts/ahoy.js +551 -325
- metadata +67 -112
- data/lib/ahoy/deckhands/location_deckhand.rb +0 -49
- data/lib/ahoy/deckhands/request_deckhand.rb +0 -52
- data/lib/ahoy/deckhands/technology_deckhand.rb +0 -47
- data/lib/ahoy/deckhands/traffic_source_deckhand.rb +0 -22
- data/lib/ahoy/deckhands/utm_parameter_deckhand.rb +0 -23
- data/lib/ahoy/geocode_job.rb +0 -13
- data/lib/ahoy/logger_silencer.rb +0 -75
- data/lib/ahoy/stores/active_record_store.rb +0 -61
- data/lib/ahoy/stores/active_record_token_store.rb +0 -114
- data/lib/ahoy/stores/base_store.rb +0 -88
- data/lib/ahoy/stores/bunny_store.rb +0 -33
- data/lib/ahoy/stores/fluentd_store.rb +0 -17
- data/lib/ahoy/stores/kafka_store.rb +0 -42
- data/lib/ahoy/stores/kinesis_firehose_store.rb +0 -42
- data/lib/ahoy/stores/log_store.rb +0 -53
- data/lib/ahoy/stores/mongoid_store.rb +0 -63
- data/lib/ahoy/stores/nats_store.rb +0 -34
- data/lib/ahoy/stores/nsq_store.rb +0 -36
- data/lib/ahoy/subscribers/active_record.rb +0 -19
- data/lib/ahoy/throttle.rb +0 -17
- data/lib/generators/ahoy/stores/active_record_events_generator.rb +0 -59
- data/lib/generators/ahoy/stores/active_record_generator.rb +0 -16
- data/lib/generators/ahoy/stores/active_record_visits_generator.rb +0 -49
- data/lib/generators/ahoy/stores/bunny_generator.rb +0 -15
- data/lib/generators/ahoy/stores/custom_generator.rb +0 -15
- data/lib/generators/ahoy/stores/fluentd_generator.rb +0 -15
- data/lib/generators/ahoy/stores/kafka_generator.rb +0 -15
- data/lib/generators/ahoy/stores/kinesis_firehose_generator.rb +0 -15
- data/lib/generators/ahoy/stores/log_generator.rb +0 -15
- data/lib/generators/ahoy/stores/mongoid_events_generator.rb +0 -19
- data/lib/generators/ahoy/stores/mongoid_generator.rb +0 -14
- data/lib/generators/ahoy/stores/mongoid_visits_generator.rb +0 -27
- data/lib/generators/ahoy/stores/nats_generator.rb +0 -15
- data/lib/generators/ahoy/stores/nsq_generator.rb +0 -15
- data/lib/generators/ahoy/stores/templates/active_record_event_model.rb +0 -12
- data/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +0 -20
- data/lib/generators/ahoy/stores/templates/active_record_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/active_record_visit_model.rb +0 -4
- data/lib/generators/ahoy/stores/templates/bunny_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/custom_initializer.rb +0 -10
- data/lib/generators/ahoy/stores/templates/fluentd_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/kafka_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/kinesis_firehose_initializer.rb +0 -17
- data/lib/generators/ahoy/stores/templates/log_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/mongoid_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/nats_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/nsq_initializer.rb +0 -9
- data/test/visit_properties_test.rb +0 -44
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47cc04adfac18b2f14547b376a3465f601d59307
|
|
4
|
+
data.tar.gz: 6e1638296155ceab46f9d105e52d7422259ebc63
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f0a217bd790fff2b55e1e6395ea940079b2a457efc1328c61a054d6a3835f0d6fcb9c154eae7f3496f8a79559282cc3d9b1eefb2db4ce651d74d6c14dce536a
|
|
7
|
+
data.tar.gz: 6789de07f914f49b05f72b4b5517935571368be2e43987421e170dd8da838d78a1fa48e1d878424a9800f53ea779b5dcd8b3523432977f7aec4a29e296941a41
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 2.0.0
|
|
2
|
+
|
|
3
|
+
- Removed dependency on jQuery
|
|
4
|
+
- Use `navigator.sendBeacon` by default in supported browsers
|
|
5
|
+
- Added `geocode` event
|
|
6
|
+
- Added `where_event` method for querying events
|
|
7
|
+
- Added support for `visitable` and `where_props` to Mongoid
|
|
8
|
+
- Added `preserve_callbacks` option
|
|
9
|
+
- Use `json` for MySQL by default
|
|
10
|
+
- Fixed log silencing
|
|
11
|
+
|
|
12
|
+
Breaking changes
|
|
13
|
+
|
|
14
|
+
- Simpler interface for data stores
|
|
15
|
+
- Renamed `track_visits_immediately` to `server_side_visits` and enabled by default
|
|
16
|
+
- Renamed `mount` option to `api` and disabled by default
|
|
17
|
+
- Enabled `protect_from_forgery` by default
|
|
18
|
+
- Removed deprecated options
|
|
19
|
+
- Removed throttling
|
|
20
|
+
- Removed most built-in stores
|
|
21
|
+
- Removed support for Rails < 4.2
|
|
22
|
+
|
|
1
23
|
## 1.6.1
|
|
2
24
|
|
|
3
25
|
- Added `gin` index on properties for events
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
First, thanks for wanting to contribute. You’re awesome! :heart:
|
|
4
|
+
|
|
5
|
+
## Questions
|
|
6
|
+
|
|
7
|
+
Use [Stack Overflow](https://stackoverflow.com/) with the tag `ahoy`.
|
|
8
|
+
|
|
9
|
+
## Feature Requests
|
|
10
|
+
|
|
11
|
+
Create an issue. Start the title with `[Idea]`.
|
|
12
|
+
|
|
13
|
+
## Issues
|
|
14
|
+
|
|
15
|
+
Think you’ve discovered an issue?
|
|
16
|
+
|
|
17
|
+
1. Search existing issues to see if it’s been reported.
|
|
18
|
+
2. Try the `master` branch to make sure it hasn’t been fixed.
|
|
19
|
+
|
|
20
|
+
```rb
|
|
21
|
+
gem "ahoy_matey", github: "ankane/ahoy"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If the above steps don’t help, create an issue. Include:
|
|
25
|
+
|
|
26
|
+
- Detailed steps to reproduce
|
|
27
|
+
- Complete backtraces for exceptions
|
|
28
|
+
|
|
29
|
+
## Pull Requests
|
|
30
|
+
|
|
31
|
+
Fork the project and create a pull request. A few tips:
|
|
32
|
+
|
|
33
|
+
- Keep changes to a minimum. If you have multiple features or fixes, submit multiple pull requests.
|
|
34
|
+
- Follow the existing style. The code should read like it’s written by a single person.
|
|
35
|
+
|
|
36
|
+
Feel free to open an issue to get feedback on your idea before spending too much time on it.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
This contributing guide is released under [CCO](https://creativecommons.org/publicdomain/zero/1.0/) (public domain). Use it for your own project without attribution.
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Ahoy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
:fire: Simple, powerful analytics for Rails
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Track visits and events in Ruby, JavaScript, and native apps. Data is stored in your database by default so you can easily combine it with other data.
|
|
6
|
+
|
|
7
|
+
**Ahoy 2.0 was recently released!** See [how to upgrade](docs/Ahoy-2-Upgrade.md)
|
|
6
8
|
|
|
7
|
-
:postbox: To track emails, check out [Ahoy Email](https://github.com/ankane/ahoy_email).
|
|
9
|
+
:postbox: To track emails, check out [Ahoy Email](https://github.com/ankane/ahoy_email), and for A/B testing, check out [Field Test](https://github.com/ankane/field_test)
|
|
8
10
|
|
|
9
|
-
:
|
|
11
|
+
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
|
10
12
|
|
|
11
13
|
## Installation
|
|
12
14
|
|
|
@@ -16,177 +18,73 @@ Add this line to your application’s Gemfile:
|
|
|
16
18
|
gem 'ahoy_matey'
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
And add the javascript file in `app/assets/javascripts/application.js` after jQuery.
|
|
20
|
-
|
|
21
|
-
```javascript
|
|
22
|
-
//= require jquery
|
|
23
|
-
//= require ahoy
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Choose a Data Store
|
|
27
|
-
|
|
28
|
-
Ahoy supports a number of data stores out of the box. You can start with one of them and customize as needed, or create your own store from scratch.
|
|
29
|
-
|
|
30
|
-
- [PostgreSQL, MySQL, or SQLite](#postgresql-mysql-or-sqlite)
|
|
31
|
-
- [MongoDB](#mongodb)
|
|
32
|
-
- [Kafka](#kafka), [Fluentd](#fluentd), [RabbitMQ](#rabbitmq), [NATS](#nats), [NSQ](#nsq), or [Amazon Kinesis Firehose](#amazon-kinesis-firehose)
|
|
33
|
-
- [Logs](#logs)
|
|
34
|
-
- [Custom](#custom)
|
|
35
|
-
|
|
36
|
-
### PostgreSQL, MySQL, or SQLite
|
|
37
|
-
|
|
38
|
-
Run:
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
rails generate ahoy:stores:active_record
|
|
42
|
-
rake db:migrate
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### MongoDB
|
|
46
|
-
|
|
47
|
-
Run:
|
|
48
|
-
|
|
49
|
-
```sh
|
|
50
|
-
rails generate ahoy:stores:mongoid
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Kafka
|
|
54
|
-
|
|
55
|
-
Add [ruby-kafka](https://github.com/zendesk/ruby-kafka) to your Gemfile.
|
|
56
|
-
|
|
57
|
-
```ruby
|
|
58
|
-
gem 'ruby-kafka'
|
|
59
|
-
```
|
|
60
|
-
|
|
61
21
|
And run:
|
|
62
22
|
|
|
63
23
|
```sh
|
|
64
|
-
|
|
24
|
+
bundle install
|
|
25
|
+
rails generate ahoy:install
|
|
26
|
+
rails db:migrate
|
|
65
27
|
```
|
|
66
28
|
|
|
67
|
-
|
|
29
|
+
Restart your web server, open a page in your browser, and a visit will be created :tada:
|
|
68
30
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Add [fluent-logger](https://github.com/fluent/fluent-logger-ruby) to your Gemfile.
|
|
31
|
+
Track your first event from a controller with:
|
|
72
32
|
|
|
73
33
|
```ruby
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
And run:
|
|
78
|
-
|
|
79
|
-
```sh
|
|
80
|
-
rails generate ahoy:stores:fluentd
|
|
34
|
+
ahoy.track "My first event", {language: "Ruby"}
|
|
81
35
|
```
|
|
82
36
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
### RabbitMQ
|
|
37
|
+
### JavaScript & Native Apps
|
|
86
38
|
|
|
87
|
-
|
|
39
|
+
First, enable the API in `config/initializers/ahoy.rb`:
|
|
88
40
|
|
|
89
41
|
```ruby
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
And run:
|
|
94
|
-
|
|
95
|
-
```sh
|
|
96
|
-
rails generate ahoy:stores:bunny
|
|
42
|
+
Ahoy.api = true
|
|
97
43
|
```
|
|
98
44
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
### NATS
|
|
45
|
+
And restart your web server.
|
|
102
46
|
|
|
103
|
-
|
|
47
|
+
For JavaScript, add to `app/assets/javascripts/application.js`:
|
|
104
48
|
|
|
105
|
-
```
|
|
106
|
-
|
|
49
|
+
```javascript
|
|
50
|
+
//= require ahoy
|
|
107
51
|
```
|
|
108
52
|
|
|
109
|
-
And
|
|
53
|
+
And track an event with:
|
|
110
54
|
|
|
111
|
-
```
|
|
112
|
-
|
|
55
|
+
```javascript
|
|
56
|
+
ahoy.track("My second event", {language: "JavaScript"});
|
|
113
57
|
```
|
|
114
58
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### NSQ
|
|
118
|
-
|
|
119
|
-
Add [nsq-ruby](https://github.com/wistia/nsq-ruby) to your Gemfile.
|
|
59
|
+
For native apps, see the [API spec](#api-spec).
|
|
120
60
|
|
|
121
|
-
|
|
122
|
-
gem 'nsq-ruby'
|
|
123
|
-
```
|
|
61
|
+
## How It Works
|
|
124
62
|
|
|
125
|
-
|
|
63
|
+
### Visits
|
|
126
64
|
|
|
127
|
-
|
|
128
|
-
rails generate ahoy:stores:nsq
|
|
129
|
-
```
|
|
65
|
+
When someone visits your website, Ahoy creates a visit with lots of useful information.
|
|
130
66
|
|
|
131
|
-
|
|
67
|
+
- **traffic source** - referrer, referring domain, landing page, search keyword
|
|
68
|
+
- **location** - country, region, and city
|
|
69
|
+
- **technology** - browser, OS, and device type
|
|
70
|
+
- **utm parameters** - source, medium, term, content, campaign
|
|
132
71
|
|
|
133
|
-
|
|
72
|
+
Use the `current_visit` method to access it.
|
|
134
73
|
|
|
135
|
-
|
|
74
|
+
Prevent certain Rails actions from creating visits with:
|
|
136
75
|
|
|
137
76
|
```ruby
|
|
138
|
-
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
And run:
|
|
142
|
-
|
|
143
|
-
```sh
|
|
144
|
-
rails generate ahoy:stores:kinesis_firehose
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Configure delivery streams and credentials in the initializer.
|
|
148
|
-
|
|
149
|
-
### Logs
|
|
150
|
-
|
|
151
|
-
```sh
|
|
152
|
-
rails generate ahoy:stores:log
|
|
77
|
+
skip_before_action :track_ahoy_visit
|
|
153
78
|
```
|
|
154
79
|
|
|
155
|
-
This
|
|
156
|
-
|
|
157
|
-
### Custom
|
|
80
|
+
This is typically useful for APIs.
|
|
158
81
|
|
|
159
|
-
|
|
160
|
-
rails generate ahoy:stores:custom
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
This creates a class for you to fill out.
|
|
82
|
+
You can also defer visit tracking to JavaScript (Ahoy 1.0 behavior) with:
|
|
164
83
|
|
|
165
84
|
```ruby
|
|
166
|
-
|
|
167
|
-
def track_visit(options)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def track_event(name, properties, options)
|
|
171
|
-
end
|
|
172
|
-
end
|
|
85
|
+
Ahoy.server_side_visits = false
|
|
173
86
|
```
|
|
174
87
|
|
|
175
|
-
See the [ActiveRecordTokenStore](https://github.com/ankane/ahoy/blob/master/lib/ahoy/stores/active_record_token_store.rb) for an example.
|
|
176
|
-
|
|
177
|
-
## How It Works
|
|
178
|
-
|
|
179
|
-
### Visits
|
|
180
|
-
|
|
181
|
-
When someone visits your website, Ahoy creates a visit with lots of useful information.
|
|
182
|
-
|
|
183
|
-
- **traffic source** - referrer, referring domain, landing page, search keyword
|
|
184
|
-
- **location** - country, region, and city
|
|
185
|
-
- **technology** - browser, OS, and device type
|
|
186
|
-
- **utm parameters** - source, medium, term, content, campaign
|
|
187
|
-
|
|
188
|
-
Use the `current_visit` method to access it.
|
|
189
|
-
|
|
190
88
|
### Events
|
|
191
89
|
|
|
192
90
|
Each event has a `name` and `properties`.
|
|
@@ -213,239 +111,193 @@ See [Ahoy.js](https://github.com/ankane/ahoy.js) for a complete list of features
|
|
|
213
111
|
ahoy.track "Viewed book", title: "Hot, Flat, and Crowded"
|
|
214
112
|
```
|
|
215
113
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
See the [HTTP spec](#native-apps-1) until libraries are built.
|
|
219
|
-
|
|
220
|
-
### Users
|
|
221
|
-
|
|
222
|
-
Ahoy automatically attaches the `current_user` to the visit.
|
|
223
|
-
|
|
224
|
-
With [Devise](https://github.com/plataformatec/devise), it will attach the user even if he or she signs in after the visit starts.
|
|
225
|
-
|
|
226
|
-
With other authentication frameworks, add this to the end of your sign in method:
|
|
114
|
+
or track actions automatically with:
|
|
227
115
|
|
|
228
116
|
```ruby
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
## Customize the Store
|
|
117
|
+
class ApplicationController < ActionController::Base
|
|
118
|
+
after_action :track_action
|
|
233
119
|
|
|
234
|
-
|
|
120
|
+
protected
|
|
235
121
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
122
|
+
def track_action
|
|
123
|
+
ahoy.track "Viewed action", request.path_parameters
|
|
124
|
+
end
|
|
239
125
|
end
|
|
240
126
|
```
|
|
241
127
|
|
|
242
|
-
|
|
128
|
+
#### Native Apps
|
|
243
129
|
|
|
244
|
-
|
|
130
|
+
See the [API spec](#api-spec).
|
|
245
131
|
|
|
246
|
-
|
|
247
|
-
class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
|
|
248
|
-
def exclude?
|
|
249
|
-
bot? || request.ip == "192.168.1.1"
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
```
|
|
132
|
+
### Associated Models
|
|
253
133
|
|
|
254
|
-
|
|
134
|
+
Say we want to associate orders with visits. Ahoy can do this automatically.
|
|
255
135
|
|
|
256
|
-
|
|
136
|
+
First, generate a migration and add a `visit_id` column (not needed for Mongoid).
|
|
257
137
|
|
|
258
138
|
```ruby
|
|
259
|
-
class
|
|
260
|
-
def
|
|
261
|
-
|
|
262
|
-
visit.gclid = visit_properties.landing_params["gclid"]
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def track_event(name, properties, options)
|
|
267
|
-
super do |event|
|
|
268
|
-
event.ip = request.ip
|
|
269
|
-
end
|
|
139
|
+
class AddVisitIdToOrders < ActiveRecord::Migration[5.1]
|
|
140
|
+
def change
|
|
141
|
+
add_column :orders, :visit_id, :bigint
|
|
270
142
|
end
|
|
271
143
|
end
|
|
272
144
|
```
|
|
273
145
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
### Customize User
|
|
277
|
-
|
|
278
|
-
If you use a method other than `current_user`, set it here:
|
|
146
|
+
Then, add `visitable` to the model.
|
|
279
147
|
|
|
280
148
|
```ruby
|
|
281
|
-
class
|
|
282
|
-
|
|
283
|
-
controller.true_user
|
|
284
|
-
end
|
|
149
|
+
class Order < ApplicationRecord
|
|
150
|
+
visitable
|
|
285
151
|
end
|
|
286
152
|
```
|
|
287
153
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
Exceptions are rescued so analytics do not break your app. Ahoy uses [Safely](https://github.com/ankane/safely) to try to report them to a service by default.
|
|
154
|
+
When a visitor places an order, the `visit_id` column is automatically set :tada:
|
|
291
155
|
|
|
292
|
-
|
|
156
|
+
See where orders are coming from with simple joins:
|
|
293
157
|
|
|
294
158
|
```ruby
|
|
295
|
-
|
|
159
|
+
Order.joins(:visit).group("referring_domain").count
|
|
160
|
+
Order.joins(:visit).group("city").count
|
|
161
|
+
Order.joins(:visit).group("device_type").count
|
|
296
162
|
```
|
|
297
163
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
For ActiveRecord and Mongoid stores
|
|
164
|
+
Customize the column and class name with:
|
|
301
165
|
|
|
302
166
|
```ruby
|
|
303
|
-
|
|
304
|
-
def visit_model
|
|
305
|
-
CustomVisit
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def event_model
|
|
309
|
-
CustomEvent
|
|
310
|
-
end
|
|
311
|
-
end
|
|
167
|
+
visitable :sign_up_visit, class_name: "Visit"
|
|
312
168
|
```
|
|
313
169
|
|
|
314
|
-
|
|
170
|
+
### Users
|
|
315
171
|
|
|
316
|
-
|
|
172
|
+
Ahoy automatically attaches the `current_user` to the visit. With [Devise](https://github.com/plataformatec/devise), it attaches the user even if he or she signs in after the visit starts.
|
|
317
173
|
|
|
318
|
-
|
|
174
|
+
With other authentication frameworks, add this to the end of your sign in method:
|
|
319
175
|
|
|
320
|
-
```
|
|
321
|
-
ahoy.
|
|
176
|
+
```ruby
|
|
177
|
+
ahoy.authenticate(user)
|
|
322
178
|
```
|
|
323
179
|
|
|
324
|
-
|
|
180
|
+
To see the visits for a given user, create an association:
|
|
325
181
|
|
|
326
|
-
```
|
|
327
|
-
|
|
182
|
+
```ruby
|
|
183
|
+
class User < ApplicationRecord
|
|
184
|
+
has_many :visits, class_name: "Ahoy::Visit"
|
|
185
|
+
end
|
|
328
186
|
```
|
|
329
187
|
|
|
330
|
-
|
|
188
|
+
And use:
|
|
331
189
|
|
|
332
190
|
```ruby
|
|
333
|
-
|
|
334
|
-
after_action :track_action
|
|
335
|
-
|
|
336
|
-
protected
|
|
337
|
-
|
|
338
|
-
def track_action
|
|
339
|
-
ahoy.track "Viewed #{controller_path}##{action_name}", params: request.path_parameters
|
|
340
|
-
end
|
|
341
|
-
end
|
|
191
|
+
User.find(123).visits
|
|
342
192
|
```
|
|
343
193
|
|
|
344
|
-
|
|
194
|
+
#### Custom User Method
|
|
345
195
|
|
|
346
|
-
|
|
196
|
+
Use a method besides `current_user`
|
|
347
197
|
|
|
348
198
|
```ruby
|
|
349
|
-
Ahoy.
|
|
199
|
+
Ahoy.user_method = :true_user
|
|
350
200
|
```
|
|
351
201
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
By default, a new visit is created after 4 hours of inactivity.
|
|
355
|
-
|
|
356
|
-
Change this with:
|
|
202
|
+
or use a proc
|
|
357
203
|
|
|
358
204
|
```ruby
|
|
359
|
-
Ahoy.
|
|
205
|
+
Ahoy.user_method = ->(controller) { controller.true_user }
|
|
360
206
|
```
|
|
361
207
|
|
|
362
|
-
###
|
|
363
|
-
|
|
364
|
-
Let’s associate orders with visits.
|
|
208
|
+
### Doorkeeper
|
|
365
209
|
|
|
366
|
-
|
|
210
|
+
To attach the user with [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper), be sure you have a `current_resource_owner` method in `ApplicationController`.
|
|
367
211
|
|
|
368
212
|
```ruby
|
|
369
|
-
class
|
|
370
|
-
|
|
371
|
-
|
|
213
|
+
class ApplicationController < ActionController::Base
|
|
214
|
+
private
|
|
215
|
+
|
|
216
|
+
def current_resource_owner
|
|
217
|
+
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
|
|
372
218
|
end
|
|
373
219
|
end
|
|
374
220
|
```
|
|
375
221
|
|
|
376
|
-
|
|
222
|
+
### Exclusions
|
|
377
223
|
|
|
378
|
-
|
|
224
|
+
Bots are excluded from tracking by default. To enable, use:
|
|
379
225
|
|
|
380
226
|
```ruby
|
|
381
|
-
|
|
382
|
-
|
|
227
|
+
Ahoy.track_bots = true
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Add your own rules with:
|
|
231
|
+
|
|
232
|
+
```ruby
|
|
233
|
+
Ahoy.exclude_method = lambda do |controller, request|
|
|
234
|
+
request.ip == "192.168.1.1"
|
|
383
235
|
end
|
|
384
236
|
```
|
|
385
237
|
|
|
386
|
-
|
|
238
|
+
### Visit Duration
|
|
387
239
|
|
|
388
|
-
|
|
240
|
+
By default, a new visit is created after 4 hours of inactivity. Change this with:
|
|
389
241
|
|
|
390
242
|
```ruby
|
|
391
|
-
|
|
243
|
+
Ahoy.visit_duration = 30.minutes
|
|
392
244
|
```
|
|
393
245
|
|
|
394
|
-
###
|
|
246
|
+
### Multiple Subdomains
|
|
395
247
|
|
|
396
|
-
To
|
|
248
|
+
To track visits across multiple subdomains, use:
|
|
397
249
|
|
|
398
250
|
```ruby
|
|
399
|
-
|
|
400
|
-
private
|
|
401
|
-
|
|
402
|
-
def current_resource_owner
|
|
403
|
-
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
|
|
404
|
-
end
|
|
405
|
-
end
|
|
251
|
+
Ahoy.cookie_domain = :all
|
|
406
252
|
```
|
|
407
253
|
|
|
408
254
|
### Geocoding
|
|
409
255
|
|
|
410
|
-
|
|
256
|
+
Disable geocoding with:
|
|
411
257
|
|
|
412
258
|
```ruby
|
|
413
|
-
Ahoy.geocode =
|
|
259
|
+
Ahoy.geocode = false
|
|
414
260
|
```
|
|
415
261
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
To change the queue name (`ahoy` by default), use:
|
|
262
|
+
Change the job queue with:
|
|
419
263
|
|
|
420
264
|
```ruby
|
|
421
265
|
Ahoy.job_queue = :low_priority
|
|
422
266
|
```
|
|
423
267
|
|
|
424
|
-
|
|
268
|
+
### Token Generation
|
|
269
|
+
|
|
270
|
+
Ahoy uses random UUIDs for visit and visitor tokens by default, but you can use your own generator like [Druuid](https://github.com/recurly/druuid).
|
|
425
271
|
|
|
426
272
|
```ruby
|
|
427
|
-
Ahoy.
|
|
273
|
+
Ahoy.token_generator = -> { Druuid.gen }
|
|
428
274
|
```
|
|
429
275
|
|
|
430
|
-
###
|
|
276
|
+
### Throttling
|
|
431
277
|
|
|
432
|
-
|
|
278
|
+
You can use [Rack::Attack](https://github.com/kickstarter/rack-attack) to throttle requests to the API.
|
|
433
279
|
|
|
434
280
|
```ruby
|
|
435
|
-
|
|
281
|
+
class Rack::Attack
|
|
282
|
+
throttle("ahoy/ip", limit: 20, period: 1.minute) do |req|
|
|
283
|
+
if req.path.start_with?("/ahoy/")
|
|
284
|
+
req.ip
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
436
288
|
```
|
|
437
289
|
|
|
438
|
-
|
|
290
|
+
### Exceptions
|
|
439
291
|
|
|
440
|
-
|
|
292
|
+
Exceptions are rescued so analytics do not break your app. Ahoy uses [Safely](https://github.com/ankane/safely) to try to report them to a service by default. To customize this, use:
|
|
441
293
|
|
|
442
294
|
```ruby
|
|
443
|
-
|
|
295
|
+
Safely.report_exception_method = ->(e) { Rollbar.error(e) }
|
|
444
296
|
```
|
|
445
297
|
|
|
446
298
|
## Development
|
|
447
299
|
|
|
448
|
-
Ahoy is built with developers in mind.
|
|
300
|
+
Ahoy is built with developers in mind. You can run the following code in your browser’s console.
|
|
449
301
|
|
|
450
302
|
Force a new visit
|
|
451
303
|
|
|
@@ -465,293 +317,162 @@ Turn off logging
|
|
|
465
317
|
ahoy.debug(false);
|
|
466
318
|
```
|
|
467
319
|
|
|
468
|
-
Debug
|
|
320
|
+
Debug API requests in Ruby
|
|
469
321
|
|
|
470
322
|
```ruby
|
|
471
323
|
Ahoy.quiet = false
|
|
472
324
|
```
|
|
473
325
|
|
|
474
|
-
##
|
|
475
|
-
|
|
476
|
-
How you explore the data depends on the data store used.
|
|
477
|
-
|
|
478
|
-
For SQL databases, you can use [Blazer](https://github.com/ankane/blazer) to easily generate charts and dashboards.
|
|
326
|
+
## Data Stores
|
|
479
327
|
|
|
480
|
-
|
|
328
|
+
Data tracked by Ahoy is sent to your data store. Ahoy ships with a data store that uses your Rails database by default. You can find it in `config/initializers/ahoy.rb`:
|
|
481
329
|
|
|
482
330
|
```ruby
|
|
483
|
-
|
|
484
|
-
Visit.group(:country).count
|
|
485
|
-
Visit.group(:referring_domain).count
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
[Chartkick](http://chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it easy to visualize the data.
|
|
489
|
-
|
|
490
|
-
```erb
|
|
491
|
-
<%= line_chart Visit.group_by_day(:started_at).count %>
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
See where orders are coming from with simple joins:
|
|
495
|
-
|
|
496
|
-
```ruby
|
|
497
|
-
Order.joins(:visit).group("referring_domain").count
|
|
498
|
-
Order.joins(:visit).group("city").count
|
|
499
|
-
Order.joins(:visit).group("device_type").count
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
To see the visits for a given user, create an association:
|
|
503
|
-
|
|
504
|
-
```ruby
|
|
505
|
-
class User < ActiveRecord::Base
|
|
506
|
-
has_many :visits
|
|
331
|
+
class Ahoy::Store < Ahoy::DatabaseStore
|
|
507
332
|
end
|
|
508
333
|
```
|
|
509
334
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
```ruby
|
|
513
|
-
user = User.first
|
|
514
|
-
user.visits
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
### Create Funnels
|
|
335
|
+
There are four events data stores can subscribe to:
|
|
518
336
|
|
|
519
337
|
```ruby
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
The same approach also works with visitor tokens.
|
|
526
|
-
|
|
527
|
-
### Querying Properties
|
|
528
|
-
|
|
529
|
-
With ActiveRecord, use:
|
|
338
|
+
class Ahoy::Store < Ahoy::BaseStore
|
|
339
|
+
def track_visit(data)
|
|
340
|
+
# new visit
|
|
341
|
+
end
|
|
530
342
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
343
|
+
def track_event(data)
|
|
344
|
+
# new event
|
|
345
|
+
end
|
|
534
346
|
|
|
535
|
-
|
|
347
|
+
def geocode(data)
|
|
348
|
+
# visit geocoded
|
|
349
|
+
end
|
|
536
350
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
class Event < ActiveRecord::Base
|
|
540
|
-
include Ahoy::Properties
|
|
541
|
-
...
|
|
351
|
+
def authenticate(data)
|
|
352
|
+
# user authenticates
|
|
542
353
|
end
|
|
543
354
|
end
|
|
544
355
|
```
|
|
545
356
|
|
|
546
|
-
|
|
357
|
+
Data stores are designed to be highly customizable so you can scale as you grow. Check out [examples](docs/Data-Store-Examples.md) for Kafka, RabbitMQ, Fluentd, NATS, NSQ, and Amazon Kinesis Firehose.
|
|
547
358
|
|
|
548
|
-
|
|
359
|
+
### Track Additional Data
|
|
549
360
|
|
|
550
361
|
```ruby
|
|
551
|
-
Ahoy
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
# limit number of requests to 100 requests every 5 minutes
|
|
558
|
-
Ahoy.throttle_limit = 100
|
|
559
|
-
Ahoy.throttle_period = 5.minutes
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
## Tutorials
|
|
563
|
-
|
|
564
|
-
- [Tracking Metrics with Ahoy and Blazer](https://gorails.com/episodes/internal-metrics-with-ahoy-and-blazer)
|
|
565
|
-
|
|
566
|
-
## Native Apps
|
|
567
|
-
|
|
568
|
-
### Visits
|
|
569
|
-
|
|
570
|
-
When a user launches the app, create a visit.
|
|
571
|
-
|
|
572
|
-
Generate a `visit_token` and `visitor_token` as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier).
|
|
573
|
-
|
|
574
|
-
Send these values in the `Ahoy-Visit` and `Ahoy-Visitor` headers with all requests.
|
|
575
|
-
|
|
576
|
-
Send a `POST` request to `/ahoy/visits` with:
|
|
577
|
-
|
|
578
|
-
- platform - `iOS`, `Android`, etc.
|
|
579
|
-
- app_version - `1.0.0`
|
|
580
|
-
- os_version - `7.0.6`
|
|
581
|
-
|
|
582
|
-
After 4 hours of inactivity, create another visit and use the updated visit id.
|
|
583
|
-
|
|
584
|
-
### Events
|
|
585
|
-
|
|
586
|
-
Send a `POST` request as `Content-Type: application/json` to `/ahoy/events` with:
|
|
587
|
-
|
|
588
|
-
- id - `5aea7b70-182d-4070-b062-b0a09699ad5e` - UUID
|
|
589
|
-
- name - `Viewed item`
|
|
590
|
-
- properties - `{"item_id": 123}`
|
|
591
|
-
- time - `2014-06-17T00:00:00-07:00` - [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)
|
|
592
|
-
- `Ahoy-Visit` and `Ahoy-Visitor` headers
|
|
593
|
-
- user token (depends on your authentication framework)
|
|
594
|
-
|
|
595
|
-
Use an array to pass multiple events at once.
|
|
596
|
-
|
|
597
|
-
## Reference
|
|
598
|
-
|
|
599
|
-
By default, Ahoy create endpoints at `/ahoy/visits` and `/ahoy/events`. To disable, use:
|
|
600
|
-
|
|
601
|
-
```ruby
|
|
602
|
-
Ahoy.mount = false
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
## Upgrading
|
|
606
|
-
|
|
607
|
-
### 1.4.0
|
|
608
|
-
|
|
609
|
-
There’s nothing mandatory to do, but it’s worth noting the default store was changed from `ActiveRecordStore` to `ActiveRecordTokenStore` for new installations. `ActiveRecordStore` will continue to be supported.
|
|
610
|
-
|
|
611
|
-
**Optional** Consider migrating `ahoy_events` table to have the following multi-column index as this *may* benefit
|
|
612
|
-
query performance depending on your usage:
|
|
613
|
-
|
|
614
|
-
```ruby
|
|
615
|
-
add_index :ahoy_events, [:name, :time]
|
|
362
|
+
class Ahoy::Store < Ahoy::DatabaseStore
|
|
363
|
+
def track_visit(data)
|
|
364
|
+
data[:accept_language] = request.headers["Accept-Language"]
|
|
365
|
+
super(data)
|
|
366
|
+
end
|
|
367
|
+
end
|
|
616
368
|
```
|
|
617
369
|
|
|
618
|
-
|
|
370
|
+
Two useful methods you can use are `request` and `controller`.
|
|
619
371
|
|
|
620
|
-
|
|
372
|
+
### Use Different Models
|
|
621
373
|
|
|
622
374
|
```ruby
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
Restart your web server immediately afterwards, as Ahoy will rescue and report errors until then.
|
|
628
|
-
|
|
629
|
-
Sync the new column.
|
|
375
|
+
class Ahoy::Store < Ahoy::DatabaseStore
|
|
376
|
+
def visit_model
|
|
377
|
+
MyVisit
|
|
378
|
+
end
|
|
630
379
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
380
|
+
def event_model
|
|
381
|
+
MyEvent
|
|
382
|
+
end
|
|
634
383
|
end
|
|
635
384
|
```
|
|
636
385
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
```ruby
|
|
640
|
-
remove_column :ahoy_events, :properties_json
|
|
641
|
-
```
|
|
386
|
+
## Explore the Data
|
|
642
387
|
|
|
643
|
-
|
|
388
|
+
[Blazer](https://github.com/ankane/blazer) is a great tool for exploring your data.
|
|
644
389
|
|
|
645
|
-
|
|
390
|
+
With ActiveRecord, you can do:
|
|
646
391
|
|
|
647
392
|
```ruby
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
393
|
+
Ahoy::Visit.group(:search_keyword).count
|
|
394
|
+
Ahoy::Visit.group(:country).count
|
|
395
|
+
Ahoy::Visit.group(:referring_domain).count
|
|
651
396
|
```
|
|
652
397
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
```ruby
|
|
656
|
-
module Ahoy
|
|
657
|
-
class Event < ActiveRecord::Base
|
|
658
|
-
self.table_name = "ahoy_events"
|
|
659
|
-
|
|
660
|
-
belongs_to :visit
|
|
661
|
-
belongs_to :user, polymorphic: true
|
|
398
|
+
[Chartkick](http://chartkick.com/) and [Groupdate](https://github.com/ankane/groupdate) make it easy to visualize the data.
|
|
662
399
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
end
|
|
400
|
+
```erb
|
|
401
|
+
<%= line_chart Ahoy::Visit.group_by_day(:started_at).count %>
|
|
666
402
|
```
|
|
667
403
|
|
|
668
|
-
|
|
404
|
+
### Querying Events
|
|
669
405
|
|
|
670
|
-
|
|
406
|
+
Ahoy provides two methods on the event model to make querying easier.
|
|
671
407
|
|
|
672
|
-
|
|
408
|
+
To query on both name and properties, you can use:
|
|
673
409
|
|
|
674
410
|
```ruby
|
|
675
|
-
|
|
676
|
-
belongs_to :user, polymorphic: true
|
|
677
|
-
end
|
|
411
|
+
Ahoy::Event.where_event("Viewed product", product_id: 123).count
|
|
678
412
|
```
|
|
679
413
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
Remove `uses_deprecated_subscribers` from `Ahoy::Store`.
|
|
683
|
-
|
|
684
|
-
If you have a custom subscriber, copy the `track` method to `track_event` in `Ahoy::Store`.
|
|
414
|
+
Or just query properties with:
|
|
685
415
|
|
|
686
416
|
```ruby
|
|
687
|
-
|
|
688
|
-
def track_event(name, properties, options)
|
|
689
|
-
# code copied from the track method in your subscriber
|
|
690
|
-
end
|
|
691
|
-
end
|
|
417
|
+
Ahoy::Event.where_props(product_id: 123).count
|
|
692
418
|
```
|
|
693
419
|
|
|
694
|
-
|
|
420
|
+
### Funnels
|
|
695
421
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
To restore this behavior, use:
|
|
422
|
+
It’s easy to create funnels.
|
|
699
423
|
|
|
700
424
|
```ruby
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
ahoy.track "$authenticate"
|
|
705
|
-
end
|
|
706
|
-
end
|
|
425
|
+
viewed_store_ids = Ahoy::Event.where(name: "Viewed store").distinct.pluck(:user_id)
|
|
426
|
+
added_item_ids = Ahoy::Event.where(user_id: viewed_store_ids, name: "Added item to cart").distinct.pluck(:user_id)
|
|
427
|
+
viewed_checkout_ids = Ahoy::Event.where(user_id: added_item_ids, name: "Viewed checkout").distinct.pluck(:user_id)
|
|
707
428
|
```
|
|
708
429
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
Replace the `Ahoy.user_method` with `user` method, and replace `Ahoy.track_bots` and `Ahoy.exclude_method` with `exclude?` method.
|
|
712
|
-
|
|
713
|
-
Skip this step if you do not use these options.
|
|
714
|
-
|
|
715
|
-
```ruby
|
|
716
|
-
class Ahoy::Store < Ahoy::Stores::ActiveRecordTokenStore
|
|
717
|
-
def user
|
|
718
|
-
# logic from Ahoy.user_method goes here
|
|
719
|
-
controller.true_user
|
|
720
|
-
end
|
|
430
|
+
The same approach also works with visitor tokens.
|
|
721
431
|
|
|
722
|
-
|
|
723
|
-
# logic from Ahoy.track_bots and Ahoy.exclude_method goes here
|
|
724
|
-
bot? || request.ip == "192.168.1.1"
|
|
725
|
-
end
|
|
726
|
-
end
|
|
727
|
-
```
|
|
432
|
+
## Tutorials
|
|
728
433
|
|
|
729
|
-
|
|
434
|
+
- [Tracking Metrics with Ahoy and Blazer](https://gorails.com/episodes/internal-metrics-with-ahoy-and-blazer)
|
|
730
435
|
|
|
731
|
-
|
|
436
|
+
## API Spec
|
|
732
437
|
|
|
733
|
-
|
|
438
|
+
### Visits
|
|
734
439
|
|
|
735
|
-
|
|
440
|
+
Generate visit and visitor tokens as [UUIDs](http://en.wikipedia.org/wiki/Universally_unique_identifier), and include these values in the `Ahoy-Visit` and `Ahoy-Visitor` headers with all requests.
|
|
736
441
|
|
|
737
|
-
|
|
442
|
+
Send a `POST` request to `/ahoy/visits` with `Content-Type: application/json` and a body like:
|
|
738
443
|
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
visit
|
|
742
|
-
|
|
743
|
-
|
|
444
|
+
```json
|
|
445
|
+
{
|
|
446
|
+
"visit_token": "<visit-token>",
|
|
447
|
+
"visitor_token": "<visitor-token>",
|
|
448
|
+
"platform": "iOS",
|
|
449
|
+
"app_version": "1.0.0",
|
|
450
|
+
"os_version": "11.2.6"
|
|
451
|
+
}
|
|
744
452
|
```
|
|
745
453
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
- real-time dashboard of visits and events
|
|
749
|
-
- more events for append only stores
|
|
750
|
-
- turn off modules
|
|
454
|
+
After 4 hours of inactivity, create another visit (use the same visitor token).
|
|
751
455
|
|
|
752
|
-
|
|
456
|
+
### Events
|
|
753
457
|
|
|
754
|
-
|
|
458
|
+
Send a `POST` request to `/ahoy/events` with `Content-Type: application/json` and a body like:
|
|
459
|
+
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"visit_token": "<visit-token>",
|
|
463
|
+
"visitor_token": "<visitor-token>",
|
|
464
|
+
"events": [
|
|
465
|
+
{
|
|
466
|
+
"id": "<optional-random-id>",
|
|
467
|
+
"name": "Viewed item",
|
|
468
|
+
"properties": {
|
|
469
|
+
"item_id": 123
|
|
470
|
+
},
|
|
471
|
+
"time": "2018-01-01T00:00:00-07:00"
|
|
472
|
+
}
|
|
473
|
+
]
|
|
474
|
+
}
|
|
475
|
+
```
|
|
755
476
|
|
|
756
477
|
## History
|
|
757
478
|
|