Skip to content
This repository was archived by the owner on Feb 7, 2022. It is now read-only.

Commit 2e3b66a

Browse files
authored
Feature/statefull version (#3)
* implement queue * improve public api * implement batching * implement test mocks
1 parent f11c2ae commit 2e3b66a

File tree

12 files changed

+1167
-199
lines changed

12 files changed

+1167
-199
lines changed

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending every file
7+
[*]
8+
end_of_line = lf
9+
insert_final_newline = true
10+
charset = utf-8
11+
indent_size = 2
12+
indent_style = space

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
6.9

LICENSE

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
ISC License
2+
3+
Copyright (c) 2017, GlobalWebIndex
4+
5+
Permission to use, copy, modify, and/or distribute this software for any
6+
purpose with or without fee is hereby granted, provided that the above
7+
copyright notice and this permission notice appear in all copies.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14+
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15+
PERFORMANCE OF THIS SOFTWARE.

README.md

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,65 @@
11
# Segment
22

3-
A Segment analytics library using the HTTP api directly. The reason for this library is to delegate the responsibility of distributing data across integrations to Segment itself after having countless issues with data inconsistencies, because the official Segment way is to let the browser itself take care of all the integrations. That of course creates problems with ad-blockers.
3+
This is an unofficial alternative to [analytics.js](https://segment.com/docs/sources/website/analytics.js/) by [segment.io](https://segment.io).
4+
Unlike original implementation this library speaks with Segment's API directly and delegates responsibility of data distribution to back-end (as official Ruby, Java, Clojure, Python and many others do).
5+
This helps you to prevent many issues with data inconsistency between various back-ends and optimize number of HTTP payloads required for tracks.
6+
This library also comes with few other improvements over official one namely it uses **batch api** to prevent issues with [rate limits](https://segment.com/docs/sources/server/http/#rate-limits),
7+
prevents tracks without `userId` by using internal queue, has **Promise** API to make easy to reason about async actions and **comes with test mocks** you can use in your test suit.
8+
9+
## What if I actually want to track event before calling identify?
10+
11+
No problem with that. Just use `anonymousTrack` or `anonymousPage`.
12+
13+
## Demo
14+
15+
![demo](http://i.imgur.com/EGNqJLS.gif)
416

517
## Usage
618

7-
### Installation
19+
At first install this using npm:
820

921
```
1022
$ npm install gwi-segment --save
1123
```
1224

13-
### Client initialization
25+
### The Most Simple Use-Case
26+
27+
In most cases you want to just initialize library and store instance to global singleton object like this:
1428

1529
```javascript
1630
const Segment = require('gwi-segment');
1731

18-
// Optional
19-
const additionContext = {
20-
app: 'My Supreme Application'
21-
};
32+
window.segment = Segment.getClient('YOUR_SEGMENT_WRITE_KEY');
33+
```
2234

23-
// Optional
24-
// window.btoa is the default if you do not provide this argument
25-
// and it is used to generate the right authentication header from your key
26-
const btoa = window.btoa
35+
in case you need more instances or fancier implementation of static object you're free to do it as you wish!
2736

28-
var segment = Segment.getClient(YOUR_SEGMENT_WRITE_KEY, additionalContext, btoa);
29-
```
37+
## Api Reference
38+
39+
This is all you have available for production usage:
40+
41+
### Static Initialization
42+
43+
User static `getClient()` function to initialize instance of client. This is api of that function:
44+
45+
- `writeKey` [string] - your segment.io write key. **required**
46+
- `options` [object] - custom settings. **optional**
47+
- `context` [object] - custom meta to be added to segment's context record.
48+
- `timeout` [number] - bulk "debounce" timeout in ms. default: 100; use `-1` for instant (sync) requests.
49+
50+
Calling `getClient()` returns instance of api client. This object implements this public interface:
3051

3152
### #identify
3253

54+
Used for identifying user. Id of user is than used in all `track` and `page` calls.
55+
56+
- `userId` [string] - identification of user **required**
57+
- `traits` [object] - additional user information **optional**
58+
59+
**returns promise.**
60+
61+
#### Example
62+
3363
```javascript
3464
const userId = 'someId';
3565

@@ -42,19 +72,37 @@ segment.identify(userId, traits);
4272

4373
### #track
4474

75+
Main method for tracking user's action in your application.
76+
77+
- `event` [string] - name/id of event **required**
78+
- `properties` - additional information to event **optional**
79+
80+
**returns promise.**
81+
82+
#### Example
83+
4584
```javascript
46-
const userId = 'someId';
4785
const event = 'Clicked a CTA'
4886

4987
const properties = {
5088
ctaId: 'foo'
5189
};
5290

53-
segment.track(userId, event, properties);
91+
segment.track(event, properties);
5492
```
5593

5694
### #anonymousTrack
5795

96+
Same as track but doesn't require `identify` call (to get `userId` to track).
97+
98+
- `anonymousId` [string] - value that will be send as user id just for this track
99+
- `event` [string] - name/id of event **required**
100+
- `properties` - additional information to event **optional**
101+
102+
**returns promise.**
103+
104+
#### Example
105+
58106
```javascript
59107
const anonymousId = '123abc';
60108
const event = 'Clicked a CTA'
@@ -68,19 +116,35 @@ segment.anonymousTrack(anonymousId, event, properties);
68116

69117
### #page
70118

119+
Used for tracking page event.
120+
121+
- `name` [string] - name/id of page displayed **required**
122+
- `properties` [object] - addition information **optional**
123+
124+
**returns promise.**
125+
126+
#### Example
127+
71128
```javascript
72-
const userId = 'someId';
73129
const name = 'Index Page'
74130

75131
const properties = {
76132
referrer: 'www.google.com'
77133
};
78134

79-
segment.page(userId, name, properties);
135+
segment.page(name, properties);
80136
```
81137

82138
### #anonymousPage
83139

140+
Same as `page` but doesn't require `identify` call (to get `userId` for page event).
141+
142+
- `anonymousId` [string] - value that will be send as user id just for this track
143+
- `name` [string] - name/id of page displayed **required**
144+
- `properties` [object] - addition information **optional**
145+
146+
**returns promise.**
147+
84148
```javascript
85149
const anonymousId = '123abc';
86150
const name = 'Index Page'
@@ -92,6 +156,47 @@ const properties = {
92156
segment.anonymousPage(anonymousId, name, properties);
93157
```
94158

159+
## How Queue and Waiting For UserId Works
160+
161+
No `#track` nor `#page` call is proceed before `#identify` is called. This is to prevent events with missing `userId` to go through the system.
162+
All events happened before `#identify` are added to queue and are waiting for userId. Once `#identify` is called `userId` from this call is used
163+
for all waiting events which are waiting. Events are then tracked in order they were added to queue.
164+
165+
## How Batching Works
166+
167+
By default there is `100`ms timeout for collecting all tracks into single [batch](https://segment.com/docs/sources/server/http/#batch) request. This means events are not sent immediately
168+
but are collected into one single request. This helps you to overcome issue with [rate limits](https://segment.com/docs/sources/server/http/#rate-limits) and optimize requests from app or website.
169+
You can change default timeout using `options.timeout` or disable it completely by passing `-1` as timeout value.
170+
171+
## Test Mocking
172+
173+
Similarly to main client you can initialize test mock instead. This is done using `getTestMockClient()` static function and returns instance implementing default API.
174+
However this client doesn't really speaks to API but instead pushes events into internal stack. Also this client doesn't perform any merging to batch API
175+
but rather keeps all events isolated to make it easier to use in test suit. Public api still uses promises as production one but in fact works synchronously to make your tests simpler and faster.
176+
It also contains extra `inspect` name-space for checking state of tracks.
177+
178+
### #inspect.allEvents
179+
180+
Returns array of all events tracked (including identify and page).
181+
182+
*no arguments*
183+
184+
### #inspect.lastEvent
185+
186+
Returns last event tracked (including identify and page).
187+
188+
*no arguments*
189+
190+
### #inspect.clearEvents
191+
192+
Clears state of test mock.
193+
194+
*no arguments*
195+
196+
## Support
197+
198+
This package supports Node 0.12 and higher.
199+
95200
## Licence
96201

97202
[ISC](https://en.wikipedia.org/wiki/ISC_license)

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gwi-segment",
3-
"version": "1.0.1",
3+
"version": "2.0.0",
44
"description": "Tracking library using Segment's HTTP API directly",
55
"scripts": {
66
"test": "jasmine"
@@ -21,11 +21,11 @@
2121
},
2222
"homepage": "https://github.com/GlobalWebIndex/segment#readme",
2323
"devDependencies": {
24-
"btoa": "^1.1.2",
2524
"fetch-mock": "^5.9.4",
2625
"jasmine": "^2.5.3"
2726
},
2827
"dependencies": {
28+
"btoa": "^1.1.2",
2929
"es6-promise": "^4.1.0",
3030
"isomorphic-fetch": "^2.2.1"
3131
}

0 commit comments

Comments
 (0)