@datalyr/api 1.0.3 → 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 +43 -8
- package/dist/index.mjs +43 -8
- 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,24 +63,46 @@ 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
|
-
version: "1.0.
|
|
103
|
+
version: "1.0.4",
|
|
104
|
+
source: "api"
|
|
105
|
+
// Explicitly set source for server-side API
|
|
83
106
|
},
|
|
84
107
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
85
108
|
};
|
|
@@ -89,7 +112,10 @@ var Datalyr = class {
|
|
|
89
112
|
if (!userId) {
|
|
90
113
|
throw new Error("userId is required for identify");
|
|
91
114
|
}
|
|
92
|
-
return this.track(userId, "$identify", {
|
|
115
|
+
return this.track(userId, "$identify", {
|
|
116
|
+
$set: traits,
|
|
117
|
+
anonymous_id: this.getOrCreateAnonymousId()
|
|
118
|
+
});
|
|
93
119
|
}
|
|
94
120
|
async page(userId, name, properties) {
|
|
95
121
|
return this.track(userId, "$pageview", { name, ...properties });
|
|
@@ -217,6 +243,15 @@ var Datalyr = class {
|
|
|
217
243
|
generateAnonymousId() {
|
|
218
244
|
return "anon_" + Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
219
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
|
+
}
|
|
220
255
|
// Cleanup
|
|
221
256
|
async close() {
|
|
222
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,24 +38,46 @@ 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
|
-
version: "1.0.
|
|
78
|
+
version: "1.0.4",
|
|
79
|
+
source: "api"
|
|
80
|
+
// Explicitly set source for server-side API
|
|
58
81
|
},
|
|
59
82
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
60
83
|
};
|
|
@@ -64,7 +87,10 @@ var Datalyr = class {
|
|
|
64
87
|
if (!userId) {
|
|
65
88
|
throw new Error("userId is required for identify");
|
|
66
89
|
}
|
|
67
|
-
return this.track(userId, "$identify", {
|
|
90
|
+
return this.track(userId, "$identify", {
|
|
91
|
+
$set: traits,
|
|
92
|
+
anonymous_id: this.getOrCreateAnonymousId()
|
|
93
|
+
});
|
|
68
94
|
}
|
|
69
95
|
async page(userId, name, properties) {
|
|
70
96
|
return this.track(userId, "$pageview", { name, ...properties });
|
|
@@ -192,6 +218,15 @@ var Datalyr = class {
|
|
|
192
218
|
generateAnonymousId() {
|
|
193
219
|
return "anon_" + Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
194
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
|
+
}
|
|
195
230
|
// Cleanup
|
|
196
231
|
async close() {
|
|
197
232
|
this.isClosing = true;
|