@datalyr/react-native 1.1.1 → 1.2.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.
- package/CHANGELOG.md +24 -141
- package/LICENSE +21 -0
- package/README.md +405 -217
- package/datalyr-react-native.podspec +31 -0
- package/ios/DatalyrNative.m +70 -0
- package/ios/DatalyrNative.swift +275 -0
- package/ios/DatalyrSKAdNetwork.m +26 -0
- package/lib/datalyr-sdk.d.ts +64 -3
- package/lib/datalyr-sdk.js +322 -3
- package/lib/index.d.ts +1 -0
- package/lib/index.js +4 -2
- package/lib/integrations/index.d.ts +6 -0
- package/lib/integrations/index.js +6 -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 +31 -0
- package/lib/native/DatalyrNativeBridge.js +168 -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 +10 -5
- package/src/datalyr-sdk-expo.ts +957 -0
- package/src/datalyr-sdk.ts +419 -19
- package/src/expo.ts +38 -18
- package/src/index.ts +5 -2
- package/src/integrations/index.ts +7 -0
- package/src/integrations/meta-integration.ts +238 -0
- package/src/integrations/tiktok-integration.ts +360 -0
- package/src/native/DatalyrNativeBridge.ts +271 -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
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta (Facebook) SDK Integration
|
|
3
|
+
* Uses bundled native iOS SDK for deferred deep linking, event forwarding, and Advanced Matching
|
|
4
|
+
*/
|
|
5
|
+
import { Platform } from 'react-native';
|
|
6
|
+
import { MetaNativeBridge, isNativeModuleAvailable } from '../native/DatalyrNativeBridge';
|
|
7
|
+
/**
|
|
8
|
+
* Meta Integration class for handling Facebook SDK operations
|
|
9
|
+
* Uses native iOS SDK bundled via CocoaPods (no additional npm packages required)
|
|
10
|
+
*/
|
|
11
|
+
export class MetaIntegration {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.config = null;
|
|
14
|
+
this.initialized = false;
|
|
15
|
+
this.available = false;
|
|
16
|
+
this.debug = false;
|
|
17
|
+
this.deferredDeepLinkData = null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Initialize Meta SDK with configuration
|
|
21
|
+
*/
|
|
22
|
+
async initialize(config, debug = false) {
|
|
23
|
+
var _a;
|
|
24
|
+
this.debug = debug;
|
|
25
|
+
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');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.available = isNativeModuleAvailable();
|
|
32
|
+
if (!this.available) {
|
|
33
|
+
this.log('Meta native module not available');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const success = await MetaNativeBridge.initialize(config.appId, config.clientToken, (_a = config.advertiserTrackingEnabled) !== null && _a !== void 0 ? _a : false);
|
|
38
|
+
if (success) {
|
|
39
|
+
this.initialized = true;
|
|
40
|
+
this.log(`Meta SDK initialized with App ID: ${config.appId}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
this.logError('Failed to initialize Meta SDK:', error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Update tracking authorization status (call after ATT prompt)
|
|
49
|
+
*/
|
|
50
|
+
async updateTrackingAuthorization(enabled) {
|
|
51
|
+
if (!this.available || !this.initialized)
|
|
52
|
+
return;
|
|
53
|
+
try {
|
|
54
|
+
await MetaNativeBridge.updateTrackingAuthorization(enabled);
|
|
55
|
+
this.log(`Meta ATT status updated: ${enabled ? 'authorized' : 'not authorized'}`);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.logError('Failed to update Meta tracking authorization:', error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Fetch deferred deep link from Meta SDK
|
|
63
|
+
* This captures fbclid for installs that went through App Store
|
|
64
|
+
*/
|
|
65
|
+
async fetchDeferredDeepLink() {
|
|
66
|
+
var _a;
|
|
67
|
+
if (!this.available || !this.initialized) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableDeferredDeepLink) === false) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const url = await MetaNativeBridge.fetchDeferredAppLink();
|
|
75
|
+
if (!url) {
|
|
76
|
+
this.log('No deferred deep link available from Meta');
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
// Parse the URL for attribution parameters
|
|
80
|
+
const result = this.parseDeepLinkUrl(url);
|
|
81
|
+
this.deferredDeepLinkData = result;
|
|
82
|
+
this.log(`Meta deferred deep link fetched: ${url}`);
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// This is expected to fail in some scenarios - log but don't treat as error
|
|
87
|
+
this.log('Could not fetch Meta deferred deep link (may not be available)');
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse deep link URL to extract attribution parameters
|
|
93
|
+
*/
|
|
94
|
+
parseDeepLinkUrl(urlString) {
|
|
95
|
+
const result = {
|
|
96
|
+
url: urlString,
|
|
97
|
+
source: 'meta',
|
|
98
|
+
};
|
|
99
|
+
try {
|
|
100
|
+
const url = new URL(urlString);
|
|
101
|
+
const params = url.searchParams;
|
|
102
|
+
// Extract known parameters
|
|
103
|
+
if (params.get('fbclid'))
|
|
104
|
+
result.fbclid = params.get('fbclid');
|
|
105
|
+
if (params.get('utm_source'))
|
|
106
|
+
result.utmSource = params.get('utm_source');
|
|
107
|
+
if (params.get('utm_medium'))
|
|
108
|
+
result.utmMedium = params.get('utm_medium');
|
|
109
|
+
if (params.get('utm_campaign'))
|
|
110
|
+
result.utmCampaign = params.get('utm_campaign');
|
|
111
|
+
if (params.get('utm_content'))
|
|
112
|
+
result.utmContent = params.get('utm_content');
|
|
113
|
+
if (params.get('utm_term'))
|
|
114
|
+
result.utmTerm = params.get('utm_term');
|
|
115
|
+
if (params.get('campaign_id'))
|
|
116
|
+
result.campaignId = params.get('campaign_id');
|
|
117
|
+
if (params.get('adset_id'))
|
|
118
|
+
result.adsetId = params.get('adset_id');
|
|
119
|
+
if (params.get('ad_id'))
|
|
120
|
+
result.adId = params.get('ad_id');
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
this.logError('Failed to parse deep link URL:', error);
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Log purchase event to Meta
|
|
129
|
+
*/
|
|
130
|
+
async logPurchase(value, currency, parameters) {
|
|
131
|
+
var _a;
|
|
132
|
+
if (!this.available || !this.initialized)
|
|
133
|
+
return;
|
|
134
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
135
|
+
return;
|
|
136
|
+
try {
|
|
137
|
+
await MetaNativeBridge.logPurchase(value, currency, parameters);
|
|
138
|
+
this.log(`Meta purchase event logged: ${value} ${currency}`);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
this.logError('Failed to log Meta purchase:', error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Log custom event to Meta
|
|
146
|
+
*/
|
|
147
|
+
async logEvent(eventName, valueToSum, parameters) {
|
|
148
|
+
var _a;
|
|
149
|
+
if (!this.available || !this.initialized)
|
|
150
|
+
return;
|
|
151
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
152
|
+
return;
|
|
153
|
+
try {
|
|
154
|
+
await MetaNativeBridge.logEvent(eventName, valueToSum, parameters);
|
|
155
|
+
this.log(`Meta event logged: ${eventName}`);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
this.logError('Failed to log Meta event:', error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Set user data for Advanced Matching (improves conversion attribution)
|
|
163
|
+
* Note: Meta's Advanced Matching uses these specific fields - externalId is not supported
|
|
164
|
+
*/
|
|
165
|
+
async setUserData(userData) {
|
|
166
|
+
if (!this.available || !this.initialized)
|
|
167
|
+
return;
|
|
168
|
+
try {
|
|
169
|
+
await MetaNativeBridge.setUserData(userData);
|
|
170
|
+
this.log('Meta user data set for Advanced Matching');
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
this.logError('Failed to set Meta user data:', error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Clear user data (call on logout)
|
|
178
|
+
*/
|
|
179
|
+
async clearUserData() {
|
|
180
|
+
if (!this.available || !this.initialized)
|
|
181
|
+
return;
|
|
182
|
+
try {
|
|
183
|
+
await MetaNativeBridge.clearUserData();
|
|
184
|
+
this.log('Meta user data cleared');
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
this.logError('Failed to clear Meta user data:', error);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get cached deferred deep link data
|
|
192
|
+
*/
|
|
193
|
+
getDeferredDeepLinkData() {
|
|
194
|
+
return this.deferredDeepLinkData;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Check if Meta SDK is available and initialized
|
|
198
|
+
*/
|
|
199
|
+
isAvailable() {
|
|
200
|
+
return this.available && this.initialized;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Check if Meta SDK native module is installed
|
|
204
|
+
*/
|
|
205
|
+
isInstalled() {
|
|
206
|
+
return this.available;
|
|
207
|
+
}
|
|
208
|
+
log(message, data) {
|
|
209
|
+
if (this.debug) {
|
|
210
|
+
console.log(`[Datalyr/Meta] ${message}`, data || '');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
logError(message, error) {
|
|
214
|
+
console.error(`[Datalyr/Meta] ${message}`, error);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Export singleton instance
|
|
218
|
+
export const metaIntegration = new MetaIntegration();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TikTok Business SDK Integration
|
|
3
|
+
* Uses bundled native iOS SDK for event forwarding and user identification
|
|
4
|
+
*/
|
|
5
|
+
import { TikTokConfig } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* TikTok Integration class for handling TikTok Business SDK operations
|
|
8
|
+
* Uses native iOS SDK bundled via CocoaPods (no additional npm packages required)
|
|
9
|
+
*/
|
|
10
|
+
export declare class TikTokIntegration {
|
|
11
|
+
private config;
|
|
12
|
+
private initialized;
|
|
13
|
+
private available;
|
|
14
|
+
private debug;
|
|
15
|
+
/**
|
|
16
|
+
* Initialize TikTok SDK with configuration
|
|
17
|
+
*/
|
|
18
|
+
initialize(config: TikTokConfig, debug?: boolean): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Update tracking authorization status (call after ATT prompt)
|
|
21
|
+
*/
|
|
22
|
+
updateTrackingAuthorization(enabled: boolean): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Log purchase event to TikTok (uses Purchase - TikTok's current standard event)
|
|
25
|
+
*/
|
|
26
|
+
logPurchase(value: number, currency: string, contentId?: string, contentType?: string, parameters?: Record<string, any>): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Log subscription event to TikTok
|
|
29
|
+
*/
|
|
30
|
+
logSubscription(value: number, currency: string, plan?: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Log add to cart event
|
|
33
|
+
*/
|
|
34
|
+
logAddToCart(value: number, currency: string, contentId?: string, contentType?: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Log view content event
|
|
37
|
+
*/
|
|
38
|
+
logViewContent(contentId?: string, contentName?: string, contentType?: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Log initiate checkout event
|
|
41
|
+
*/
|
|
42
|
+
logInitiateCheckout(value: number, currency: string, numItems?: number): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Log complete registration event
|
|
45
|
+
*/
|
|
46
|
+
logCompleteRegistration(method?: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Log search event
|
|
49
|
+
*/
|
|
50
|
+
logSearch(query: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Log lead event (uses Lead - current standard, SubmitForm is legacy)
|
|
53
|
+
*/
|
|
54
|
+
logLead(value?: number, currency?: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Log add payment info event
|
|
57
|
+
*/
|
|
58
|
+
logAddPaymentInfo(success: boolean): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Log custom event to TikTok
|
|
61
|
+
*/
|
|
62
|
+
trackEvent(eventName: string, properties?: Record<string, any>): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Identify user for improved attribution matching
|
|
65
|
+
*/
|
|
66
|
+
identify(email?: string, phone?: string, externalId?: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Clear user session (call on logout)
|
|
69
|
+
*/
|
|
70
|
+
logout(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Check if TikTok SDK is available and initialized
|
|
73
|
+
*/
|
|
74
|
+
isAvailable(): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Check if TikTok SDK native module is installed
|
|
77
|
+
*/
|
|
78
|
+
isInstalled(): boolean;
|
|
79
|
+
private log;
|
|
80
|
+
private logError;
|
|
81
|
+
}
|
|
82
|
+
export declare const tiktokIntegration: TikTokIntegration;
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TikTok Business SDK Integration
|
|
3
|
+
* Uses bundled native iOS SDK for event forwarding and user identification
|
|
4
|
+
*/
|
|
5
|
+
import { Platform } from 'react-native';
|
|
6
|
+
import { TikTokNativeBridge, isNativeModuleAvailable } from '../native/DatalyrNativeBridge';
|
|
7
|
+
/**
|
|
8
|
+
* TikTok standard event names (current as of 2025)
|
|
9
|
+
* Note: CompletePayment and SubmitForm are legacy, use Purchase and Lead instead
|
|
10
|
+
*/
|
|
11
|
+
const TikTokEvents = {
|
|
12
|
+
// Commerce events
|
|
13
|
+
PURCHASE: 'Purchase',
|
|
14
|
+
ADD_TO_CART: 'AddToCart',
|
|
15
|
+
ADD_TO_WISHLIST: 'AddToWishlist',
|
|
16
|
+
INITIATE_CHECKOUT: 'InitiateCheckout',
|
|
17
|
+
ADD_PAYMENT_INFO: 'AddPaymentInfo',
|
|
18
|
+
VIEW_CONTENT: 'ViewContent',
|
|
19
|
+
SEARCH: 'Search',
|
|
20
|
+
// User events
|
|
21
|
+
COMPLETE_REGISTRATION: 'CompleteRegistration',
|
|
22
|
+
SUBSCRIBE: 'Subscribe',
|
|
23
|
+
START_TRIAL: 'StartTrial',
|
|
24
|
+
LEAD: 'Lead',
|
|
25
|
+
CONTACT: 'Contact',
|
|
26
|
+
// App events
|
|
27
|
+
DOWNLOAD: 'Download',
|
|
28
|
+
SCHEDULE: 'Schedule',
|
|
29
|
+
SUBMIT_APPLICATION: 'SubmitApplication',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* TikTok Integration class for handling TikTok Business SDK operations
|
|
33
|
+
* Uses native iOS SDK bundled via CocoaPods (no additional npm packages required)
|
|
34
|
+
*/
|
|
35
|
+
export class TikTokIntegration {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.config = null;
|
|
38
|
+
this.initialized = false;
|
|
39
|
+
this.available = false;
|
|
40
|
+
this.debug = false;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Initialize TikTok SDK with configuration
|
|
44
|
+
*/
|
|
45
|
+
async initialize(config, debug = false) {
|
|
46
|
+
this.debug = debug;
|
|
47
|
+
this.config = config;
|
|
48
|
+
// Only available on iOS via native module
|
|
49
|
+
if (Platform.OS !== 'ios') {
|
|
50
|
+
this.log('TikTok SDK only available on iOS');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.available = isNativeModuleAvailable();
|
|
54
|
+
if (!this.available) {
|
|
55
|
+
this.log('TikTok native module not available');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const success = await TikTokNativeBridge.initialize(config.appId, config.tiktokAppId, config.accessToken, debug);
|
|
60
|
+
if (success) {
|
|
61
|
+
this.initialized = true;
|
|
62
|
+
this.log(`TikTok SDK initialized with App ID: ${config.tiktokAppId}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
this.logError('Failed to initialize TikTok SDK:', error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Update tracking authorization status (call after ATT prompt)
|
|
71
|
+
*/
|
|
72
|
+
async updateTrackingAuthorization(enabled) {
|
|
73
|
+
if (!this.available || !this.initialized)
|
|
74
|
+
return;
|
|
75
|
+
try {
|
|
76
|
+
// TikTok SDK auto-handles ATT, but we track the event
|
|
77
|
+
if (enabled) {
|
|
78
|
+
await this.trackEvent('ATTAuthorized');
|
|
79
|
+
}
|
|
80
|
+
await TikTokNativeBridge.updateTrackingAuthorization(enabled);
|
|
81
|
+
this.log(`TikTok ATT status: ${enabled ? 'authorized' : 'not authorized'}`);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
this.logError('Failed to update TikTok tracking authorization:', error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Log purchase event to TikTok (uses Purchase - TikTok's current standard event)
|
|
89
|
+
*/
|
|
90
|
+
async logPurchase(value, currency, contentId, contentType, parameters) {
|
|
91
|
+
var _a;
|
|
92
|
+
if (!this.available || !this.initialized)
|
|
93
|
+
return;
|
|
94
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
95
|
+
return;
|
|
96
|
+
try {
|
|
97
|
+
const properties = {
|
|
98
|
+
value,
|
|
99
|
+
currency,
|
|
100
|
+
...parameters,
|
|
101
|
+
};
|
|
102
|
+
if (contentId)
|
|
103
|
+
properties.content_id = contentId;
|
|
104
|
+
if (contentType)
|
|
105
|
+
properties.content_type = contentType;
|
|
106
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.PURCHASE, undefined, properties);
|
|
107
|
+
this.log(`TikTok Purchase event logged: ${value} ${currency}`);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
this.logError('Failed to log TikTok purchase:', error);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Log subscription event to TikTok
|
|
115
|
+
*/
|
|
116
|
+
async logSubscription(value, currency, plan) {
|
|
117
|
+
var _a;
|
|
118
|
+
if (!this.available || !this.initialized)
|
|
119
|
+
return;
|
|
120
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
121
|
+
return;
|
|
122
|
+
try {
|
|
123
|
+
const properties = {
|
|
124
|
+
value,
|
|
125
|
+
currency,
|
|
126
|
+
};
|
|
127
|
+
if (plan) {
|
|
128
|
+
properties.content_id = plan;
|
|
129
|
+
properties.content_type = 'subscription';
|
|
130
|
+
}
|
|
131
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.SUBSCRIBE, undefined, properties);
|
|
132
|
+
this.log(`TikTok subscription event logged: ${value} ${currency}`);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
this.logError('Failed to log TikTok subscription:', error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Log add to cart event
|
|
140
|
+
*/
|
|
141
|
+
async logAddToCart(value, currency, contentId, contentType) {
|
|
142
|
+
var _a;
|
|
143
|
+
if (!this.available || !this.initialized)
|
|
144
|
+
return;
|
|
145
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
146
|
+
return;
|
|
147
|
+
try {
|
|
148
|
+
const properties = {
|
|
149
|
+
value,
|
|
150
|
+
currency,
|
|
151
|
+
};
|
|
152
|
+
if (contentId)
|
|
153
|
+
properties.content_id = contentId;
|
|
154
|
+
if (contentType)
|
|
155
|
+
properties.content_type = contentType;
|
|
156
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.ADD_TO_CART, undefined, properties);
|
|
157
|
+
this.log('TikTok add to cart event logged');
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
this.logError('Failed to log TikTok add to cart:', error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Log view content event
|
|
165
|
+
*/
|
|
166
|
+
async logViewContent(contentId, contentName, contentType) {
|
|
167
|
+
var _a;
|
|
168
|
+
if (!this.available || !this.initialized)
|
|
169
|
+
return;
|
|
170
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
171
|
+
return;
|
|
172
|
+
try {
|
|
173
|
+
const properties = {};
|
|
174
|
+
if (contentId)
|
|
175
|
+
properties.content_id = contentId;
|
|
176
|
+
if (contentName)
|
|
177
|
+
properties.content_name = contentName;
|
|
178
|
+
if (contentType)
|
|
179
|
+
properties.content_type = contentType;
|
|
180
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.VIEW_CONTENT, undefined, properties);
|
|
181
|
+
this.log('TikTok view content event logged');
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
this.logError('Failed to log TikTok view content:', error);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Log initiate checkout event
|
|
189
|
+
*/
|
|
190
|
+
async logInitiateCheckout(value, currency, numItems) {
|
|
191
|
+
var _a;
|
|
192
|
+
if (!this.available || !this.initialized)
|
|
193
|
+
return;
|
|
194
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
195
|
+
return;
|
|
196
|
+
try {
|
|
197
|
+
const properties = {
|
|
198
|
+
value,
|
|
199
|
+
currency,
|
|
200
|
+
};
|
|
201
|
+
if (numItems)
|
|
202
|
+
properties.quantity = numItems;
|
|
203
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.INITIATE_CHECKOUT, undefined, properties);
|
|
204
|
+
this.log('TikTok initiate checkout event logged');
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
this.logError('Failed to log TikTok initiate checkout:', error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Log complete registration event
|
|
212
|
+
*/
|
|
213
|
+
async logCompleteRegistration(method) {
|
|
214
|
+
var _a;
|
|
215
|
+
if (!this.available || !this.initialized)
|
|
216
|
+
return;
|
|
217
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
218
|
+
return;
|
|
219
|
+
try {
|
|
220
|
+
const properties = {};
|
|
221
|
+
if (method)
|
|
222
|
+
properties.registration_method = method;
|
|
223
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.COMPLETE_REGISTRATION, undefined, properties);
|
|
224
|
+
this.log('TikTok complete registration event logged');
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
this.logError('Failed to log TikTok complete registration:', error);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Log search event
|
|
232
|
+
*/
|
|
233
|
+
async logSearch(query) {
|
|
234
|
+
var _a;
|
|
235
|
+
if (!this.available || !this.initialized)
|
|
236
|
+
return;
|
|
237
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
238
|
+
return;
|
|
239
|
+
try {
|
|
240
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.SEARCH, undefined, { query });
|
|
241
|
+
this.log('TikTok search event logged');
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
this.logError('Failed to log TikTok search:', error);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Log lead event (uses Lead - current standard, SubmitForm is legacy)
|
|
249
|
+
*/
|
|
250
|
+
async logLead(value, currency) {
|
|
251
|
+
var _a;
|
|
252
|
+
if (!this.available || !this.initialized)
|
|
253
|
+
return;
|
|
254
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
255
|
+
return;
|
|
256
|
+
try {
|
|
257
|
+
const properties = {};
|
|
258
|
+
if (value !== undefined)
|
|
259
|
+
properties.value = value;
|
|
260
|
+
if (currency)
|
|
261
|
+
properties.currency = currency;
|
|
262
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.LEAD, undefined, properties);
|
|
263
|
+
this.log('TikTok lead event logged');
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
this.logError('Failed to log TikTok lead:', error);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Log add payment info event
|
|
271
|
+
*/
|
|
272
|
+
async logAddPaymentInfo(success) {
|
|
273
|
+
var _a;
|
|
274
|
+
if (!this.available || !this.initialized)
|
|
275
|
+
return;
|
|
276
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
277
|
+
return;
|
|
278
|
+
try {
|
|
279
|
+
await TikTokNativeBridge.trackEvent(TikTokEvents.ADD_PAYMENT_INFO, undefined, { success });
|
|
280
|
+
this.log('TikTok add payment info event logged');
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
this.logError('Failed to log TikTok add payment info:', error);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Log custom event to TikTok
|
|
288
|
+
*/
|
|
289
|
+
async trackEvent(eventName, properties) {
|
|
290
|
+
var _a;
|
|
291
|
+
if (!this.available || !this.initialized)
|
|
292
|
+
return;
|
|
293
|
+
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableAppEvents) === false)
|
|
294
|
+
return;
|
|
295
|
+
try {
|
|
296
|
+
await TikTokNativeBridge.trackEvent(eventName, undefined, properties || {});
|
|
297
|
+
this.log(`TikTok event logged: ${eventName}`);
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
this.logError('Failed to log TikTok event:', error);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Identify user for improved attribution matching
|
|
305
|
+
*/
|
|
306
|
+
async identify(email, phone, externalId) {
|
|
307
|
+
if (!this.available || !this.initialized)
|
|
308
|
+
return;
|
|
309
|
+
// Only call identify if we have at least one value
|
|
310
|
+
if (!email && !phone && !externalId)
|
|
311
|
+
return;
|
|
312
|
+
try {
|
|
313
|
+
await TikTokNativeBridge.identify(externalId, email, phone);
|
|
314
|
+
this.log('TikTok user identification set');
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
this.logError('Failed to identify TikTok user:', error);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Clear user session (call on logout)
|
|
322
|
+
*/
|
|
323
|
+
async logout() {
|
|
324
|
+
if (!this.available || !this.initialized)
|
|
325
|
+
return;
|
|
326
|
+
try {
|
|
327
|
+
await TikTokNativeBridge.logout();
|
|
328
|
+
this.log('TikTok user logged out');
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
this.logError('Failed to logout TikTok user:', error);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Check if TikTok SDK is available and initialized
|
|
336
|
+
*/
|
|
337
|
+
isAvailable() {
|
|
338
|
+
return this.available && this.initialized;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Check if TikTok SDK native module is installed
|
|
342
|
+
*/
|
|
343
|
+
isInstalled() {
|
|
344
|
+
return this.available;
|
|
345
|
+
}
|
|
346
|
+
log(message, data) {
|
|
347
|
+
if (this.debug) {
|
|
348
|
+
console.log(`[Datalyr/TikTok] ${message}`, data || '');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
logError(message, error) {
|
|
352
|
+
console.error(`[Datalyr/TikTok] ${message}`, error);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Export singleton instance
|
|
356
|
+
export const tiktokIntegration = new TikTokIntegration();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Bridge for Meta and TikTok SDKs
|
|
3
|
+
* Uses bundled native modules instead of separate npm packages
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if native module is available
|
|
7
|
+
*/
|
|
8
|
+
export declare const isNativeModuleAvailable: () => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Get SDK availability status
|
|
11
|
+
*/
|
|
12
|
+
export declare const getSDKAvailability: () => Promise<{
|
|
13
|
+
meta: boolean;
|
|
14
|
+
tiktok: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const MetaNativeBridge: {
|
|
17
|
+
initialize(appId: string, clientToken?: string, advertiserTrackingEnabled?: boolean): Promise<boolean>;
|
|
18
|
+
fetchDeferredAppLink(): Promise<string | null>;
|
|
19
|
+
logEvent(eventName: string, valueToSum?: number, parameters?: Record<string, any>): Promise<boolean>;
|
|
20
|
+
logPurchase(amount: number, currency: string, parameters?: Record<string, any>): Promise<boolean>;
|
|
21
|
+
setUserData(userData: Record<string, string | undefined>): Promise<boolean>;
|
|
22
|
+
clearUserData(): Promise<boolean>;
|
|
23
|
+
updateTrackingAuthorization(enabled: boolean): Promise<boolean>;
|
|
24
|
+
};
|
|
25
|
+
export declare const TikTokNativeBridge: {
|
|
26
|
+
initialize(appId: string, tiktokAppId: string, accessToken?: string, debug?: boolean): Promise<boolean>;
|
|
27
|
+
trackEvent(eventName: string, eventId?: string, properties?: Record<string, any>): Promise<boolean>;
|
|
28
|
+
identify(externalId?: string, email?: string, phone?: string): Promise<boolean>;
|
|
29
|
+
logout(): Promise<boolean>;
|
|
30
|
+
updateTrackingAuthorization(enabled: boolean): Promise<boolean>;
|
|
31
|
+
};
|