@datalyr/api 1.0.4 → 1.1.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.
- package/README.md +52 -1
- package/dist/index.d.mts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +40 -7
- package/dist/index.mjs +40 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @datalyr/api
|
|
2
2
|
|
|
3
|
-
Official API SDK for Datalyr server-side tracking.
|
|
3
|
+
Official API SDK for Datalyr server-side tracking with identity resolution support.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -52,6 +52,57 @@ await datalyr.group('user_123', 'company_456', {
|
|
|
52
52
|
await datalyr.close();
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
## Identity Resolution (New in v1.1.0)
|
|
56
|
+
|
|
57
|
+
The SDK now supports anonymous IDs for complete user journey tracking:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// Option 1: Pass anonymous_id from browser/mobile for attribution preservation
|
|
61
|
+
await datalyr.track({
|
|
62
|
+
event: 'Purchase Completed',
|
|
63
|
+
userId: 'user_123',
|
|
64
|
+
anonymousId: req.body.anonymous_id, // From browser/mobile SDK
|
|
65
|
+
properties: {
|
|
66
|
+
amount: 99.99,
|
|
67
|
+
currency: 'USD'
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Option 2: Use legacy signature (SDK generates anonymous_id)
|
|
72
|
+
await datalyr.track('user_123', 'Purchase Completed', {
|
|
73
|
+
amount: 99.99
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Get the SDK's anonymous ID (useful for server-only tracking)
|
|
77
|
+
const anonymousId = datalyr.getAnonymousId();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Express.js Example with Browser Attribution
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
app.post('/api/purchase', async (req, res) => {
|
|
84
|
+
const { items, anonymous_id } = req.body; // anonymous_id from browser
|
|
85
|
+
|
|
86
|
+
// Track with anonymous_id to preserve attribution (fbclid, gclid, etc.)
|
|
87
|
+
await datalyr.track({
|
|
88
|
+
event: 'Purchase Completed',
|
|
89
|
+
userId: req.user?.id,
|
|
90
|
+
anonymousId: anonymous_id, // Links to browser events!
|
|
91
|
+
properties: {
|
|
92
|
+
total: calculateTotal(items),
|
|
93
|
+
items: items.length
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
res.json({ success: true });
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Key Benefits:
|
|
102
|
+
- **Attribution Preservation**: Never lose fbclid, gclid, ttclid, or lyr tracking
|
|
103
|
+
- **Complete Journey**: Track users from web → server → mobile
|
|
104
|
+
- **Flexible API**: Support both legacy and new tracking methods
|
|
105
|
+
|
|
55
106
|
## Configuration
|
|
56
107
|
|
|
57
108
|
```javascript
|
package/dist/index.d.mts
CHANGED
|
@@ -16,6 +16,12 @@ interface TrackEvent {
|
|
|
16
16
|
context?: Record<string, any>;
|
|
17
17
|
timestamp?: string;
|
|
18
18
|
}
|
|
19
|
+
interface TrackOptions {
|
|
20
|
+
userId?: string;
|
|
21
|
+
anonymousId?: string;
|
|
22
|
+
event: string;
|
|
23
|
+
properties?: Record<string, any>;
|
|
24
|
+
}
|
|
19
25
|
declare class Datalyr {
|
|
20
26
|
private apiKey;
|
|
21
27
|
private host;
|
|
@@ -29,7 +35,9 @@ declare class Datalyr {
|
|
|
29
35
|
private timer?;
|
|
30
36
|
private isFlushing;
|
|
31
37
|
private isClosing;
|
|
38
|
+
private anonymousId?;
|
|
32
39
|
constructor(config: DatalyrConfig | string);
|
|
40
|
+
track(options: TrackOptions): Promise<void>;
|
|
33
41
|
track(userId: string | null, event: string, properties?: any): Promise<void>;
|
|
34
42
|
identify(userId: string, traits?: any): Promise<void>;
|
|
35
43
|
page(userId: string, name?: string, properties?: any): Promise<void>;
|
|
@@ -39,7 +47,9 @@ declare class Datalyr {
|
|
|
39
47
|
private sendEvent;
|
|
40
48
|
private startFlushTimer;
|
|
41
49
|
private generateAnonymousId;
|
|
50
|
+
private getOrCreateAnonymousId;
|
|
51
|
+
getAnonymousId(): string;
|
|
42
52
|
close(): Promise<void>;
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
export { Datalyr, type DatalyrConfig, type TrackEvent, Datalyr as default };
|
|
55
|
+
export { Datalyr, type DatalyrConfig, type TrackEvent, type TrackOptions, Datalyr as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,12 @@ interface TrackEvent {
|
|
|
16
16
|
context?: Record<string, any>;
|
|
17
17
|
timestamp?: string;
|
|
18
18
|
}
|
|
19
|
+
interface TrackOptions {
|
|
20
|
+
userId?: string;
|
|
21
|
+
anonymousId?: string;
|
|
22
|
+
event: string;
|
|
23
|
+
properties?: Record<string, any>;
|
|
24
|
+
}
|
|
19
25
|
declare class Datalyr {
|
|
20
26
|
private apiKey;
|
|
21
27
|
private host;
|
|
@@ -29,7 +35,9 @@ declare class Datalyr {
|
|
|
29
35
|
private timer?;
|
|
30
36
|
private isFlushing;
|
|
31
37
|
private isClosing;
|
|
38
|
+
private anonymousId?;
|
|
32
39
|
constructor(config: DatalyrConfig | string);
|
|
40
|
+
track(options: TrackOptions): Promise<void>;
|
|
33
41
|
track(userId: string | null, event: string, properties?: any): Promise<void>;
|
|
34
42
|
identify(userId: string, traits?: any): Promise<void>;
|
|
35
43
|
page(userId: string, name?: string, properties?: any): Promise<void>;
|
|
@@ -39,7 +47,9 @@ declare class Datalyr {
|
|
|
39
47
|
private sendEvent;
|
|
40
48
|
private startFlushTimer;
|
|
41
49
|
private generateAnonymousId;
|
|
50
|
+
private getOrCreateAnonymousId;
|
|
51
|
+
getAnonymousId(): string;
|
|
42
52
|
close(): Promise<void>;
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
export { Datalyr, type DatalyrConfig, type TrackEvent, Datalyr as default };
|
|
55
|
+
export { Datalyr, type DatalyrConfig, type TrackEvent, type TrackOptions, Datalyr as default };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
var Datalyr = class {
|
|
28
|
+
// Persistent anonymous ID for identity resolution
|
|
28
29
|
constructor(config) {
|
|
29
30
|
this.queue = [];
|
|
30
31
|
this.isFlushing = false;
|
|
@@ -62,21 +63,41 @@ var Datalyr = class {
|
|
|
62
63
|
if (this.maxQueueSize > 1e4) this.maxQueueSize = 1e4;
|
|
63
64
|
this.startFlushTimer();
|
|
64
65
|
}
|
|
65
|
-
async track(
|
|
66
|
+
async track(userIdOrOptions, event, properties) {
|
|
66
67
|
if (this.isClosing) {
|
|
67
68
|
if (this.debug) {
|
|
68
|
-
console.warn("[Datalyr] SDK is closing, event dropped
|
|
69
|
+
console.warn("[Datalyr] SDK is closing, event dropped");
|
|
69
70
|
}
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
+
let userId;
|
|
74
|
+
let eventName;
|
|
75
|
+
let eventProperties;
|
|
76
|
+
let providedAnonymousId;
|
|
77
|
+
if (typeof userIdOrOptions === "object" && userIdOrOptions !== null) {
|
|
78
|
+
userId = userIdOrOptions.userId;
|
|
79
|
+
eventName = userIdOrOptions.event;
|
|
80
|
+
eventProperties = userIdOrOptions.properties || {};
|
|
81
|
+
providedAnonymousId = userIdOrOptions.anonymousId;
|
|
82
|
+
} else {
|
|
83
|
+
userId = userIdOrOptions || void 0;
|
|
84
|
+
eventName = event;
|
|
85
|
+
eventProperties = properties || {};
|
|
86
|
+
}
|
|
87
|
+
if (!eventName || typeof eventName !== "string") {
|
|
73
88
|
throw new Error("Event name is required and must be a string");
|
|
74
89
|
}
|
|
90
|
+
const anonymousId = providedAnonymousId || this.getOrCreateAnonymousId();
|
|
91
|
+
const enrichedProperties = {
|
|
92
|
+
...eventProperties,
|
|
93
|
+
anonymous_id: anonymousId
|
|
94
|
+
};
|
|
75
95
|
const trackEvent = {
|
|
76
96
|
userId: userId || void 0,
|
|
77
|
-
anonymousId
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
anonymousId,
|
|
98
|
+
// Always include for identity resolution
|
|
99
|
+
event: eventName,
|
|
100
|
+
properties: enrichedProperties,
|
|
80
101
|
context: {
|
|
81
102
|
library: "@datalyr/api",
|
|
82
103
|
version: "1.0.4",
|
|
@@ -91,7 +112,10 @@ var Datalyr = class {
|
|
|
91
112
|
if (!userId) {
|
|
92
113
|
throw new Error("userId is required for identify");
|
|
93
114
|
}
|
|
94
|
-
return this.track(userId, "$identify", {
|
|
115
|
+
return this.track(userId, "$identify", {
|
|
116
|
+
$set: traits,
|
|
117
|
+
anonymous_id: this.getOrCreateAnonymousId()
|
|
118
|
+
});
|
|
95
119
|
}
|
|
96
120
|
async page(userId, name, properties) {
|
|
97
121
|
return this.track(userId, "$pageview", { name, ...properties });
|
|
@@ -219,6 +243,15 @@ var Datalyr = class {
|
|
|
219
243
|
generateAnonymousId() {
|
|
220
244
|
return "anon_" + Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
221
245
|
}
|
|
246
|
+
getOrCreateAnonymousId() {
|
|
247
|
+
if (!this.anonymousId) {
|
|
248
|
+
this.anonymousId = this.generateAnonymousId();
|
|
249
|
+
}
|
|
250
|
+
return this.anonymousId;
|
|
251
|
+
}
|
|
252
|
+
getAnonymousId() {
|
|
253
|
+
return this.getOrCreateAnonymousId();
|
|
254
|
+
}
|
|
222
255
|
// Cleanup
|
|
223
256
|
async close() {
|
|
224
257
|
this.isClosing = true;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
var Datalyr = class {
|
|
3
|
+
// Persistent anonymous ID for identity resolution
|
|
3
4
|
constructor(config) {
|
|
4
5
|
this.queue = [];
|
|
5
6
|
this.isFlushing = false;
|
|
@@ -37,21 +38,41 @@ var Datalyr = class {
|
|
|
37
38
|
if (this.maxQueueSize > 1e4) this.maxQueueSize = 1e4;
|
|
38
39
|
this.startFlushTimer();
|
|
39
40
|
}
|
|
40
|
-
async track(
|
|
41
|
+
async track(userIdOrOptions, event, properties) {
|
|
41
42
|
if (this.isClosing) {
|
|
42
43
|
if (this.debug) {
|
|
43
|
-
console.warn("[Datalyr] SDK is closing, event dropped
|
|
44
|
+
console.warn("[Datalyr] SDK is closing, event dropped");
|
|
44
45
|
}
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
let userId;
|
|
49
|
+
let eventName;
|
|
50
|
+
let eventProperties;
|
|
51
|
+
let providedAnonymousId;
|
|
52
|
+
if (typeof userIdOrOptions === "object" && userIdOrOptions !== null) {
|
|
53
|
+
userId = userIdOrOptions.userId;
|
|
54
|
+
eventName = userIdOrOptions.event;
|
|
55
|
+
eventProperties = userIdOrOptions.properties || {};
|
|
56
|
+
providedAnonymousId = userIdOrOptions.anonymousId;
|
|
57
|
+
} else {
|
|
58
|
+
userId = userIdOrOptions || void 0;
|
|
59
|
+
eventName = event;
|
|
60
|
+
eventProperties = properties || {};
|
|
61
|
+
}
|
|
62
|
+
if (!eventName || typeof eventName !== "string") {
|
|
48
63
|
throw new Error("Event name is required and must be a string");
|
|
49
64
|
}
|
|
65
|
+
const anonymousId = providedAnonymousId || this.getOrCreateAnonymousId();
|
|
66
|
+
const enrichedProperties = {
|
|
67
|
+
...eventProperties,
|
|
68
|
+
anonymous_id: anonymousId
|
|
69
|
+
};
|
|
50
70
|
const trackEvent = {
|
|
51
71
|
userId: userId || void 0,
|
|
52
|
-
anonymousId
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
anonymousId,
|
|
73
|
+
// Always include for identity resolution
|
|
74
|
+
event: eventName,
|
|
75
|
+
properties: enrichedProperties,
|
|
55
76
|
context: {
|
|
56
77
|
library: "@datalyr/api",
|
|
57
78
|
version: "1.0.4",
|
|
@@ -66,7 +87,10 @@ var Datalyr = class {
|
|
|
66
87
|
if (!userId) {
|
|
67
88
|
throw new Error("userId is required for identify");
|
|
68
89
|
}
|
|
69
|
-
return this.track(userId, "$identify", {
|
|
90
|
+
return this.track(userId, "$identify", {
|
|
91
|
+
$set: traits,
|
|
92
|
+
anonymous_id: this.getOrCreateAnonymousId()
|
|
93
|
+
});
|
|
70
94
|
}
|
|
71
95
|
async page(userId, name, properties) {
|
|
72
96
|
return this.track(userId, "$pageview", { name, ...properties });
|
|
@@ -194,6 +218,15 @@ var Datalyr = class {
|
|
|
194
218
|
generateAnonymousId() {
|
|
195
219
|
return "anon_" + Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
196
220
|
}
|
|
221
|
+
getOrCreateAnonymousId() {
|
|
222
|
+
if (!this.anonymousId) {
|
|
223
|
+
this.anonymousId = this.generateAnonymousId();
|
|
224
|
+
}
|
|
225
|
+
return this.anonymousId;
|
|
226
|
+
}
|
|
227
|
+
getAnonymousId() {
|
|
228
|
+
return this.getOrCreateAnonymousId();
|
|
229
|
+
}
|
|
197
230
|
// Cleanup
|
|
198
231
|
async close() {
|
|
199
232
|
this.isClosing = true;
|