@datalyr/react-native 1.1.0 → 1.1.1
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/lib/attribution.d.ts +5 -0
- package/lib/attribution.js +39 -0
- package/lib/datalyr-sdk.d.ts +5 -0
- package/lib/datalyr-sdk.js +66 -0
- package/lib/types.d.ts +1 -0
- package/package.json +2 -1
- package/src/attribution.ts +45 -0
- package/src/datalyr-sdk.ts +80 -4
- package/src/types.ts +1 -1
package/lib/attribution.d.ts
CHANGED
|
@@ -95,6 +95,11 @@ export declare class AttributionManager {
|
|
|
95
95
|
* Track install event with attribution data
|
|
96
96
|
*/
|
|
97
97
|
trackInstall(): Promise<AttributionData>;
|
|
98
|
+
/**
|
|
99
|
+
* Merge web attribution data into mobile session
|
|
100
|
+
* Called when web-to-app attribution is resolved via email
|
|
101
|
+
*/
|
|
102
|
+
mergeWebAttribution(webAttribution: any): void;
|
|
98
103
|
/**
|
|
99
104
|
* Set custom attribution data
|
|
100
105
|
*/
|
package/lib/attribution.js
CHANGED
|
@@ -335,6 +335,45 @@ export class AttributionManager {
|
|
|
335
335
|
}
|
|
336
336
|
return this.attributionData;
|
|
337
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Merge web attribution data into mobile session
|
|
340
|
+
* Called when web-to-app attribution is resolved via email
|
|
341
|
+
*/
|
|
342
|
+
mergeWebAttribution(webAttribution) {
|
|
343
|
+
debugLog('Merging web attribution data:', webAttribution);
|
|
344
|
+
// Only merge if we don't already have attribution data
|
|
345
|
+
// Web attribution takes precedence for first-touch
|
|
346
|
+
if (!this.attributionData.fbclid && webAttribution.fbclid) {
|
|
347
|
+
this.attributionData.fbclid = webAttribution.fbclid;
|
|
348
|
+
}
|
|
349
|
+
if (!this.attributionData.gclid && webAttribution.gclid) {
|
|
350
|
+
this.attributionData.gclid = webAttribution.gclid;
|
|
351
|
+
}
|
|
352
|
+
if (!this.attributionData.ttclid && webAttribution.ttclid) {
|
|
353
|
+
this.attributionData.ttclid = webAttribution.ttclid;
|
|
354
|
+
}
|
|
355
|
+
// Merge UTM parameters
|
|
356
|
+
if (!this.attributionData.utm_source && webAttribution.utm_source) {
|
|
357
|
+
this.attributionData.utm_source = webAttribution.utm_source;
|
|
358
|
+
}
|
|
359
|
+
if (!this.attributionData.utm_medium && webAttribution.utm_medium) {
|
|
360
|
+
this.attributionData.utm_medium = webAttribution.utm_medium;
|
|
361
|
+
}
|
|
362
|
+
if (!this.attributionData.utm_campaign && webAttribution.utm_campaign) {
|
|
363
|
+
this.attributionData.utm_campaign = webAttribution.utm_campaign;
|
|
364
|
+
}
|
|
365
|
+
if (!this.attributionData.utm_content && webAttribution.utm_content) {
|
|
366
|
+
this.attributionData.utm_content = webAttribution.utm_content;
|
|
367
|
+
}
|
|
368
|
+
if (!this.attributionData.utm_term && webAttribution.utm_term) {
|
|
369
|
+
this.attributionData.utm_term = webAttribution.utm_term;
|
|
370
|
+
}
|
|
371
|
+
// Store web visitor ID for cross-device tracking
|
|
372
|
+
this.attributionData.web_visitor_id = webAttribution.visitor_id;
|
|
373
|
+
// Save merged attribution data
|
|
374
|
+
this.saveAttributionData();
|
|
375
|
+
debugLog('Web attribution merged successfully');
|
|
376
|
+
}
|
|
338
377
|
/**
|
|
339
378
|
* Set custom attribution data
|
|
340
379
|
*/
|
package/lib/datalyr-sdk.d.ts
CHANGED
|
@@ -26,6 +26,11 @@ export declare class DatalyrSDK {
|
|
|
26
26
|
* Identify a user
|
|
27
27
|
*/
|
|
28
28
|
identify(userId: string, properties?: UserProperties): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Fetch web attribution data for user and merge into mobile session
|
|
31
|
+
* Called automatically during identify() if email is provided
|
|
32
|
+
*/
|
|
33
|
+
private fetchAndMergeWebAttribution;
|
|
29
34
|
/**
|
|
30
35
|
* Alias a user (connect anonymous user to known user)
|
|
31
36
|
*/
|
package/lib/datalyr-sdk.js
CHANGED
|
@@ -200,11 +200,77 @@ export class DatalyrSDK {
|
|
|
200
200
|
anonymous_id: this.state.anonymousId,
|
|
201
201
|
...properties
|
|
202
202
|
});
|
|
203
|
+
// Fetch and merge web attribution if email is provided
|
|
204
|
+
if (this.state.config.enableWebToAppAttribution !== false) {
|
|
205
|
+
const email = (properties === null || properties === void 0 ? void 0 : properties.email) || (typeof userId === 'string' && userId.includes('@') ? userId : null);
|
|
206
|
+
if (email) {
|
|
207
|
+
await this.fetchAndMergeWebAttribution(email);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
203
210
|
}
|
|
204
211
|
catch (error) {
|
|
205
212
|
errorLog('Error identifying user:', error);
|
|
206
213
|
}
|
|
207
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Fetch web attribution data for user and merge into mobile session
|
|
217
|
+
* Called automatically during identify() if email is provided
|
|
218
|
+
*/
|
|
219
|
+
async fetchAndMergeWebAttribution(email) {
|
|
220
|
+
try {
|
|
221
|
+
debugLog('Fetching web attribution for email:', email);
|
|
222
|
+
// Call API endpoint to get web attribution
|
|
223
|
+
const response = await fetch('https://api.datalyr.com/attribution/lookup', {
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: {
|
|
226
|
+
'Content-Type': 'application/json',
|
|
227
|
+
'X-Datalyr-API-Key': this.state.config.apiKey,
|
|
228
|
+
},
|
|
229
|
+
body: JSON.stringify({ email }),
|
|
230
|
+
});
|
|
231
|
+
if (!response.ok) {
|
|
232
|
+
debugLog('Failed to fetch web attribution:', response.status);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const result = await response.json();
|
|
236
|
+
if (!result.found || !result.attribution) {
|
|
237
|
+
debugLog('No web attribution found for user');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const webAttribution = result.attribution;
|
|
241
|
+
debugLog('Web attribution found:', {
|
|
242
|
+
visitor_id: webAttribution.visitor_id,
|
|
243
|
+
has_fbclid: !!webAttribution.fbclid,
|
|
244
|
+
has_gclid: !!webAttribution.gclid,
|
|
245
|
+
utm_source: webAttribution.utm_source,
|
|
246
|
+
});
|
|
247
|
+
// Merge web attribution into current session
|
|
248
|
+
await this.track('$web_attribution_merged', {
|
|
249
|
+
web_visitor_id: webAttribution.visitor_id,
|
|
250
|
+
web_user_id: webAttribution.user_id,
|
|
251
|
+
fbclid: webAttribution.fbclid,
|
|
252
|
+
gclid: webAttribution.gclid,
|
|
253
|
+
ttclid: webAttribution.ttclid,
|
|
254
|
+
gbraid: webAttribution.gbraid,
|
|
255
|
+
wbraid: webAttribution.wbraid,
|
|
256
|
+
fbp: webAttribution.fbp,
|
|
257
|
+
fbc: webAttribution.fbc,
|
|
258
|
+
utm_source: webAttribution.utm_source,
|
|
259
|
+
utm_medium: webAttribution.utm_medium,
|
|
260
|
+
utm_campaign: webAttribution.utm_campaign,
|
|
261
|
+
utm_content: webAttribution.utm_content,
|
|
262
|
+
utm_term: webAttribution.utm_term,
|
|
263
|
+
web_timestamp: webAttribution.timestamp,
|
|
264
|
+
});
|
|
265
|
+
// Update attribution manager with web data
|
|
266
|
+
attributionManager.mergeWebAttribution(webAttribution);
|
|
267
|
+
debugLog('Successfully merged web attribution into mobile session');
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
errorLog('Error fetching web attribution:', error);
|
|
271
|
+
// Non-blocking - continue even if attribution fetch fails
|
|
272
|
+
}
|
|
273
|
+
}
|
|
208
274
|
/**
|
|
209
275
|
* Alias a user (connect anonymous user to known user)
|
|
210
276
|
*/
|
package/lib/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalyr/react-native",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Datalyr SDK for React Native & Expo - Server-side attribution tracking",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/jest": "^30.0.0",
|
|
60
60
|
"@types/react": "^18.2.0",
|
|
61
|
+
"@types/react-native": "^0.72.8",
|
|
61
62
|
"@types/uuid": "^10.0.0",
|
|
62
63
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
63
64
|
"@typescript-eslint/parser": "^8.0.0",
|
package/src/attribution.ts
CHANGED
|
@@ -441,6 +441,51 @@ export class AttributionManager {
|
|
|
441
441
|
return this.attributionData;
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
+
/**
|
|
445
|
+
* Merge web attribution data into mobile session
|
|
446
|
+
* Called when web-to-app attribution is resolved via email
|
|
447
|
+
*/
|
|
448
|
+
mergeWebAttribution(webAttribution: any): void {
|
|
449
|
+
debugLog('Merging web attribution data:', webAttribution);
|
|
450
|
+
|
|
451
|
+
// Only merge if we don't already have attribution data
|
|
452
|
+
// Web attribution takes precedence for first-touch
|
|
453
|
+
if (!this.attributionData.fbclid && webAttribution.fbclid) {
|
|
454
|
+
this.attributionData.fbclid = webAttribution.fbclid;
|
|
455
|
+
}
|
|
456
|
+
if (!this.attributionData.gclid && webAttribution.gclid) {
|
|
457
|
+
this.attributionData.gclid = webAttribution.gclid;
|
|
458
|
+
}
|
|
459
|
+
if (!this.attributionData.ttclid && webAttribution.ttclid) {
|
|
460
|
+
this.attributionData.ttclid = webAttribution.ttclid;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Merge UTM parameters
|
|
464
|
+
if (!this.attributionData.utm_source && webAttribution.utm_source) {
|
|
465
|
+
this.attributionData.utm_source = webAttribution.utm_source;
|
|
466
|
+
}
|
|
467
|
+
if (!this.attributionData.utm_medium && webAttribution.utm_medium) {
|
|
468
|
+
this.attributionData.utm_medium = webAttribution.utm_medium;
|
|
469
|
+
}
|
|
470
|
+
if (!this.attributionData.utm_campaign && webAttribution.utm_campaign) {
|
|
471
|
+
this.attributionData.utm_campaign = webAttribution.utm_campaign;
|
|
472
|
+
}
|
|
473
|
+
if (!this.attributionData.utm_content && webAttribution.utm_content) {
|
|
474
|
+
this.attributionData.utm_content = webAttribution.utm_content;
|
|
475
|
+
}
|
|
476
|
+
if (!this.attributionData.utm_term && webAttribution.utm_term) {
|
|
477
|
+
this.attributionData.utm_term = webAttribution.utm_term;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Store web visitor ID for cross-device tracking
|
|
481
|
+
this.attributionData.web_visitor_id = webAttribution.visitor_id;
|
|
482
|
+
|
|
483
|
+
// Save merged attribution data
|
|
484
|
+
this.saveAttributionData();
|
|
485
|
+
|
|
486
|
+
debugLog('Web attribution merged successfully');
|
|
487
|
+
}
|
|
488
|
+
|
|
444
489
|
/**
|
|
445
490
|
* Set custom attribution data
|
|
446
491
|
*/
|
package/src/datalyr-sdk.ts
CHANGED
|
@@ -248,7 +248,7 @@ export class DatalyrSDK {
|
|
|
248
248
|
|
|
249
249
|
// Update current user ID
|
|
250
250
|
this.state.currentUserId = userId;
|
|
251
|
-
|
|
251
|
+
|
|
252
252
|
// Merge user properties
|
|
253
253
|
this.state.userProperties = { ...this.state.userProperties, ...properties };
|
|
254
254
|
|
|
@@ -256,17 +256,93 @@ export class DatalyrSDK {
|
|
|
256
256
|
await this.persistUserData();
|
|
257
257
|
|
|
258
258
|
// Track $identify event for identity resolution
|
|
259
|
-
await this.track('$identify', {
|
|
260
|
-
userId,
|
|
259
|
+
await this.track('$identify', {
|
|
260
|
+
userId,
|
|
261
261
|
anonymous_id: this.state.anonymousId,
|
|
262
|
-
...properties
|
|
262
|
+
...properties
|
|
263
263
|
});
|
|
264
264
|
|
|
265
|
+
// Fetch and merge web attribution if email is provided
|
|
266
|
+
if (this.state.config.enableWebToAppAttribution !== false) {
|
|
267
|
+
const email = properties?.email || (typeof userId === 'string' && userId.includes('@') ? userId : null);
|
|
268
|
+
if (email) {
|
|
269
|
+
await this.fetchAndMergeWebAttribution(email);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
265
273
|
} catch (error) {
|
|
266
274
|
errorLog('Error identifying user:', error as Error);
|
|
267
275
|
}
|
|
268
276
|
}
|
|
269
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Fetch web attribution data for user and merge into mobile session
|
|
280
|
+
* Called automatically during identify() if email is provided
|
|
281
|
+
*/
|
|
282
|
+
private async fetchAndMergeWebAttribution(email: string): Promise<void> {
|
|
283
|
+
try {
|
|
284
|
+
debugLog('Fetching web attribution for email:', email);
|
|
285
|
+
|
|
286
|
+
// Call API endpoint to get web attribution
|
|
287
|
+
const response = await fetch('https://api.datalyr.com/attribution/lookup', {
|
|
288
|
+
method: 'POST',
|
|
289
|
+
headers: {
|
|
290
|
+
'Content-Type': 'application/json',
|
|
291
|
+
'X-Datalyr-API-Key': this.state.config.apiKey!,
|
|
292
|
+
},
|
|
293
|
+
body: JSON.stringify({ email }),
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
if (!response.ok) {
|
|
297
|
+
debugLog('Failed to fetch web attribution:', response.status);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const result = await response.json() as { found: boolean; attribution?: any };
|
|
302
|
+
|
|
303
|
+
if (!result.found || !result.attribution) {
|
|
304
|
+
debugLog('No web attribution found for user');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const webAttribution = result.attribution;
|
|
309
|
+
debugLog('Web attribution found:', {
|
|
310
|
+
visitor_id: webAttribution.visitor_id,
|
|
311
|
+
has_fbclid: !!webAttribution.fbclid,
|
|
312
|
+
has_gclid: !!webAttribution.gclid,
|
|
313
|
+
utm_source: webAttribution.utm_source,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Merge web attribution into current session
|
|
317
|
+
await this.track('$web_attribution_merged', {
|
|
318
|
+
web_visitor_id: webAttribution.visitor_id,
|
|
319
|
+
web_user_id: webAttribution.user_id,
|
|
320
|
+
fbclid: webAttribution.fbclid,
|
|
321
|
+
gclid: webAttribution.gclid,
|
|
322
|
+
ttclid: webAttribution.ttclid,
|
|
323
|
+
gbraid: webAttribution.gbraid,
|
|
324
|
+
wbraid: webAttribution.wbraid,
|
|
325
|
+
fbp: webAttribution.fbp,
|
|
326
|
+
fbc: webAttribution.fbc,
|
|
327
|
+
utm_source: webAttribution.utm_source,
|
|
328
|
+
utm_medium: webAttribution.utm_medium,
|
|
329
|
+
utm_campaign: webAttribution.utm_campaign,
|
|
330
|
+
utm_content: webAttribution.utm_content,
|
|
331
|
+
utm_term: webAttribution.utm_term,
|
|
332
|
+
web_timestamp: webAttribution.timestamp,
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Update attribution manager with web data
|
|
336
|
+
attributionManager.mergeWebAttribution(webAttribution);
|
|
337
|
+
|
|
338
|
+
debugLog('Successfully merged web attribution into mobile session');
|
|
339
|
+
|
|
340
|
+
} catch (error) {
|
|
341
|
+
errorLog('Error fetching web attribution:', error as Error);
|
|
342
|
+
// Non-blocking - continue even if attribution fetch fails
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
270
346
|
/**
|
|
271
347
|
* Alias a user (connect anonymous user to known user)
|
|
272
348
|
*/
|
package/src/types.ts
CHANGED
|
@@ -25,6 +25,7 @@ export interface DatalyrConfig {
|
|
|
25
25
|
respectDoNotTrack?: boolean;
|
|
26
26
|
enableAutoEvents?: boolean;
|
|
27
27
|
enableAttribution?: boolean;
|
|
28
|
+
enableWebToAppAttribution?: boolean;
|
|
28
29
|
autoEvents?: AutoEventConfig;
|
|
29
30
|
autoEventConfig?: AutoEventConfig;
|
|
30
31
|
retryConfig?: {
|
|
@@ -33,7 +34,6 @@ export interface DatalyrConfig {
|
|
|
33
34
|
};
|
|
34
35
|
skadTemplate?: 'ecommerce' | 'gaming' | 'subscription';
|
|
35
36
|
}
|
|
36
|
-
|
|
37
37
|
// Event Types
|
|
38
38
|
export interface EventData {
|
|
39
39
|
[key: string]: any;
|