@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.
@@ -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
  */
@@ -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
  */
@@ -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
  */
@@ -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
@@ -22,6 +22,7 @@ export interface DatalyrConfig {
22
22
  respectDoNotTrack?: boolean;
23
23
  enableAutoEvents?: boolean;
24
24
  enableAttribution?: boolean;
25
+ enableWebToAppAttribution?: boolean;
25
26
  autoEvents?: AutoEventConfig;
26
27
  autoEventConfig?: AutoEventConfig;
27
28
  retryConfig?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalyr/react-native",
3
- "version": "1.1.0",
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",
@@ -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
  */
@@ -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;