@datalyr/react-native 1.2.0 → 1.3.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +30 -1
  3. package/android/build.gradle +54 -0
  4. package/android/src/main/AndroidManifest.xml +14 -0
  5. package/android/src/main/java/com/datalyr/reactnative/DatalyrNativeModule.java +423 -0
  6. package/android/src/main/java/com/datalyr/reactnative/DatalyrPackage.java +30 -0
  7. package/android/src/main/java/com/datalyr/reactnative/DatalyrPlayInstallReferrerModule.java +229 -0
  8. package/datalyr-react-native.podspec +2 -2
  9. package/ios/DatalyrNative.m +4 -0
  10. package/ios/DatalyrNative.swift +58 -1
  11. package/ios/DatalyrSKAdNetwork.m +52 -1
  12. package/lib/ConversionValueEncoder.d.ts +13 -1
  13. package/lib/ConversionValueEncoder.js +57 -23
  14. package/lib/datalyr-sdk.d.ts +34 -2
  15. package/lib/datalyr-sdk.js +90 -8
  16. package/lib/index.d.ts +4 -1
  17. package/lib/index.js +2 -1
  18. package/lib/integrations/apple-search-ads-integration.d.ts +43 -0
  19. package/lib/integrations/apple-search-ads-integration.js +106 -0
  20. package/lib/integrations/index.d.ts +4 -1
  21. package/lib/integrations/index.js +3 -1
  22. package/lib/integrations/meta-integration.d.ts +1 -0
  23. package/lib/integrations/meta-integration.js +4 -3
  24. package/lib/integrations/play-install-referrer.d.ts +74 -0
  25. package/lib/integrations/play-install-referrer.js +156 -0
  26. package/lib/integrations/tiktok-integration.d.ts +1 -0
  27. package/lib/integrations/tiktok-integration.js +4 -3
  28. package/lib/journey.d.ts +106 -0
  29. package/lib/journey.js +258 -0
  30. package/lib/native/DatalyrNativeBridge.d.ts +67 -2
  31. package/lib/native/DatalyrNativeBridge.js +80 -7
  32. package/lib/native/SKAdNetworkBridge.d.ts +21 -0
  33. package/lib/native/SKAdNetworkBridge.js +54 -0
  34. package/package.json +9 -3
  35. package/src/ConversionValueEncoder.ts +67 -26
  36. package/src/datalyr-sdk-expo.ts +98 -9
  37. package/src/datalyr-sdk.ts +109 -14
  38. package/src/expo.ts +8 -0
  39. package/src/index.ts +6 -1
  40. package/src/integrations/apple-search-ads-integration.ts +119 -0
  41. package/src/integrations/index.ts +4 -1
  42. package/src/integrations/meta-integration.ts +4 -3
  43. package/src/integrations/play-install-referrer.ts +203 -0
  44. package/src/integrations/tiktok-integration.ts +4 -3
  45. package/src/journey.ts +338 -0
  46. package/src/native/DatalyrNativeBridge.ts +137 -9
  47. package/src/native/SKAdNetworkBridge.ts +86 -2
@@ -3,10 +3,11 @@ import { getOrCreateVisitorId, getOrCreateAnonymousId, getOrCreateSessionId, cre
3
3
  import { createHttpClient, HttpClient } from './http-client';
4
4
  import { createEventQueue, EventQueue } from './event-queue';
5
5
  import { attributionManager } from './attribution';
6
+ import { journeyManager } from './journey';
6
7
  import { AutoEventsManager } from './auto-events';
7
8
  import { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
8
9
  import { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
9
- import { metaIntegration, tiktokIntegration } from './integrations';
10
+ import { metaIntegration, tiktokIntegration, appleSearchAdsIntegration, playInstallReferrerIntegration } from './integrations';
10
11
  export class DatalyrSDK {
11
12
  constructor() {
12
13
  this.autoEventsManager = null;
@@ -82,6 +83,22 @@ export class DatalyrSDK {
82
83
  if (this.state.config.enableAttribution) {
83
84
  await attributionManager.initialize();
84
85
  }
86
+ // Initialize journey tracking (for first-touch, last-touch, touchpoints)
87
+ await journeyManager.initialize();
88
+ // Record initial attribution to journey if this is a new session with attribution
89
+ const initialAttribution = attributionManager.getAttributionData();
90
+ if (initialAttribution.utm_source || initialAttribution.fbclid || initialAttribution.gclid || initialAttribution.lyr) {
91
+ await journeyManager.recordAttribution(this.state.sessionId, {
92
+ source: initialAttribution.utm_source || initialAttribution.campaign_source,
93
+ medium: initialAttribution.utm_medium || initialAttribution.campaign_medium,
94
+ campaign: initialAttribution.utm_campaign || initialAttribution.campaign_name,
95
+ fbclid: initialAttribution.fbclid,
96
+ gclid: initialAttribution.gclid,
97
+ ttclid: initialAttribution.ttclid,
98
+ clickIdType: initialAttribution.fbclid ? 'fbclid' : initialAttribution.gclid ? 'gclid' : initialAttribution.ttclid ? 'ttclid' : undefined,
99
+ lyr: initialAttribution.lyr,
100
+ });
101
+ }
85
102
  // Initialize auto-events manager (asynchronously to avoid blocking)
86
103
  if (this.state.config.enableAutoEvents) {
87
104
  this.autoEventsManager = new AutoEventsManager(this.track.bind(this), this.state.config.autoEventConfig);
@@ -132,9 +149,15 @@ export class DatalyrSDK {
132
149
  if (((_c = config.tiktok) === null || _c === void 0 ? void 0 : _c.appId) && ((_d = config.tiktok) === null || _d === void 0 ? void 0 : _d.tiktokAppId)) {
133
150
  await tiktokIntegration.initialize(config.tiktok, config.debug);
134
151
  }
152
+ // Initialize Apple Search Ads attribution (iOS only, auto-fetches on init)
153
+ await appleSearchAdsIntegration.initialize(config.debug);
154
+ // Initialize Google Play Install Referrer (Android only)
155
+ await playInstallReferrerIntegration.initialize();
135
156
  debugLog('Platform integrations initialized', {
136
157
  meta: metaIntegration.isAvailable(),
137
158
  tiktok: tiktokIntegration.isAvailable(),
159
+ appleSearchAds: appleSearchAdsIntegration.isAvailable(),
160
+ playInstallReferrer: playInstallReferrerIntegration.isAvailable(),
138
161
  });
139
162
  // SDK initialized successfully - set state before tracking install event
140
163
  this.state.initialized = true;
@@ -395,6 +418,7 @@ export class DatalyrSDK {
395
418
  currentUserId: this.state.currentUserId,
396
419
  queueStats: this.eventQueue.getStats(),
397
420
  attribution: attributionManager.getAttributionSummary(),
421
+ journey: journeyManager.getJourneySummary(),
398
422
  };
399
423
  }
400
424
  /**
@@ -404,10 +428,28 @@ export class DatalyrSDK {
404
428
  return this.state.anonymousId;
405
429
  }
406
430
  /**
407
- * Get detailed attribution data
431
+ * Get detailed attribution data (includes journey tracking data)
408
432
  */
409
433
  getAttributionData() {
410
- return attributionManager.getAttributionData();
434
+ const attribution = attributionManager.getAttributionData();
435
+ const journeyData = journeyManager.getAttributionData();
436
+ // Merge attribution with journey data
437
+ return {
438
+ ...attribution,
439
+ ...journeyData,
440
+ };
441
+ }
442
+ /**
443
+ * Get journey tracking summary
444
+ */
445
+ getJourneySummary() {
446
+ return journeyManager.getJourneySummary();
447
+ }
448
+ /**
449
+ * Get full customer journey (all touchpoints)
450
+ */
451
+ getJourney() {
452
+ return journeyManager.getJourney();
411
453
  }
412
454
  /**
413
455
  * Set custom attribution data (for testing or manual attribution)
@@ -457,22 +499,25 @@ export class DatalyrSDK {
457
499
  // MARK: - SKAdNetwork Enhanced Methods
458
500
  /**
459
501
  * Track event with automatic SKAdNetwork conversion value encoding
502
+ * Uses SKAN 4.0 on iOS 16.1+ with coarse values and lock window support
460
503
  */
461
504
  async trackWithSKAdNetwork(event, properties) {
462
505
  // Existing tracking (keep exactly as-is)
463
506
  await this.track(event, properties);
464
- // NEW: Automatic SKAdNetwork encoding
507
+ // Automatic SKAdNetwork encoding with SKAN 4.0 support
465
508
  if (!DatalyrSDK.conversionEncoder) {
466
509
  if (DatalyrSDK.debugEnabled) {
467
510
  errorLog('SKAdNetwork encoder not initialized. Pass skadTemplate in initialize()');
468
511
  }
469
512
  return;
470
513
  }
471
- const conversionValue = DatalyrSDK.conversionEncoder.encode(event, properties);
472
- if (conversionValue > 0) {
473
- const success = await SKAdNetworkBridge.updateConversionValue(conversionValue);
514
+ // Use SKAN 4.0 encoding (includes coarse value and lock window)
515
+ const result = DatalyrSDK.conversionEncoder.encodeWithSKAN4(event, properties);
516
+ if (result.fineValue > 0 || result.priority > 0) {
517
+ // Use SKAN 4.0 method (automatically falls back to SKAN 3.0 on older iOS)
518
+ const success = await SKAdNetworkBridge.updatePostbackConversionValue(result);
474
519
  if (DatalyrSDK.debugEnabled) {
475
- debugLog(`Event: ${event}, Conversion Value: ${conversionValue}, Success: ${success}`, properties);
520
+ debugLog(`SKAN: event=${event}, fine=${result.fineValue}, coarse=${result.coarseValue}, lock=${result.lockWindow}, success=${success}`, properties);
476
521
  }
477
522
  }
478
523
  else if (DatalyrSDK.debugEnabled) {
@@ -672,8 +717,25 @@ export class DatalyrSDK {
672
717
  return {
673
718
  meta: metaIntegration.isAvailable(),
674
719
  tiktok: tiktokIntegration.isAvailable(),
720
+ appleSearchAds: appleSearchAdsIntegration.isAvailable(),
721
+ playInstallReferrer: playInstallReferrerIntegration.isAvailable(),
675
722
  };
676
723
  }
724
+ /**
725
+ * Get Apple Search Ads attribution data
726
+ * Returns attribution if user installed via Apple Search Ads, null otherwise
727
+ */
728
+ getAppleSearchAdsAttribution() {
729
+ return appleSearchAdsIntegration.getAttributionData();
730
+ }
731
+ /**
732
+ * Get Google Play Install Referrer attribution data (Android only)
733
+ * Returns referrer data if available, null otherwise
734
+ */
735
+ getPlayInstallReferrer() {
736
+ const data = playInstallReferrerIntegration.getReferrerData();
737
+ return data ? playInstallReferrerIntegration.getAttributionData() : null;
738
+ }
677
739
  /**
678
740
  * Update tracking authorization status on all platform SDKs
679
741
  * Call this AFTER the user responds to the ATT permission dialog
@@ -745,6 +807,21 @@ export class DatalyrSDK {
745
807
  const deviceInfo = await getDeviceInfo();
746
808
  const fingerprintData = await createFingerprintData();
747
809
  const attributionData = attributionManager.getAttributionData();
810
+ // Get Apple Search Ads attribution if available
811
+ const asaAttribution = appleSearchAdsIntegration.getAttributionData();
812
+ const asaData = (asaAttribution === null || asaAttribution === void 0 ? void 0 : asaAttribution.attribution) ? {
813
+ asa_campaign_id: asaAttribution.campaignId,
814
+ asa_campaign_name: asaAttribution.campaignName,
815
+ asa_ad_group_id: asaAttribution.adGroupId,
816
+ asa_ad_group_name: asaAttribution.adGroupName,
817
+ asa_keyword_id: asaAttribution.keywordId,
818
+ asa_keyword: asaAttribution.keyword,
819
+ asa_org_id: asaAttribution.orgId,
820
+ asa_org_name: asaAttribution.orgName,
821
+ asa_click_date: asaAttribution.clickDate,
822
+ asa_conversion_type: asaAttribution.conversionType,
823
+ asa_country_or_region: asaAttribution.countryOrRegion,
824
+ } : {};
748
825
  const payload = {
749
826
  workspaceId: this.state.config.workspaceId || 'mobile_sdk',
750
827
  visitorId: this.state.visitorId,
@@ -766,6 +843,8 @@ export class DatalyrSDK {
766
843
  timestamp: Date.now(),
767
844
  // Attribution data
768
845
  ...attributionData,
846
+ // Apple Search Ads attribution
847
+ ...asaData,
769
848
  },
770
849
  fingerprintData,
771
850
  source: 'mobile_app',
@@ -999,6 +1078,9 @@ export class Datalyr {
999
1078
  static getPlatformIntegrationStatus() {
1000
1079
  return datalyr.getPlatformIntegrationStatus();
1001
1080
  }
1081
+ static getAppleSearchAdsAttribution() {
1082
+ return datalyr.getAppleSearchAdsAttribution();
1083
+ }
1002
1084
  static async updateTrackingAuthorization(enabled) {
1003
1085
  await datalyr.updateTrackingAuthorization(enabled);
1004
1086
  }
package/lib/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export declare const datalyr: DatalyrSDK;
3
3
  export { Datalyr };
4
4
  export * from './types';
5
5
  export { attributionManager } from './attribution';
6
+ export { journeyManager } from './journey';
7
+ export type { TouchAttribution, TouchPoint } from './journey';
6
8
  export { createAutoEventsManager, AutoEventsManager } from './auto-events';
7
9
  export * from './utils';
8
10
  export * from './http-client';
@@ -10,5 +12,6 @@ export * from './event-queue';
10
12
  export { DatalyrSDK };
11
13
  export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
12
14
  export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
13
- export { metaIntegration, tiktokIntegration } from './integrations';
15
+ export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
16
+ export type { AppleSearchAdsAttribution } from './native/DatalyrNativeBridge';
14
17
  export default DatalyrSDK;
package/lib/index.js CHANGED
@@ -8,6 +8,7 @@ export { Datalyr };
8
8
  // Export types and utilities
9
9
  export * from './types';
10
10
  export { attributionManager } from './attribution';
11
+ export { journeyManager } from './journey';
11
12
  export { createAutoEventsManager, AutoEventsManager } from './auto-events';
12
13
  // Re-export utilities for advanced usage
13
14
  export * from './utils';
@@ -19,6 +20,6 @@ export { DatalyrSDK };
19
20
  export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
20
21
  export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
21
22
  // Export platform integrations
22
- export { metaIntegration, tiktokIntegration } from './integrations';
23
+ export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
23
24
  // Default export for compatibility
24
25
  export default DatalyrSDK;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Apple Search Ads Attribution Integration
3
+ * Uses AdServices framework (iOS 14.3+) to capture attribution from App Store search ads
4
+ */
5
+ import { AppleSearchAdsAttribution } from '../native/DatalyrNativeBridge';
6
+ /**
7
+ * Apple Search Ads Integration class
8
+ * Fetches attribution data for users who installed via Apple Search Ads
9
+ */
10
+ export declare class AppleSearchAdsIntegration {
11
+ private attributionData;
12
+ private fetched;
13
+ private available;
14
+ private debug;
15
+ /**
16
+ * Initialize and fetch Apple Search Ads attribution
17
+ */
18
+ initialize(debug?: boolean): Promise<void>;
19
+ /**
20
+ * Fetch attribution data from Apple's AdServices API
21
+ * Call this during app initialization
22
+ */
23
+ fetchAttribution(): Promise<AppleSearchAdsAttribution | null>;
24
+ /**
25
+ * Get cached attribution data
26
+ */
27
+ getAttributionData(): AppleSearchAdsAttribution | null;
28
+ /**
29
+ * Check if user came from Apple Search Ads
30
+ */
31
+ hasAttribution(): boolean;
32
+ /**
33
+ * Check if Apple Search Ads is available (iOS 14.3+)
34
+ */
35
+ isAvailable(): boolean;
36
+ /**
37
+ * Check if attribution has been fetched
38
+ */
39
+ hasFetched(): boolean;
40
+ private log;
41
+ private logError;
42
+ }
43
+ export declare const appleSearchAdsIntegration: AppleSearchAdsIntegration;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Apple Search Ads Attribution Integration
3
+ * Uses AdServices framework (iOS 14.3+) to capture attribution from App Store search ads
4
+ */
5
+ import { Platform } from 'react-native';
6
+ import { AppleSearchAdsNativeBridge, isNativeModuleAvailable } from '../native/DatalyrNativeBridge';
7
+ /**
8
+ * Apple Search Ads Integration class
9
+ * Fetches attribution data for users who installed via Apple Search Ads
10
+ */
11
+ export class AppleSearchAdsIntegration {
12
+ constructor() {
13
+ this.attributionData = null;
14
+ this.fetched = false;
15
+ this.available = false;
16
+ this.debug = false;
17
+ }
18
+ /**
19
+ * Initialize and fetch Apple Search Ads attribution
20
+ */
21
+ async initialize(debug = false) {
22
+ this.debug = debug;
23
+ // Only available on iOS via native module
24
+ if (Platform.OS !== 'ios') {
25
+ this.log('Apple Search Ads only available on iOS');
26
+ return;
27
+ }
28
+ this.available = isNativeModuleAvailable();
29
+ if (!this.available) {
30
+ this.log('Apple Search Ads native module not available');
31
+ return;
32
+ }
33
+ // Automatically fetch attribution on init
34
+ await this.fetchAttribution();
35
+ }
36
+ /**
37
+ * Fetch attribution data from Apple's AdServices API
38
+ * Call this during app initialization
39
+ */
40
+ async fetchAttribution() {
41
+ var _a;
42
+ if (!this.available) {
43
+ return null;
44
+ }
45
+ // Only fetch once
46
+ if (this.fetched) {
47
+ return this.attributionData;
48
+ }
49
+ try {
50
+ this.attributionData = await AppleSearchAdsNativeBridge.getAttribution();
51
+ this.fetched = true;
52
+ if ((_a = this.attributionData) === null || _a === void 0 ? void 0 : _a.attribution) {
53
+ this.log('Apple Search Ads attribution found:', {
54
+ campaignId: this.attributionData.campaignId,
55
+ campaignName: this.attributionData.campaignName,
56
+ adGroupId: this.attributionData.adGroupId,
57
+ keyword: this.attributionData.keyword,
58
+ });
59
+ }
60
+ else {
61
+ this.log('No Apple Search Ads attribution (user did not come from search ad)');
62
+ }
63
+ return this.attributionData;
64
+ }
65
+ catch (error) {
66
+ this.logError('Failed to fetch Apple Search Ads attribution:', error);
67
+ this.fetched = true;
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * Get cached attribution data
73
+ */
74
+ getAttributionData() {
75
+ return this.attributionData;
76
+ }
77
+ /**
78
+ * Check if user came from Apple Search Ads
79
+ */
80
+ hasAttribution() {
81
+ var _a;
82
+ return ((_a = this.attributionData) === null || _a === void 0 ? void 0 : _a.attribution) === true;
83
+ }
84
+ /**
85
+ * Check if Apple Search Ads is available (iOS 14.3+)
86
+ */
87
+ isAvailable() {
88
+ return this.available;
89
+ }
90
+ /**
91
+ * Check if attribution has been fetched
92
+ */
93
+ hasFetched() {
94
+ return this.fetched;
95
+ }
96
+ log(message, data) {
97
+ if (this.debug) {
98
+ console.log(`[Datalyr/AppleSearchAds] ${message}`, data || '');
99
+ }
100
+ }
101
+ logError(message, error) {
102
+ console.error(`[Datalyr/AppleSearchAds] ${message}`, error);
103
+ }
104
+ }
105
+ // Export singleton instance
106
+ export const appleSearchAdsIntegration = new AppleSearchAdsIntegration();
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Platform SDK Integrations
3
- * Meta (Facebook) and TikTok SDK wrappers for deferred deep linking and event forwarding
3
+ * Meta (Facebook), TikTok, Apple Search Ads, and Google Play Install Referrer SDK wrappers
4
4
  */
5
5
  export { MetaIntegration, metaIntegration } from './meta-integration';
6
6
  export { TikTokIntegration, tiktokIntegration } from './tiktok-integration';
7
+ export { AppleSearchAdsIntegration, appleSearchAdsIntegration } from './apple-search-ads-integration';
8
+ export { playInstallReferrerIntegration } from './play-install-referrer';
9
+ export type { PlayInstallReferrer } from './play-install-referrer';
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Platform SDK Integrations
3
- * Meta (Facebook) and TikTok SDK wrappers for deferred deep linking and event forwarding
3
+ * Meta (Facebook), TikTok, Apple Search Ads, and Google Play Install Referrer SDK wrappers
4
4
  */
5
5
  export { MetaIntegration, metaIntegration } from './meta-integration';
6
6
  export { TikTokIntegration, tiktokIntegration } from './tiktok-integration';
7
+ export { AppleSearchAdsIntegration, appleSearchAdsIntegration } from './apple-search-ads-integration';
8
+ export { playInstallReferrerIntegration } from './play-install-referrer';
@@ -15,6 +15,7 @@ export declare class MetaIntegration {
15
15
  private deferredDeepLinkData;
16
16
  /**
17
17
  * Initialize Meta SDK with configuration
18
+ * Supported on both iOS and Android via native modules
18
19
  */
19
20
  initialize(config: MetaConfig, debug?: boolean): Promise<void>;
20
21
  /**
@@ -18,14 +18,15 @@ export class MetaIntegration {
18
18
  }
19
19
  /**
20
20
  * Initialize Meta SDK with configuration
21
+ * Supported on both iOS and Android via native modules
21
22
  */
22
23
  async initialize(config, debug = false) {
23
24
  var _a;
24
25
  this.debug = debug;
25
26
  this.config = config;
26
- // Only available on iOS via native module
27
- if (Platform.OS !== 'ios') {
28
- this.log('Meta SDK only available on iOS');
27
+ // Only available on iOS and Android via native modules
28
+ if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
29
+ this.log('Meta SDK only available on iOS and Android');
29
30
  return;
30
31
  }
31
32
  this.available = isNativeModuleAvailable();
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Google Play Install Referrer Integration
3
+ *
4
+ * Provides Android install attribution via the Google Play Install Referrer API.
5
+ * This captures UTM parameters and click IDs passed through Google Play Store.
6
+ *
7
+ * How it works:
8
+ * 1. User clicks ad/link with UTM parameters
9
+ * 2. Google Play Store stores the referrer URL
10
+ * 3. On first app launch, SDK retrieves the referrer
11
+ * 4. Attribution data (utm_source, utm_medium, gclid, etc.) is extracted
12
+ *
13
+ * Requirements:
14
+ * - Android only (returns null on iOS)
15
+ * - Requires Google Play Install Referrer Library in build.gradle:
16
+ * implementation 'com.android.installreferrer:installreferrer:2.2'
17
+ *
18
+ * Attribution data captured:
19
+ * - referrer_url: Full referrer URL from Play Store
20
+ * - referrer_click_timestamp: When the referrer link was clicked
21
+ * - install_begin_timestamp: When the install began
22
+ * - gclid: Google Ads click ID (if present)
23
+ * - utm_source, utm_medium, utm_campaign, etc.
24
+ */
25
+ export interface PlayInstallReferrer {
26
+ referrerUrl: string;
27
+ referrerClickTimestamp: number;
28
+ installBeginTimestamp: number;
29
+ installCompleteTimestamp?: number;
30
+ gclid?: string;
31
+ utmSource?: string;
32
+ utmMedium?: string;
33
+ utmCampaign?: string;
34
+ utmTerm?: string;
35
+ utmContent?: string;
36
+ [key: string]: any;
37
+ }
38
+ /**
39
+ * Google Play Install Referrer Integration
40
+ *
41
+ * Retrieves install attribution data from Google Play Store.
42
+ * Only available on Android.
43
+ */
44
+ declare class PlayInstallReferrerIntegration {
45
+ private referrerData;
46
+ private initialized;
47
+ /**
48
+ * Check if Play Install Referrer is available
49
+ */
50
+ isAvailable(): boolean;
51
+ /**
52
+ * Initialize and fetch install referrer data
53
+ * Should be called once on first app launch
54
+ */
55
+ initialize(): Promise<void>;
56
+ /**
57
+ * Fetch install referrer from Play Store
58
+ */
59
+ fetchInstallReferrer(): Promise<PlayInstallReferrer | null>;
60
+ /**
61
+ * Parse referrer URL to extract UTM parameters and click IDs
62
+ */
63
+ private parseReferrerUrl;
64
+ /**
65
+ * Get cached install referrer data
66
+ */
67
+ getReferrerData(): PlayInstallReferrer | null;
68
+ /**
69
+ * Get attribution data in standard format
70
+ */
71
+ getAttributionData(): Record<string, any>;
72
+ }
73
+ export declare const playInstallReferrerIntegration: PlayInstallReferrerIntegration;
74
+ export {};
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Google Play Install Referrer Integration
3
+ *
4
+ * Provides Android install attribution via the Google Play Install Referrer API.
5
+ * This captures UTM parameters and click IDs passed through Google Play Store.
6
+ *
7
+ * How it works:
8
+ * 1. User clicks ad/link with UTM parameters
9
+ * 2. Google Play Store stores the referrer URL
10
+ * 3. On first app launch, SDK retrieves the referrer
11
+ * 4. Attribution data (utm_source, utm_medium, gclid, etc.) is extracted
12
+ *
13
+ * Requirements:
14
+ * - Android only (returns null on iOS)
15
+ * - Requires Google Play Install Referrer Library in build.gradle:
16
+ * implementation 'com.android.installreferrer:installreferrer:2.2'
17
+ *
18
+ * Attribution data captured:
19
+ * - referrer_url: Full referrer URL from Play Store
20
+ * - referrer_click_timestamp: When the referrer link was clicked
21
+ * - install_begin_timestamp: When the install began
22
+ * - gclid: Google Ads click ID (if present)
23
+ * - utm_source, utm_medium, utm_campaign, etc.
24
+ */
25
+ import { Platform, NativeModules } from 'react-native';
26
+ import { debugLog, errorLog } from '../utils';
27
+ const { DatalyrPlayInstallReferrer } = NativeModules;
28
+ /**
29
+ * Google Play Install Referrer Integration
30
+ *
31
+ * Retrieves install attribution data from Google Play Store.
32
+ * Only available on Android.
33
+ */
34
+ class PlayInstallReferrerIntegration {
35
+ constructor() {
36
+ this.referrerData = null;
37
+ this.initialized = false;
38
+ }
39
+ /**
40
+ * Check if Play Install Referrer is available
41
+ */
42
+ isAvailable() {
43
+ return Platform.OS === 'android' && !!DatalyrPlayInstallReferrer;
44
+ }
45
+ /**
46
+ * Initialize and fetch install referrer data
47
+ * Should be called once on first app launch
48
+ */
49
+ async initialize() {
50
+ if (this.initialized)
51
+ return;
52
+ if (!this.isAvailable()) {
53
+ debugLog('[PlayInstallReferrer] Not available (iOS or native module missing)');
54
+ return;
55
+ }
56
+ try {
57
+ this.referrerData = await this.fetchInstallReferrer();
58
+ this.initialized = true;
59
+ if (this.referrerData) {
60
+ debugLog('[PlayInstallReferrer] Install referrer fetched:', {
61
+ utmSource: this.referrerData.utmSource,
62
+ utmMedium: this.referrerData.utmMedium,
63
+ hasGclid: !!this.referrerData.gclid,
64
+ });
65
+ }
66
+ }
67
+ catch (error) {
68
+ errorLog('[PlayInstallReferrer] Failed to initialize:', error);
69
+ }
70
+ }
71
+ /**
72
+ * Fetch install referrer from Play Store
73
+ */
74
+ async fetchInstallReferrer() {
75
+ if (!this.isAvailable()) {
76
+ return null;
77
+ }
78
+ try {
79
+ const referrer = await DatalyrPlayInstallReferrer.getInstallReferrer();
80
+ if (!referrer) {
81
+ return null;
82
+ }
83
+ // Parse UTM parameters from referrer URL
84
+ const parsed = this.parseReferrerUrl(referrer.referrerUrl);
85
+ return {
86
+ ...referrer,
87
+ ...parsed,
88
+ };
89
+ }
90
+ catch (error) {
91
+ errorLog('[PlayInstallReferrer] Error fetching referrer:', error);
92
+ return null;
93
+ }
94
+ }
95
+ /**
96
+ * Parse referrer URL to extract UTM parameters and click IDs
97
+ */
98
+ parseReferrerUrl(referrerUrl) {
99
+ const params = {};
100
+ if (!referrerUrl)
101
+ return params;
102
+ try {
103
+ // Referrer URL is URL-encoded, decode it first
104
+ const decoded = decodeURIComponent(referrerUrl);
105
+ const searchParams = new URLSearchParams(decoded);
106
+ // Extract UTM parameters
107
+ params.utmSource = searchParams.get('utm_source') || undefined;
108
+ params.utmMedium = searchParams.get('utm_medium') || undefined;
109
+ params.utmCampaign = searchParams.get('utm_campaign') || undefined;
110
+ params.utmTerm = searchParams.get('utm_term') || undefined;
111
+ params.utmContent = searchParams.get('utm_content') || undefined;
112
+ // Extract click IDs
113
+ params.gclid = searchParams.get('gclid') || undefined;
114
+ // Store any additional parameters
115
+ searchParams.forEach((value, key) => {
116
+ if (!key.startsWith('utm_') && key !== 'gclid') {
117
+ params[key] = value;
118
+ }
119
+ });
120
+ debugLog('[PlayInstallReferrer] Parsed referrer URL:', params);
121
+ }
122
+ catch (error) {
123
+ errorLog('[PlayInstallReferrer] Error parsing referrer URL:', error);
124
+ }
125
+ return params;
126
+ }
127
+ /**
128
+ * Get cached install referrer data
129
+ */
130
+ getReferrerData() {
131
+ return this.referrerData;
132
+ }
133
+ /**
134
+ * Get attribution data in standard format
135
+ */
136
+ getAttributionData() {
137
+ if (!this.referrerData)
138
+ return {};
139
+ return {
140
+ // Install referrer specific
141
+ install_referrer_url: this.referrerData.referrerUrl,
142
+ referrer_click_timestamp: this.referrerData.referrerClickTimestamp,
143
+ install_begin_timestamp: this.referrerData.installBeginTimestamp,
144
+ // Standard attribution fields
145
+ gclid: this.referrerData.gclid,
146
+ utm_source: this.referrerData.utmSource,
147
+ utm_medium: this.referrerData.utmMedium,
148
+ utm_campaign: this.referrerData.utmCampaign,
149
+ utm_term: this.referrerData.utmTerm,
150
+ utm_content: this.referrerData.utmContent,
151
+ // Source indicators
152
+ attribution_source: 'play_install_referrer',
153
+ };
154
+ }
155
+ }
156
+ export const playInstallReferrerIntegration = new PlayInstallReferrerIntegration();
@@ -14,6 +14,7 @@ export declare class TikTokIntegration {
14
14
  private debug;
15
15
  /**
16
16
  * Initialize TikTok SDK with configuration
17
+ * Supported on both iOS and Android via native modules
17
18
  */
18
19
  initialize(config: TikTokConfig, debug?: boolean): Promise<void>;
19
20
  /**