@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.
- package/CHANGELOG.md +31 -140
- package/LICENSE +21 -0
- package/README.md +434 -217
- package/datalyr-react-native.podspec +31 -0
- package/ios/DatalyrNative.m +74 -0
- package/ios/DatalyrNative.swift +332 -0
- package/ios/DatalyrSKAdNetwork.m +26 -0
- package/lib/datalyr-sdk.d.ts +73 -3
- package/lib/datalyr-sdk.js +353 -3
- package/lib/index.d.ts +2 -0
- package/lib/index.js +4 -2
- package/lib/integrations/apple-search-ads-integration.d.ts +43 -0
- package/lib/integrations/apple-search-ads-integration.js +106 -0
- package/lib/integrations/index.d.ts +7 -0
- package/lib/integrations/index.js +7 -0
- package/lib/integrations/meta-integration.d.ts +76 -0
- package/lib/integrations/meta-integration.js +218 -0
- package/lib/integrations/tiktok-integration.d.ts +82 -0
- package/lib/integrations/tiktok-integration.js +356 -0
- package/lib/native/DatalyrNativeBridge.d.ts +57 -0
- package/lib/native/DatalyrNativeBridge.js +187 -0
- package/lib/native/index.d.ts +5 -0
- package/lib/native/index.js +5 -0
- package/lib/types.d.ts +29 -0
- package/package.json +11 -5
- package/src/datalyr-sdk-expo.ts +997 -0
- package/src/datalyr-sdk.ts +455 -19
- package/src/expo.ts +42 -18
- package/src/index.ts +8 -2
- package/src/integrations/apple-search-ads-integration.ts +119 -0
- package/src/integrations/index.ts +8 -0
- package/src/integrations/meta-integration.ts +238 -0
- package/src/integrations/tiktok-integration.ts +360 -0
- package/src/native/DatalyrNativeBridge.ts +313 -0
- package/src/native/index.ts +11 -0
- package/src/types.ts +39 -0
- package/src/utils-expo.ts +25 -3
- package/src/utils-interface.ts +38 -0
- package/EXPO_INSTALL.md +0 -297
- package/INSTALL.md +0 -402
- package/examples/attribution-example.tsx +0 -377
- package/examples/auto-events-example.tsx +0 -403
- package/examples/example.tsx +0 -250
- package/examples/skadnetwork-example.tsx +0 -380
- package/examples/test-implementation.tsx +0 -163
package/src/datalyr-sdk.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { Platform, AppState } from 'react-native';
|
|
2
|
-
import {
|
|
3
|
-
DatalyrConfig,
|
|
4
|
-
EventData,
|
|
5
|
-
UserProperties,
|
|
6
|
-
EventPayload,
|
|
2
|
+
import {
|
|
3
|
+
DatalyrConfig,
|
|
4
|
+
EventData,
|
|
5
|
+
UserProperties,
|
|
6
|
+
EventPayload,
|
|
7
7
|
SDKState,
|
|
8
8
|
AppState as AppStateType,
|
|
9
9
|
AutoEventConfig,
|
|
10
|
+
DeferredDeepLinkResult,
|
|
10
11
|
} from './types';
|
|
11
|
-
import {
|
|
12
|
-
getOrCreateVisitorId,
|
|
12
|
+
import {
|
|
13
|
+
getOrCreateVisitorId,
|
|
13
14
|
getOrCreateAnonymousId,
|
|
14
|
-
getOrCreateSessionId,
|
|
15
|
-
createFingerprintData,
|
|
16
|
-
generateUUID,
|
|
15
|
+
getOrCreateSessionId,
|
|
16
|
+
createFingerprintData,
|
|
17
|
+
generateUUID,
|
|
17
18
|
getDeviceInfo,
|
|
18
19
|
getNetworkType,
|
|
19
20
|
validateEventName,
|
|
@@ -29,6 +30,8 @@ import { attributionManager, AttributionData } from './attribution';
|
|
|
29
30
|
import { createAutoEventsManager, AutoEventsManager, SessionData } from './auto-events';
|
|
30
31
|
import { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
|
|
31
32
|
import { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
|
|
33
|
+
import { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
|
|
34
|
+
import { AppleSearchAdsAttribution } from './native/DatalyrNativeBridge';
|
|
32
35
|
|
|
33
36
|
export class DatalyrSDK {
|
|
34
37
|
private state: SDKState;
|
|
@@ -153,7 +156,7 @@ export class DatalyrSDK {
|
|
|
153
156
|
if (template) {
|
|
154
157
|
DatalyrSDK.conversionEncoder = new ConversionValueEncoder(template);
|
|
155
158
|
DatalyrSDK.debugEnabled = config.debug || false;
|
|
156
|
-
|
|
159
|
+
|
|
157
160
|
if (DatalyrSDK.debugEnabled) {
|
|
158
161
|
debugLog(`SKAdNetwork encoder initialized with template: ${config.skadTemplate}`);
|
|
159
162
|
debugLog(`SKAdNetwork bridge available: ${SKAdNetworkBridge.isAvailable()}`);
|
|
@@ -161,6 +164,33 @@ export class DatalyrSDK {
|
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
|
|
167
|
+
// Initialize Meta SDK if configured
|
|
168
|
+
if (config.meta?.appId) {
|
|
169
|
+
await metaIntegration.initialize(config.meta, config.debug);
|
|
170
|
+
|
|
171
|
+
// Fetch deferred deep link and merge with attribution
|
|
172
|
+
if (config.enableAttribution !== false) {
|
|
173
|
+
const deferredLink = await metaIntegration.fetchDeferredDeepLink();
|
|
174
|
+
if (deferredLink) {
|
|
175
|
+
await this.handleDeferredDeepLink(deferredLink);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Initialize TikTok SDK if configured
|
|
181
|
+
if (config.tiktok?.appId && config.tiktok?.tiktokAppId) {
|
|
182
|
+
await tiktokIntegration.initialize(config.tiktok, config.debug);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Initialize Apple Search Ads attribution (iOS only, auto-fetches on init)
|
|
186
|
+
await appleSearchAdsIntegration.initialize(config.debug);
|
|
187
|
+
|
|
188
|
+
debugLog('Platform integrations initialized', {
|
|
189
|
+
meta: metaIntegration.isAvailable(),
|
|
190
|
+
tiktok: tiktokIntegration.isAvailable(),
|
|
191
|
+
appleSearchAds: appleSearchAdsIntegration.isAvailable(),
|
|
192
|
+
});
|
|
193
|
+
|
|
164
194
|
// SDK initialized successfully - set state before tracking install event
|
|
165
195
|
this.state.initialized = true;
|
|
166
196
|
|
|
@@ -270,6 +300,39 @@ export class DatalyrSDK {
|
|
|
270
300
|
}
|
|
271
301
|
}
|
|
272
302
|
|
|
303
|
+
// Forward user data to platform SDKs for Advanced Matching
|
|
304
|
+
const email = properties?.email as string | undefined;
|
|
305
|
+
const phone = properties?.phone as string | undefined;
|
|
306
|
+
const firstName = (properties?.first_name || properties?.firstName) as string | undefined;
|
|
307
|
+
const lastName = (properties?.last_name || properties?.lastName) as string | undefined;
|
|
308
|
+
const dateOfBirth = (properties?.date_of_birth || properties?.dob || properties?.birthday) as string | undefined;
|
|
309
|
+
const gender = properties?.gender as string | undefined;
|
|
310
|
+
const city = properties?.city as string | undefined;
|
|
311
|
+
const state = properties?.state as string | undefined;
|
|
312
|
+
const zip = (properties?.zip || properties?.postal_code || properties?.zipcode) as string | undefined;
|
|
313
|
+
const country = properties?.country as string | undefined;
|
|
314
|
+
|
|
315
|
+
// Meta Advanced Matching
|
|
316
|
+
if (metaIntegration.isAvailable()) {
|
|
317
|
+
metaIntegration.setUserData({
|
|
318
|
+
email,
|
|
319
|
+
firstName,
|
|
320
|
+
lastName,
|
|
321
|
+
phone,
|
|
322
|
+
dateOfBirth,
|
|
323
|
+
gender,
|
|
324
|
+
city,
|
|
325
|
+
state,
|
|
326
|
+
zip,
|
|
327
|
+
country,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// TikTok identification
|
|
332
|
+
if (tiktokIntegration.isAvailable()) {
|
|
333
|
+
tiktokIntegration.identify(email, phone, userId);
|
|
334
|
+
}
|
|
335
|
+
|
|
273
336
|
} catch (error) {
|
|
274
337
|
errorLog('Error identifying user:', error as Error);
|
|
275
338
|
}
|
|
@@ -391,6 +454,11 @@ export class DatalyrSDK {
|
|
|
391
454
|
// Generate new session
|
|
392
455
|
this.state.sessionId = await getOrCreateSessionId();
|
|
393
456
|
|
|
457
|
+
// Clear user data from platform SDKs
|
|
458
|
+
if (metaIntegration.isAvailable()) {
|
|
459
|
+
metaIntegration.clearUserData();
|
|
460
|
+
}
|
|
461
|
+
|
|
394
462
|
debugLog('User data reset completed');
|
|
395
463
|
|
|
396
464
|
} catch (error) {
|
|
@@ -533,31 +601,319 @@ export class DatalyrSDK {
|
|
|
533
601
|
}
|
|
534
602
|
|
|
535
603
|
/**
|
|
536
|
-
* Track purchase with automatic revenue encoding
|
|
604
|
+
* Track purchase with automatic revenue encoding and platform forwarding
|
|
537
605
|
*/
|
|
538
606
|
async trackPurchase(
|
|
539
|
-
value: number,
|
|
540
|
-
currency = 'USD',
|
|
607
|
+
value: number,
|
|
608
|
+
currency = 'USD',
|
|
541
609
|
productId?: string
|
|
542
610
|
): Promise<void> {
|
|
543
611
|
const properties: Record<string, any> = { revenue: value, currency };
|
|
544
612
|
if (productId) properties.product_id = productId;
|
|
545
|
-
|
|
613
|
+
|
|
546
614
|
await this.trackWithSKAdNetwork('purchase', properties);
|
|
615
|
+
|
|
616
|
+
// Forward to Meta if available
|
|
617
|
+
if (metaIntegration.isAvailable()) {
|
|
618
|
+
metaIntegration.logPurchase(value, currency, { fb_content_id: productId });
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Forward to TikTok if available
|
|
622
|
+
if (tiktokIntegration.isAvailable()) {
|
|
623
|
+
tiktokIntegration.logPurchase(value, currency, productId, 'product');
|
|
624
|
+
}
|
|
547
625
|
}
|
|
548
626
|
|
|
549
627
|
/**
|
|
550
|
-
* Track subscription with automatic revenue encoding
|
|
628
|
+
* Track subscription with automatic revenue encoding and platform forwarding
|
|
551
629
|
*/
|
|
552
630
|
async trackSubscription(
|
|
553
|
-
value: number,
|
|
554
|
-
currency = 'USD',
|
|
631
|
+
value: number,
|
|
632
|
+
currency = 'USD',
|
|
555
633
|
plan?: string
|
|
556
634
|
): Promise<void> {
|
|
557
635
|
const properties: Record<string, any> = { revenue: value, currency };
|
|
558
636
|
if (plan) properties.plan = plan;
|
|
559
|
-
|
|
637
|
+
|
|
560
638
|
await this.trackWithSKAdNetwork('subscribe', properties);
|
|
639
|
+
|
|
640
|
+
// Forward to Meta if available
|
|
641
|
+
if (metaIntegration.isAvailable()) {
|
|
642
|
+
metaIntegration.logEvent('Subscribe', value, { subscription_plan: plan });
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Forward to TikTok if available
|
|
646
|
+
if (tiktokIntegration.isAvailable()) {
|
|
647
|
+
tiktokIntegration.logSubscription(value, currency, plan);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// MARK: - Standard E-commerce Events
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Track add to cart event
|
|
655
|
+
*/
|
|
656
|
+
async trackAddToCart(
|
|
657
|
+
value: number,
|
|
658
|
+
currency = 'USD',
|
|
659
|
+
productId?: string,
|
|
660
|
+
productName?: string
|
|
661
|
+
): Promise<void> {
|
|
662
|
+
const properties: Record<string, any> = { value, currency };
|
|
663
|
+
if (productId) properties.product_id = productId;
|
|
664
|
+
if (productName) properties.product_name = productName;
|
|
665
|
+
|
|
666
|
+
await this.trackWithSKAdNetwork('add_to_cart', properties);
|
|
667
|
+
|
|
668
|
+
// Forward to Meta
|
|
669
|
+
if (metaIntegration.isAvailable()) {
|
|
670
|
+
metaIntegration.logEvent('AddToCart', value, {
|
|
671
|
+
currency,
|
|
672
|
+
content_ids: productId ? [productId] : undefined,
|
|
673
|
+
content_name: productName,
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Forward to TikTok
|
|
678
|
+
if (tiktokIntegration.isAvailable()) {
|
|
679
|
+
tiktokIntegration.logAddToCart(value, currency, productId, 'product');
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Track view content/product event
|
|
685
|
+
*/
|
|
686
|
+
async trackViewContent(
|
|
687
|
+
contentId?: string,
|
|
688
|
+
contentName?: string,
|
|
689
|
+
contentType = 'product',
|
|
690
|
+
value?: number,
|
|
691
|
+
currency?: string
|
|
692
|
+
): Promise<void> {
|
|
693
|
+
const properties: Record<string, any> = { content_type: contentType };
|
|
694
|
+
if (contentId) properties.content_id = contentId;
|
|
695
|
+
if (contentName) properties.content_name = contentName;
|
|
696
|
+
if (value !== undefined) properties.value = value;
|
|
697
|
+
if (currency) properties.currency = currency;
|
|
698
|
+
|
|
699
|
+
await this.track('view_content', properties);
|
|
700
|
+
|
|
701
|
+
// Forward to Meta
|
|
702
|
+
if (metaIntegration.isAvailable()) {
|
|
703
|
+
metaIntegration.logEvent('ViewContent', value, {
|
|
704
|
+
content_ids: contentId ? [contentId] : undefined,
|
|
705
|
+
content_name: contentName,
|
|
706
|
+
content_type: contentType,
|
|
707
|
+
currency,
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Forward to TikTok
|
|
712
|
+
if (tiktokIntegration.isAvailable()) {
|
|
713
|
+
tiktokIntegration.logViewContent(contentId, contentName, contentType);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Track initiate checkout event
|
|
719
|
+
*/
|
|
720
|
+
async trackInitiateCheckout(
|
|
721
|
+
value: number,
|
|
722
|
+
currency = 'USD',
|
|
723
|
+
numItems?: number,
|
|
724
|
+
productIds?: string[]
|
|
725
|
+
): Promise<void> {
|
|
726
|
+
const properties: Record<string, any> = { value, currency };
|
|
727
|
+
if (numItems !== undefined) properties.num_items = numItems;
|
|
728
|
+
if (productIds) properties.product_ids = productIds;
|
|
729
|
+
|
|
730
|
+
await this.trackWithSKAdNetwork('initiate_checkout', properties);
|
|
731
|
+
|
|
732
|
+
// Forward to Meta
|
|
733
|
+
if (metaIntegration.isAvailable()) {
|
|
734
|
+
metaIntegration.logEvent('InitiateCheckout', value, {
|
|
735
|
+
currency,
|
|
736
|
+
num_items: numItems,
|
|
737
|
+
content_ids: productIds,
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Forward to TikTok
|
|
742
|
+
if (tiktokIntegration.isAvailable()) {
|
|
743
|
+
tiktokIntegration.logInitiateCheckout(value, currency, numItems);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Track complete registration event
|
|
749
|
+
*/
|
|
750
|
+
async trackCompleteRegistration(method?: string): Promise<void> {
|
|
751
|
+
const properties: Record<string, any> = {};
|
|
752
|
+
if (method) properties.method = method;
|
|
753
|
+
|
|
754
|
+
await this.trackWithSKAdNetwork('complete_registration', properties);
|
|
755
|
+
|
|
756
|
+
// Forward to Meta
|
|
757
|
+
if (metaIntegration.isAvailable()) {
|
|
758
|
+
metaIntegration.logEvent('CompleteRegistration', undefined, { registration_method: method });
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Forward to TikTok
|
|
762
|
+
if (tiktokIntegration.isAvailable()) {
|
|
763
|
+
tiktokIntegration.logCompleteRegistration(method);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Track search event
|
|
769
|
+
*/
|
|
770
|
+
async trackSearch(query: string, resultIds?: string[]): Promise<void> {
|
|
771
|
+
const properties: Record<string, any> = { query };
|
|
772
|
+
if (resultIds) properties.result_ids = resultIds;
|
|
773
|
+
|
|
774
|
+
await this.track('search', properties);
|
|
775
|
+
|
|
776
|
+
// Forward to Meta
|
|
777
|
+
if (metaIntegration.isAvailable()) {
|
|
778
|
+
metaIntegration.logEvent('Search', undefined, {
|
|
779
|
+
search_string: query,
|
|
780
|
+
content_ids: resultIds,
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Forward to TikTok
|
|
785
|
+
if (tiktokIntegration.isAvailable()) {
|
|
786
|
+
tiktokIntegration.logSearch(query);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Track lead/contact form submission
|
|
792
|
+
*/
|
|
793
|
+
async trackLead(value?: number, currency?: string): Promise<void> {
|
|
794
|
+
const properties: Record<string, any> = {};
|
|
795
|
+
if (value !== undefined) properties.value = value;
|
|
796
|
+
if (currency) properties.currency = currency;
|
|
797
|
+
|
|
798
|
+
await this.trackWithSKAdNetwork('lead', properties);
|
|
799
|
+
|
|
800
|
+
// Forward to Meta
|
|
801
|
+
if (metaIntegration.isAvailable()) {
|
|
802
|
+
metaIntegration.logEvent('Lead', value, { currency });
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// Forward to TikTok
|
|
806
|
+
if (tiktokIntegration.isAvailable()) {
|
|
807
|
+
tiktokIntegration.logLead(value, currency);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Track add payment info event
|
|
813
|
+
*/
|
|
814
|
+
async trackAddPaymentInfo(success = true): Promise<void> {
|
|
815
|
+
await this.track('add_payment_info', { success });
|
|
816
|
+
|
|
817
|
+
// Forward to Meta
|
|
818
|
+
if (metaIntegration.isAvailable()) {
|
|
819
|
+
metaIntegration.logEvent('AddPaymentInfo', undefined, { success: success ? 1 : 0 });
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Forward to TikTok
|
|
823
|
+
if (tiktokIntegration.isAvailable()) {
|
|
824
|
+
tiktokIntegration.logAddPaymentInfo(success);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// MARK: - Platform Integration Methods
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Get deferred attribution data from platform SDKs
|
|
832
|
+
*/
|
|
833
|
+
getDeferredAttributionData(): DeferredDeepLinkResult | null {
|
|
834
|
+
return metaIntegration.getDeferredDeepLinkData();
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Get platform integration status
|
|
839
|
+
*/
|
|
840
|
+
getPlatformIntegrationStatus(): { meta: boolean; tiktok: boolean; appleSearchAds: boolean } {
|
|
841
|
+
return {
|
|
842
|
+
meta: metaIntegration.isAvailable(),
|
|
843
|
+
tiktok: tiktokIntegration.isAvailable(),
|
|
844
|
+
appleSearchAds: appleSearchAdsIntegration.isAvailable(),
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Get Apple Search Ads attribution data
|
|
850
|
+
* Returns attribution if user installed via Apple Search Ads, null otherwise
|
|
851
|
+
*/
|
|
852
|
+
getAppleSearchAdsAttribution(): AppleSearchAdsAttribution | null {
|
|
853
|
+
return appleSearchAdsIntegration.getAttributionData();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Update tracking authorization status on all platform SDKs
|
|
858
|
+
* Call this AFTER the user responds to the ATT permission dialog
|
|
859
|
+
*/
|
|
860
|
+
async updateTrackingAuthorization(enabled: boolean): Promise<void> {
|
|
861
|
+
if (!this.state.initialized) {
|
|
862
|
+
errorLog('SDK not initialized. Call initialize() first.');
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
metaIntegration.updateTrackingAuthorization(enabled);
|
|
867
|
+
tiktokIntegration.updateTrackingAuthorization(enabled);
|
|
868
|
+
|
|
869
|
+
// Track ATT status event
|
|
870
|
+
await this.track('$att_status', {
|
|
871
|
+
authorized: enabled,
|
|
872
|
+
status: enabled ? 3 : 2,
|
|
873
|
+
status_name: enabled ? 'authorized' : 'denied',
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
debugLog(`ATT status updated: ${enabled ? 'authorized' : 'denied'}`);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Handle deferred deep link data from platform SDKs
|
|
881
|
+
*/
|
|
882
|
+
private async handleDeferredDeepLink(data: DeferredDeepLinkResult): Promise<void> {
|
|
883
|
+
try {
|
|
884
|
+
debugLog('Processing deferred deep link:', data);
|
|
885
|
+
|
|
886
|
+
// Track deferred attribution event
|
|
887
|
+
await this.track('$deferred_deep_link', {
|
|
888
|
+
url: data.url,
|
|
889
|
+
source: data.source,
|
|
890
|
+
fbclid: data.fbclid,
|
|
891
|
+
ttclid: data.ttclid,
|
|
892
|
+
utm_source: data.utmSource,
|
|
893
|
+
utm_medium: data.utmMedium,
|
|
894
|
+
utm_campaign: data.utmCampaign,
|
|
895
|
+
utm_content: data.utmContent,
|
|
896
|
+
utm_term: data.utmTerm,
|
|
897
|
+
campaign_id: data.campaignId,
|
|
898
|
+
adset_id: data.adsetId,
|
|
899
|
+
ad_id: data.adId,
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
// Merge into attribution manager
|
|
903
|
+
attributionManager.mergeWebAttribution({
|
|
904
|
+
fbclid: data.fbclid,
|
|
905
|
+
ttclid: data.ttclid,
|
|
906
|
+
utm_source: data.utmSource,
|
|
907
|
+
utm_medium: data.utmMedium,
|
|
908
|
+
utm_campaign: data.utmCampaign,
|
|
909
|
+
utm_content: data.utmContent,
|
|
910
|
+
utm_term: data.utmTerm,
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
debugLog('Deferred deep link processed successfully');
|
|
914
|
+
} catch (error) {
|
|
915
|
+
errorLog('Error processing deferred deep link:', error as Error);
|
|
916
|
+
}
|
|
561
917
|
}
|
|
562
918
|
|
|
563
919
|
/**
|
|
@@ -577,6 +933,22 @@ export class DatalyrSDK {
|
|
|
577
933
|
const fingerprintData = await createFingerprintData();
|
|
578
934
|
const attributionData = attributionManager.getAttributionData();
|
|
579
935
|
|
|
936
|
+
// Get Apple Search Ads attribution if available
|
|
937
|
+
const asaAttribution = appleSearchAdsIntegration.getAttributionData();
|
|
938
|
+
const asaData = asaAttribution?.attribution ? {
|
|
939
|
+
asa_campaign_id: asaAttribution.campaignId,
|
|
940
|
+
asa_campaign_name: asaAttribution.campaignName,
|
|
941
|
+
asa_ad_group_id: asaAttribution.adGroupId,
|
|
942
|
+
asa_ad_group_name: asaAttribution.adGroupName,
|
|
943
|
+
asa_keyword_id: asaAttribution.keywordId,
|
|
944
|
+
asa_keyword: asaAttribution.keyword,
|
|
945
|
+
asa_org_id: asaAttribution.orgId,
|
|
946
|
+
asa_org_name: asaAttribution.orgName,
|
|
947
|
+
asa_click_date: asaAttribution.clickDate,
|
|
948
|
+
asa_conversion_type: asaAttribution.conversionType,
|
|
949
|
+
asa_country_or_region: asaAttribution.countryOrRegion,
|
|
950
|
+
} : {};
|
|
951
|
+
|
|
580
952
|
const payload: EventPayload = {
|
|
581
953
|
workspaceId: this.state.config.workspaceId || 'mobile_sdk',
|
|
582
954
|
visitorId: this.state.visitorId,
|
|
@@ -598,6 +970,8 @@ export class DatalyrSDK {
|
|
|
598
970
|
timestamp: Date.now(),
|
|
599
971
|
// Attribution data
|
|
600
972
|
...attributionData,
|
|
973
|
+
// Apple Search Ads attribution
|
|
974
|
+
...asaData,
|
|
601
975
|
},
|
|
602
976
|
fingerprintData,
|
|
603
977
|
source: 'mobile_app',
|
|
@@ -846,6 +1220,68 @@ export class Datalyr {
|
|
|
846
1220
|
static updateAutoEventsConfig(config: Partial<AutoEventConfig>): void {
|
|
847
1221
|
datalyr.updateAutoEventsConfig(config);
|
|
848
1222
|
}
|
|
1223
|
+
|
|
1224
|
+
// Standard e-commerce events (all forward to Meta and TikTok)
|
|
1225
|
+
static async trackAddToCart(
|
|
1226
|
+
value: number,
|
|
1227
|
+
currency = 'USD',
|
|
1228
|
+
productId?: string,
|
|
1229
|
+
productName?: string
|
|
1230
|
+
): Promise<void> {
|
|
1231
|
+
await datalyr.trackAddToCart(value, currency, productId, productName);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
static async trackViewContent(
|
|
1235
|
+
contentId?: string,
|
|
1236
|
+
contentName?: string,
|
|
1237
|
+
contentType = 'product',
|
|
1238
|
+
value?: number,
|
|
1239
|
+
currency?: string
|
|
1240
|
+
): Promise<void> {
|
|
1241
|
+
await datalyr.trackViewContent(contentId, contentName, contentType, value, currency);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
static async trackInitiateCheckout(
|
|
1245
|
+
value: number,
|
|
1246
|
+
currency = 'USD',
|
|
1247
|
+
numItems?: number,
|
|
1248
|
+
productIds?: string[]
|
|
1249
|
+
): Promise<void> {
|
|
1250
|
+
await datalyr.trackInitiateCheckout(value, currency, numItems, productIds);
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
static async trackCompleteRegistration(method?: string): Promise<void> {
|
|
1254
|
+
await datalyr.trackCompleteRegistration(method);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
static async trackSearch(query: string, resultIds?: string[]): Promise<void> {
|
|
1258
|
+
await datalyr.trackSearch(query, resultIds);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
static async trackLead(value?: number, currency?: string): Promise<void> {
|
|
1262
|
+
await datalyr.trackLead(value, currency);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
static async trackAddPaymentInfo(success = true): Promise<void> {
|
|
1266
|
+
await datalyr.trackAddPaymentInfo(success);
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// Platform integration methods
|
|
1270
|
+
static getDeferredAttributionData(): DeferredDeepLinkResult | null {
|
|
1271
|
+
return datalyr.getDeferredAttributionData();
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
static getPlatformIntegrationStatus(): { meta: boolean; tiktok: boolean; appleSearchAds: boolean } {
|
|
1275
|
+
return datalyr.getPlatformIntegrationStatus();
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
static getAppleSearchAdsAttribution(): AppleSearchAdsAttribution | null {
|
|
1279
|
+
return datalyr.getAppleSearchAdsAttribution();
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
static async updateTrackingAuthorization(enabled: boolean): Promise<void> {
|
|
1283
|
+
await datalyr.updateTrackingAuthorization(enabled);
|
|
1284
|
+
}
|
|
849
1285
|
}
|
|
850
1286
|
|
|
851
1287
|
// Export default instance for backward compatibility
|
package/src/expo.ts
CHANGED
|
@@ -1,36 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Expo entry point - uses Expo-compatible utilities
|
|
3
|
+
* Import with: import { Datalyr } from '@datalyr/react-native/expo';
|
|
4
|
+
*
|
|
5
|
+
* Uses Expo-specific packages:
|
|
6
|
+
* - expo-application (app version, bundle ID)
|
|
7
|
+
* - expo-device (device model, manufacturer)
|
|
8
|
+
* - expo-network (network type detection)
|
|
9
|
+
*
|
|
10
|
+
* For React Native CLI, use:
|
|
11
|
+
* import { Datalyr } from '@datalyr/react-native';
|
|
12
|
+
*/
|
|
3
13
|
|
|
4
|
-
//
|
|
5
|
-
|
|
14
|
+
// Export Expo-specific SDK (uses utils-expo.ts)
|
|
15
|
+
export { DatalyrSDKExpo as DatalyrSDK, DatalyrExpo as Datalyr } from './datalyr-sdk-expo';
|
|
16
|
+
import datalyrExpo from './datalyr-sdk-expo';
|
|
17
|
+
export { datalyrExpo as datalyr };
|
|
6
18
|
|
|
7
|
-
|
|
19
|
+
// Export types
|
|
8
20
|
export * from './types';
|
|
21
|
+
|
|
22
|
+
// Export attribution manager
|
|
9
23
|
export { attributionManager } from './attribution';
|
|
24
|
+
|
|
25
|
+
// Export auto-events
|
|
10
26
|
export { createAutoEventsManager, AutoEventsManager } from './auto-events';
|
|
11
27
|
|
|
12
|
-
// Re-export Expo-specific utilities
|
|
13
|
-
export {
|
|
14
|
-
debugLog,
|
|
15
|
-
errorLog,
|
|
16
|
-
generateUUID,
|
|
17
|
-
Storage,
|
|
18
|
-
getOrCreateVisitorId,
|
|
28
|
+
// Re-export Expo-specific utilities for advanced usage
|
|
29
|
+
export {
|
|
30
|
+
debugLog,
|
|
31
|
+
errorLog,
|
|
32
|
+
generateUUID,
|
|
33
|
+
Storage,
|
|
34
|
+
getOrCreateVisitorId,
|
|
35
|
+
getOrCreateAnonymousId,
|
|
19
36
|
getOrCreateSessionId,
|
|
20
37
|
createFingerprintData,
|
|
21
38
|
getNetworkType,
|
|
22
39
|
validateEventName,
|
|
23
40
|
validateEventData,
|
|
24
41
|
isFirstLaunch,
|
|
25
|
-
checkAppVersion
|
|
42
|
+
checkAppVersion,
|
|
43
|
+
getDeviceInfo,
|
|
44
|
+
STORAGE_KEYS,
|
|
26
45
|
} from './utils-expo';
|
|
27
46
|
|
|
47
|
+
// Export HTTP client and event queue
|
|
28
48
|
export * from './http-client';
|
|
29
49
|
export * from './event-queue';
|
|
30
50
|
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
export
|
|
51
|
+
// Export SKAdNetwork components
|
|
52
|
+
export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
|
|
53
|
+
export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
|
|
54
|
+
|
|
55
|
+
// Export platform integrations
|
|
56
|
+
export { appleSearchAdsIntegration } from './integrations';
|
|
57
|
+
export type { AppleSearchAdsAttribution } from './native/DatalyrNativeBridge';
|
|
34
58
|
|
|
35
|
-
//
|
|
36
|
-
|
|
59
|
+
// Default export
|
|
60
|
+
export default datalyrExpo;
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Main entry point for React Native CLI
|
|
2
|
-
// Import
|
|
2
|
+
// Import with: import { Datalyr } from '@datalyr/react-native';
|
|
3
3
|
|
|
4
4
|
import { DatalyrSDK, Datalyr } from './datalyr-sdk';
|
|
5
5
|
|
|
@@ -26,5 +26,11 @@ export { DatalyrSDK };
|
|
|
26
26
|
export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
|
|
27
27
|
export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
// Export platform integrations
|
|
30
|
+
export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
|
|
31
|
+
|
|
32
|
+
// Export native bridge types
|
|
33
|
+
export type { AppleSearchAdsAttribution } from './native/DatalyrNativeBridge';
|
|
34
|
+
|
|
35
|
+
// Default export for compatibility
|
|
30
36
|
export default DatalyrSDK;
|