@datalyr/react-native 1.1.1 → 1.2.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +31 -140
  2. package/LICENSE +21 -0
  3. package/README.md +434 -217
  4. package/datalyr-react-native.podspec +31 -0
  5. package/ios/DatalyrNative.m +74 -0
  6. package/ios/DatalyrNative.swift +332 -0
  7. package/ios/DatalyrSKAdNetwork.m +26 -0
  8. package/lib/datalyr-sdk.d.ts +73 -3
  9. package/lib/datalyr-sdk.js +353 -3
  10. package/lib/index.d.ts +2 -0
  11. package/lib/index.js +4 -2
  12. package/lib/integrations/apple-search-ads-integration.d.ts +43 -0
  13. package/lib/integrations/apple-search-ads-integration.js +106 -0
  14. package/lib/integrations/index.d.ts +7 -0
  15. package/lib/integrations/index.js +7 -0
  16. package/lib/integrations/meta-integration.d.ts +76 -0
  17. package/lib/integrations/meta-integration.js +218 -0
  18. package/lib/integrations/tiktok-integration.d.ts +82 -0
  19. package/lib/integrations/tiktok-integration.js +356 -0
  20. package/lib/native/DatalyrNativeBridge.d.ts +57 -0
  21. package/lib/native/DatalyrNativeBridge.js +187 -0
  22. package/lib/native/index.d.ts +5 -0
  23. package/lib/native/index.js +5 -0
  24. package/lib/types.d.ts +29 -0
  25. package/package.json +11 -5
  26. package/src/datalyr-sdk-expo.ts +997 -0
  27. package/src/datalyr-sdk.ts +455 -19
  28. package/src/expo.ts +42 -18
  29. package/src/index.ts +8 -2
  30. package/src/integrations/apple-search-ads-integration.ts +119 -0
  31. package/src/integrations/index.ts +8 -0
  32. package/src/integrations/meta-integration.ts +238 -0
  33. package/src/integrations/tiktok-integration.ts +360 -0
  34. package/src/native/DatalyrNativeBridge.ts +313 -0
  35. package/src/native/index.ts +11 -0
  36. package/src/types.ts +39 -0
  37. package/src/utils-expo.ts +25 -3
  38. package/src/utils-interface.ts +38 -0
  39. package/EXPO_INSTALL.md +0 -297
  40. package/INSTALL.md +0 -402
  41. package/examples/attribution-example.tsx +0 -377
  42. package/examples/auto-events-example.tsx +0 -403
  43. package/examples/example.tsx +0 -250
  44. package/examples/skadnetwork-example.tsx +0 -380
  45. package/examples/test-implementation.tsx +0 -163
@@ -6,6 +6,7 @@ import { attributionManager } from './attribution';
6
6
  import { AutoEventsManager } from './auto-events';
7
7
  import { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
8
8
  import { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
9
+ import { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
9
10
  export class DatalyrSDK {
10
11
  constructor() {
11
12
  this.autoEventsManager = null;
@@ -41,7 +42,7 @@ export class DatalyrSDK {
41
42
  * Initialize the SDK with configuration
42
43
  */
43
44
  async initialize(config) {
44
- var _a;
45
+ var _a, _b, _c, _d;
45
46
  try {
46
47
  debugLog('Initializing Datalyr SDK...', { workspaceId: config.workspaceId });
47
48
  // Validate configuration
@@ -116,6 +117,28 @@ export class DatalyrSDK {
116
117
  }
117
118
  }
118
119
  }
120
+ // Initialize Meta SDK if configured
121
+ if ((_b = config.meta) === null || _b === void 0 ? void 0 : _b.appId) {
122
+ await metaIntegration.initialize(config.meta, config.debug);
123
+ // Fetch deferred deep link and merge with attribution
124
+ if (config.enableAttribution !== false) {
125
+ const deferredLink = await metaIntegration.fetchDeferredDeepLink();
126
+ if (deferredLink) {
127
+ await this.handleDeferredDeepLink(deferredLink);
128
+ }
129
+ }
130
+ }
131
+ // Initialize TikTok SDK if configured
132
+ if (((_c = config.tiktok) === null || _c === void 0 ? void 0 : _c.appId) && ((_d = config.tiktok) === null || _d === void 0 ? void 0 : _d.tiktokAppId)) {
133
+ await tiktokIntegration.initialize(config.tiktok, config.debug);
134
+ }
135
+ // Initialize Apple Search Ads attribution (iOS only, auto-fetches on init)
136
+ await appleSearchAdsIntegration.initialize(config.debug);
137
+ debugLog('Platform integrations initialized', {
138
+ meta: metaIntegration.isAvailable(),
139
+ tiktok: tiktokIntegration.isAvailable(),
140
+ appleSearchAds: appleSearchAdsIntegration.isAvailable(),
141
+ });
119
142
  // SDK initialized successfully - set state before tracking install event
120
143
  this.state.initialized = true;
121
144
  // Check for app install (after SDK is marked as initialized)
@@ -207,6 +230,36 @@ export class DatalyrSDK {
207
230
  await this.fetchAndMergeWebAttribution(email);
208
231
  }
209
232
  }
233
+ // Forward user data to platform SDKs for Advanced Matching
234
+ const email = properties === null || properties === void 0 ? void 0 : properties.email;
235
+ const phone = properties === null || properties === void 0 ? void 0 : properties.phone;
236
+ const firstName = ((properties === null || properties === void 0 ? void 0 : properties.first_name) || (properties === null || properties === void 0 ? void 0 : properties.firstName));
237
+ const lastName = ((properties === null || properties === void 0 ? void 0 : properties.last_name) || (properties === null || properties === void 0 ? void 0 : properties.lastName));
238
+ const dateOfBirth = ((properties === null || properties === void 0 ? void 0 : properties.date_of_birth) || (properties === null || properties === void 0 ? void 0 : properties.dob) || (properties === null || properties === void 0 ? void 0 : properties.birthday));
239
+ const gender = properties === null || properties === void 0 ? void 0 : properties.gender;
240
+ const city = properties === null || properties === void 0 ? void 0 : properties.city;
241
+ const state = properties === null || properties === void 0 ? void 0 : properties.state;
242
+ const zip = ((properties === null || properties === void 0 ? void 0 : properties.zip) || (properties === null || properties === void 0 ? void 0 : properties.postal_code) || (properties === null || properties === void 0 ? void 0 : properties.zipcode));
243
+ const country = properties === null || properties === void 0 ? void 0 : properties.country;
244
+ // Meta Advanced Matching
245
+ if (metaIntegration.isAvailable()) {
246
+ metaIntegration.setUserData({
247
+ email,
248
+ firstName,
249
+ lastName,
250
+ phone,
251
+ dateOfBirth,
252
+ gender,
253
+ city,
254
+ state,
255
+ zip,
256
+ country,
257
+ });
258
+ }
259
+ // TikTok identification
260
+ if (tiktokIntegration.isAvailable()) {
261
+ tiktokIntegration.identify(email, phone, userId);
262
+ }
210
263
  }
211
264
  catch (error) {
212
265
  errorLog('Error identifying user:', error);
@@ -310,6 +363,10 @@ export class DatalyrSDK {
310
363
  await Storage.removeItem(STORAGE_KEYS.USER_PROPERTIES);
311
364
  // Generate new session
312
365
  this.state.sessionId = await getOrCreateSessionId();
366
+ // Clear user data from platform SDKs
367
+ if (metaIntegration.isAvailable()) {
368
+ metaIntegration.clearUserData();
369
+ }
313
370
  debugLog('User data reset completed');
314
371
  }
315
372
  catch (error) {
@@ -426,22 +483,263 @@ export class DatalyrSDK {
426
483
  }
427
484
  }
428
485
  /**
429
- * Track purchase with automatic revenue encoding
486
+ * Track purchase with automatic revenue encoding and platform forwarding
430
487
  */
431
488
  async trackPurchase(value, currency = 'USD', productId) {
432
489
  const properties = { revenue: value, currency };
433
490
  if (productId)
434
491
  properties.product_id = productId;
435
492
  await this.trackWithSKAdNetwork('purchase', properties);
493
+ // Forward to Meta if available
494
+ if (metaIntegration.isAvailable()) {
495
+ metaIntegration.logPurchase(value, currency, { fb_content_id: productId });
496
+ }
497
+ // Forward to TikTok if available
498
+ if (tiktokIntegration.isAvailable()) {
499
+ tiktokIntegration.logPurchase(value, currency, productId, 'product');
500
+ }
436
501
  }
437
502
  /**
438
- * Track subscription with automatic revenue encoding
503
+ * Track subscription with automatic revenue encoding and platform forwarding
439
504
  */
440
505
  async trackSubscription(value, currency = 'USD', plan) {
441
506
  const properties = { revenue: value, currency };
442
507
  if (plan)
443
508
  properties.plan = plan;
444
509
  await this.trackWithSKAdNetwork('subscribe', properties);
510
+ // Forward to Meta if available
511
+ if (metaIntegration.isAvailable()) {
512
+ metaIntegration.logEvent('Subscribe', value, { subscription_plan: plan });
513
+ }
514
+ // Forward to TikTok if available
515
+ if (tiktokIntegration.isAvailable()) {
516
+ tiktokIntegration.logSubscription(value, currency, plan);
517
+ }
518
+ }
519
+ // MARK: - Standard E-commerce Events
520
+ /**
521
+ * Track add to cart event
522
+ */
523
+ async trackAddToCart(value, currency = 'USD', productId, productName) {
524
+ const properties = { value, currency };
525
+ if (productId)
526
+ properties.product_id = productId;
527
+ if (productName)
528
+ properties.product_name = productName;
529
+ await this.trackWithSKAdNetwork('add_to_cart', properties);
530
+ // Forward to Meta
531
+ if (metaIntegration.isAvailable()) {
532
+ metaIntegration.logEvent('AddToCart', value, {
533
+ currency,
534
+ content_ids: productId ? [productId] : undefined,
535
+ content_name: productName,
536
+ });
537
+ }
538
+ // Forward to TikTok
539
+ if (tiktokIntegration.isAvailable()) {
540
+ tiktokIntegration.logAddToCart(value, currency, productId, 'product');
541
+ }
542
+ }
543
+ /**
544
+ * Track view content/product event
545
+ */
546
+ async trackViewContent(contentId, contentName, contentType = 'product', value, currency) {
547
+ const properties = { content_type: contentType };
548
+ if (contentId)
549
+ properties.content_id = contentId;
550
+ if (contentName)
551
+ properties.content_name = contentName;
552
+ if (value !== undefined)
553
+ properties.value = value;
554
+ if (currency)
555
+ properties.currency = currency;
556
+ await this.track('view_content', properties);
557
+ // Forward to Meta
558
+ if (metaIntegration.isAvailable()) {
559
+ metaIntegration.logEvent('ViewContent', value, {
560
+ content_ids: contentId ? [contentId] : undefined,
561
+ content_name: contentName,
562
+ content_type: contentType,
563
+ currency,
564
+ });
565
+ }
566
+ // Forward to TikTok
567
+ if (tiktokIntegration.isAvailable()) {
568
+ tiktokIntegration.logViewContent(contentId, contentName, contentType);
569
+ }
570
+ }
571
+ /**
572
+ * Track initiate checkout event
573
+ */
574
+ async trackInitiateCheckout(value, currency = 'USD', numItems, productIds) {
575
+ const properties = { value, currency };
576
+ if (numItems !== undefined)
577
+ properties.num_items = numItems;
578
+ if (productIds)
579
+ properties.product_ids = productIds;
580
+ await this.trackWithSKAdNetwork('initiate_checkout', properties);
581
+ // Forward to Meta
582
+ if (metaIntegration.isAvailable()) {
583
+ metaIntegration.logEvent('InitiateCheckout', value, {
584
+ currency,
585
+ num_items: numItems,
586
+ content_ids: productIds,
587
+ });
588
+ }
589
+ // Forward to TikTok
590
+ if (tiktokIntegration.isAvailable()) {
591
+ tiktokIntegration.logInitiateCheckout(value, currency, numItems);
592
+ }
593
+ }
594
+ /**
595
+ * Track complete registration event
596
+ */
597
+ async trackCompleteRegistration(method) {
598
+ const properties = {};
599
+ if (method)
600
+ properties.method = method;
601
+ await this.trackWithSKAdNetwork('complete_registration', properties);
602
+ // Forward to Meta
603
+ if (metaIntegration.isAvailable()) {
604
+ metaIntegration.logEvent('CompleteRegistration', undefined, { registration_method: method });
605
+ }
606
+ // Forward to TikTok
607
+ if (tiktokIntegration.isAvailable()) {
608
+ tiktokIntegration.logCompleteRegistration(method);
609
+ }
610
+ }
611
+ /**
612
+ * Track search event
613
+ */
614
+ async trackSearch(query, resultIds) {
615
+ const properties = { query };
616
+ if (resultIds)
617
+ properties.result_ids = resultIds;
618
+ await this.track('search', properties);
619
+ // Forward to Meta
620
+ if (metaIntegration.isAvailable()) {
621
+ metaIntegration.logEvent('Search', undefined, {
622
+ search_string: query,
623
+ content_ids: resultIds,
624
+ });
625
+ }
626
+ // Forward to TikTok
627
+ if (tiktokIntegration.isAvailable()) {
628
+ tiktokIntegration.logSearch(query);
629
+ }
630
+ }
631
+ /**
632
+ * Track lead/contact form submission
633
+ */
634
+ async trackLead(value, currency) {
635
+ const properties = {};
636
+ if (value !== undefined)
637
+ properties.value = value;
638
+ if (currency)
639
+ properties.currency = currency;
640
+ await this.trackWithSKAdNetwork('lead', properties);
641
+ // Forward to Meta
642
+ if (metaIntegration.isAvailable()) {
643
+ metaIntegration.logEvent('Lead', value, { currency });
644
+ }
645
+ // Forward to TikTok
646
+ if (tiktokIntegration.isAvailable()) {
647
+ tiktokIntegration.logLead(value, currency);
648
+ }
649
+ }
650
+ /**
651
+ * Track add payment info event
652
+ */
653
+ async trackAddPaymentInfo(success = true) {
654
+ await this.track('add_payment_info', { success });
655
+ // Forward to Meta
656
+ if (metaIntegration.isAvailable()) {
657
+ metaIntegration.logEvent('AddPaymentInfo', undefined, { success: success ? 1 : 0 });
658
+ }
659
+ // Forward to TikTok
660
+ if (tiktokIntegration.isAvailable()) {
661
+ tiktokIntegration.logAddPaymentInfo(success);
662
+ }
663
+ }
664
+ // MARK: - Platform Integration Methods
665
+ /**
666
+ * Get deferred attribution data from platform SDKs
667
+ */
668
+ getDeferredAttributionData() {
669
+ return metaIntegration.getDeferredDeepLinkData();
670
+ }
671
+ /**
672
+ * Get platform integration status
673
+ */
674
+ getPlatformIntegrationStatus() {
675
+ return {
676
+ meta: metaIntegration.isAvailable(),
677
+ tiktok: tiktokIntegration.isAvailable(),
678
+ appleSearchAds: appleSearchAdsIntegration.isAvailable(),
679
+ };
680
+ }
681
+ /**
682
+ * Get Apple Search Ads attribution data
683
+ * Returns attribution if user installed via Apple Search Ads, null otherwise
684
+ */
685
+ getAppleSearchAdsAttribution() {
686
+ return appleSearchAdsIntegration.getAttributionData();
687
+ }
688
+ /**
689
+ * Update tracking authorization status on all platform SDKs
690
+ * Call this AFTER the user responds to the ATT permission dialog
691
+ */
692
+ async updateTrackingAuthorization(enabled) {
693
+ if (!this.state.initialized) {
694
+ errorLog('SDK not initialized. Call initialize() first.');
695
+ return;
696
+ }
697
+ metaIntegration.updateTrackingAuthorization(enabled);
698
+ tiktokIntegration.updateTrackingAuthorization(enabled);
699
+ // Track ATT status event
700
+ await this.track('$att_status', {
701
+ authorized: enabled,
702
+ status: enabled ? 3 : 2,
703
+ status_name: enabled ? 'authorized' : 'denied',
704
+ });
705
+ debugLog(`ATT status updated: ${enabled ? 'authorized' : 'denied'}`);
706
+ }
707
+ /**
708
+ * Handle deferred deep link data from platform SDKs
709
+ */
710
+ async handleDeferredDeepLink(data) {
711
+ try {
712
+ debugLog('Processing deferred deep link:', data);
713
+ // Track deferred attribution event
714
+ await this.track('$deferred_deep_link', {
715
+ url: data.url,
716
+ source: data.source,
717
+ fbclid: data.fbclid,
718
+ ttclid: data.ttclid,
719
+ utm_source: data.utmSource,
720
+ utm_medium: data.utmMedium,
721
+ utm_campaign: data.utmCampaign,
722
+ utm_content: data.utmContent,
723
+ utm_term: data.utmTerm,
724
+ campaign_id: data.campaignId,
725
+ adset_id: data.adsetId,
726
+ ad_id: data.adId,
727
+ });
728
+ // Merge into attribution manager
729
+ attributionManager.mergeWebAttribution({
730
+ fbclid: data.fbclid,
731
+ ttclid: data.ttclid,
732
+ utm_source: data.utmSource,
733
+ utm_medium: data.utmMedium,
734
+ utm_campaign: data.utmCampaign,
735
+ utm_content: data.utmContent,
736
+ utm_term: data.utmTerm,
737
+ });
738
+ debugLog('Deferred deep link processed successfully');
739
+ }
740
+ catch (error) {
741
+ errorLog('Error processing deferred deep link:', error);
742
+ }
445
743
  }
446
744
  /**
447
745
  * Get conversion value for testing (doesn't send to Apple)
@@ -458,6 +756,21 @@ export class DatalyrSDK {
458
756
  const deviceInfo = await getDeviceInfo();
459
757
  const fingerprintData = await createFingerprintData();
460
758
  const attributionData = attributionManager.getAttributionData();
759
+ // Get Apple Search Ads attribution if available
760
+ const asaAttribution = appleSearchAdsIntegration.getAttributionData();
761
+ const asaData = (asaAttribution === null || asaAttribution === void 0 ? void 0 : asaAttribution.attribution) ? {
762
+ asa_campaign_id: asaAttribution.campaignId,
763
+ asa_campaign_name: asaAttribution.campaignName,
764
+ asa_ad_group_id: asaAttribution.adGroupId,
765
+ asa_ad_group_name: asaAttribution.adGroupName,
766
+ asa_keyword_id: asaAttribution.keywordId,
767
+ asa_keyword: asaAttribution.keyword,
768
+ asa_org_id: asaAttribution.orgId,
769
+ asa_org_name: asaAttribution.orgName,
770
+ asa_click_date: asaAttribution.clickDate,
771
+ asa_conversion_type: asaAttribution.conversionType,
772
+ asa_country_or_region: asaAttribution.countryOrRegion,
773
+ } : {};
461
774
  const payload = {
462
775
  workspaceId: this.state.config.workspaceId || 'mobile_sdk',
463
776
  visitorId: this.state.visitorId,
@@ -479,6 +792,8 @@ export class DatalyrSDK {
479
792
  timestamp: Date.now(),
480
793
  // Attribution data
481
794
  ...attributionData,
795
+ // Apple Search Ads attribution
796
+ ...asaData,
482
797
  },
483
798
  fingerprintData,
484
799
  source: 'mobile_app',
@@ -683,6 +998,41 @@ export class Datalyr {
683
998
  static updateAutoEventsConfig(config) {
684
999
  datalyr.updateAutoEventsConfig(config);
685
1000
  }
1001
+ // Standard e-commerce events (all forward to Meta and TikTok)
1002
+ static async trackAddToCart(value, currency = 'USD', productId, productName) {
1003
+ await datalyr.trackAddToCart(value, currency, productId, productName);
1004
+ }
1005
+ static async trackViewContent(contentId, contentName, contentType = 'product', value, currency) {
1006
+ await datalyr.trackViewContent(contentId, contentName, contentType, value, currency);
1007
+ }
1008
+ static async trackInitiateCheckout(value, currency = 'USD', numItems, productIds) {
1009
+ await datalyr.trackInitiateCheckout(value, currency, numItems, productIds);
1010
+ }
1011
+ static async trackCompleteRegistration(method) {
1012
+ await datalyr.trackCompleteRegistration(method);
1013
+ }
1014
+ static async trackSearch(query, resultIds) {
1015
+ await datalyr.trackSearch(query, resultIds);
1016
+ }
1017
+ static async trackLead(value, currency) {
1018
+ await datalyr.trackLead(value, currency);
1019
+ }
1020
+ static async trackAddPaymentInfo(success = true) {
1021
+ await datalyr.trackAddPaymentInfo(success);
1022
+ }
1023
+ // Platform integration methods
1024
+ static getDeferredAttributionData() {
1025
+ return datalyr.getDeferredAttributionData();
1026
+ }
1027
+ static getPlatformIntegrationStatus() {
1028
+ return datalyr.getPlatformIntegrationStatus();
1029
+ }
1030
+ static getAppleSearchAdsAttribution() {
1031
+ return datalyr.getAppleSearchAdsAttribution();
1032
+ }
1033
+ static async updateTrackingAuthorization(enabled) {
1034
+ await datalyr.updateTrackingAuthorization(enabled);
1035
+ }
686
1036
  }
687
1037
  // Export default instance for backward compatibility
688
1038
  export default datalyr;
package/lib/index.d.ts CHANGED
@@ -10,4 +10,6 @@ export * from './event-queue';
10
10
  export { DatalyrSDK };
11
11
  export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
12
12
  export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
13
+ export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
14
+ export type { AppleSearchAdsAttribution } from './native/DatalyrNativeBridge';
13
15
  export default DatalyrSDK;
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Main entry point for React Native CLI
2
- // Import this with: import { datalyr } from '@datalyr/react-native-sdk';
2
+ // Import with: import { Datalyr } from '@datalyr/react-native';
3
3
  import { DatalyrSDK, Datalyr } from './datalyr-sdk';
4
4
  // Create singleton instance for easy usage
5
5
  export const datalyr = new DatalyrSDK();
@@ -18,5 +18,7 @@ export { DatalyrSDK };
18
18
  // Export SKAdNetwork components
19
19
  export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
20
20
  export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
21
- // Default export for compatibility
21
+ // Export platform integrations
22
+ export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
23
+ // Default export for compatibility
22
24
  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();
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Platform SDK Integrations
3
+ * Meta (Facebook), TikTok, and Apple Search Ads SDK wrappers
4
+ */
5
+ export { MetaIntegration, metaIntegration } from './meta-integration';
6
+ export { TikTokIntegration, tiktokIntegration } from './tiktok-integration';
7
+ export { AppleSearchAdsIntegration, appleSearchAdsIntegration } from './apple-search-ads-integration';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Platform SDK Integrations
3
+ * Meta (Facebook), TikTok, and Apple Search Ads SDK wrappers
4
+ */
5
+ export { MetaIntegration, metaIntegration } from './meta-integration';
6
+ export { TikTokIntegration, tiktokIntegration } from './tiktok-integration';
7
+ export { AppleSearchAdsIntegration, appleSearchAdsIntegration } from './apple-search-ads-integration';