@datalyr/react-native 1.4.9 → 1.6.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 (38) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +17 -127
  3. package/android/build.gradle +0 -7
  4. package/android/src/main/java/com/datalyr/reactnative/DatalyrNativeModule.java +2 -380
  5. package/android/src/main/java/com/datalyr/reactnative/DatalyrPackage.java +1 -1
  6. package/datalyr-react-native.podspec +3 -7
  7. package/expo-module.config.json +4 -1
  8. package/ios/DatalyrNativeModule.swift +0 -266
  9. package/lib/datalyr-sdk.d.ts +8 -4
  10. package/lib/datalyr-sdk.js +83 -143
  11. package/lib/http-client.js +2 -2
  12. package/lib/index.d.ts +1 -1
  13. package/lib/index.js +1 -1
  14. package/lib/integrations/index.d.ts +3 -4
  15. package/lib/integrations/index.js +3 -4
  16. package/lib/native/DatalyrNativeBridge.d.ts +6 -22
  17. package/lib/native/DatalyrNativeBridge.js +6 -147
  18. package/lib/native/index.d.ts +1 -1
  19. package/lib/native/index.js +1 -1
  20. package/lib/types.d.ts +1 -19
  21. package/package.json +3 -5
  22. package/src/datalyr-sdk-expo.ts +6 -141
  23. package/src/datalyr-sdk.ts +96 -173
  24. package/src/http-client.ts +2 -2
  25. package/src/index.ts +1 -1
  26. package/src/integrations/index.ts +3 -4
  27. package/src/native/DatalyrNativeBridge.ts +6 -241
  28. package/src/native/index.ts +0 -2
  29. package/src/types.ts +2 -25
  30. package/src/utils-expo.ts +2 -2
  31. package/ios/DatalyrObjCExceptionCatcher.h +0 -14
  32. package/ios/DatalyrObjCExceptionCatcher.m +0 -30
  33. package/lib/integrations/meta-integration.d.ts +0 -77
  34. package/lib/integrations/meta-integration.js +0 -219
  35. package/lib/integrations/tiktok-integration.d.ts +0 -83
  36. package/lib/integrations/tiktok-integration.js +0 -360
  37. package/src/integrations/meta-integration.ts +0 -239
  38. package/src/integrations/tiktok-integration.ts +0 -363
@@ -1,283 +1,17 @@
1
1
  import ExpoModulesCore
2
- import FBSDKCoreKit
3
- import TikTokBusinessSDK
4
2
  import AdServices
5
3
  import AppTrackingTransparency
6
4
  import AdSupport
7
5
 
8
6
  public class DatalyrNativeModule: Module {
9
- private var tiktokInitialized = false
10
- private var metaInitialized = false
11
7
 
12
8
  public func definition() -> ModuleDefinition {
13
9
  Name("DatalyrNative")
14
10
 
15
- // MARK: - Meta (Facebook) SDK Methods
16
-
17
- AsyncFunction("initializeMetaSDK") { (appId: String, clientToken: String?, advertiserTrackingEnabled: Bool, promise: Promise) in
18
- DispatchQueue.main.async { [weak self] in
19
- Settings.shared.appID = appId
20
-
21
- if let token = clientToken, !token.isEmpty {
22
- Settings.shared.clientToken = token
23
- }
24
-
25
- Settings.shared.isAdvertiserTrackingEnabled = advertiserTrackingEnabled
26
- Settings.shared.isAdvertiserIDCollectionEnabled = advertiserTrackingEnabled
27
-
28
- var initError: NSError?
29
- let success = DatalyrObjCExceptionCatcher.tryBlock({
30
- ApplicationDelegate.shared.application(
31
- UIApplication.shared,
32
- didFinishLaunchingWithOptions: nil
33
- )
34
- }, error: &initError)
35
-
36
- if success {
37
- self?.metaInitialized = true
38
- promise.resolve(true)
39
- } else {
40
- let message = initError?.localizedDescription ?? "Unknown ObjC exception during Meta SDK init"
41
- promise.reject("meta_init_error", message)
42
- }
43
- }
44
- }
45
-
46
- AsyncFunction("fetchDeferredAppLink") { (promise: Promise) in
47
- DispatchQueue.main.async {
48
- AppLinkUtility.fetchDeferredAppLink { url, error in
49
- if error != nil {
50
- promise.resolve(nil)
51
- return
52
- }
53
-
54
- if let url = url {
55
- promise.resolve(url.absoluteString)
56
- } else {
57
- promise.resolve(nil)
58
- }
59
- }
60
- }
61
- }
62
-
63
- AsyncFunction("logMetaEvent") { (eventName: String, valueToSum: Double?, parameters: [String: Any]?, promise: Promise) in
64
- guard self.metaInitialized else {
65
- promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
66
- return
67
- }
68
-
69
- DispatchQueue.main.async {
70
- var params: [AppEvents.ParameterName: Any] = [:]
71
-
72
- if let dict = parameters {
73
- for (key, value) in dict {
74
- params[AppEvents.ParameterName(key)] = value
75
- }
76
- }
77
-
78
- var logError: NSError?
79
- DatalyrObjCExceptionCatcher.tryBlock({
80
- if let value = valueToSum {
81
- AppEvents.shared.logEvent(AppEvents.Name(eventName), valueToSum: value, parameters: params)
82
- } else if params.isEmpty {
83
- AppEvents.shared.logEvent(AppEvents.Name(eventName))
84
- } else {
85
- AppEvents.shared.logEvent(AppEvents.Name(eventName), parameters: params)
86
- }
87
- }, error: &logError)
88
-
89
- if let logError = logError {
90
- promise.reject("meta_event_error", logError.localizedDescription)
91
- } else {
92
- promise.resolve(true)
93
- }
94
- }
95
- }
96
-
97
- AsyncFunction("logMetaPurchase") { (amount: Double, currency: String, parameters: [String: Any]?, promise: Promise) in
98
- guard self.metaInitialized else {
99
- promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
100
- return
101
- }
102
-
103
- DispatchQueue.main.async {
104
- var params: [AppEvents.ParameterName: Any] = [:]
105
-
106
- if let dict = parameters {
107
- for (key, value) in dict {
108
- params[AppEvents.ParameterName(key)] = value
109
- }
110
- }
111
-
112
- var logError: NSError?
113
- DatalyrObjCExceptionCatcher.tryBlock({
114
- AppEvents.shared.logPurchase(amount: amount, currency: currency, parameters: params)
115
- }, error: &logError)
116
-
117
- if let logError = logError {
118
- promise.reject("meta_event_error", logError.localizedDescription)
119
- } else {
120
- promise.resolve(true)
121
- }
122
- }
123
- }
124
-
125
- AsyncFunction("setMetaUserData") { (userData: [String: Any], promise: Promise) in
126
- guard self.metaInitialized else {
127
- promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
128
- return
129
- }
130
-
131
- DispatchQueue.main.async {
132
- if let email = userData["email"] as? String { AppEvents.shared.setUserData(email, forType: .email) }
133
- if let firstName = userData["firstName"] as? String { AppEvents.shared.setUserData(firstName, forType: .firstName) }
134
- if let lastName = userData["lastName"] as? String { AppEvents.shared.setUserData(lastName, forType: .lastName) }
135
- if let phone = userData["phone"] as? String { AppEvents.shared.setUserData(phone, forType: .phone) }
136
- if let dateOfBirth = userData["dateOfBirth"] as? String { AppEvents.shared.setUserData(dateOfBirth, forType: .dateOfBirth) }
137
- if let gender = userData["gender"] as? String { AppEvents.shared.setUserData(gender, forType: .gender) }
138
- if let city = userData["city"] as? String { AppEvents.shared.setUserData(city, forType: .city) }
139
- if let state = userData["state"] as? String { AppEvents.shared.setUserData(state, forType: .state) }
140
- if let zip = userData["zip"] as? String { AppEvents.shared.setUserData(zip, forType: .zip) }
141
- if let country = userData["country"] as? String { AppEvents.shared.setUserData(country, forType: .country) }
142
-
143
- promise.resolve(true)
144
- }
145
- }
146
-
147
- AsyncFunction("clearMetaUserData") { (promise: Promise) in
148
- guard self.metaInitialized else {
149
- promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
150
- return
151
- }
152
-
153
- DispatchQueue.main.async {
154
- AppEvents.shared.clearUserData()
155
- promise.resolve(true)
156
- }
157
- }
158
-
159
- AsyncFunction("updateMetaTrackingAuthorization") { (enabled: Bool, promise: Promise) in
160
- guard self.metaInitialized else {
161
- promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
162
- return
163
- }
164
-
165
- DispatchQueue.main.async {
166
- Settings.shared.isAdvertiserTrackingEnabled = enabled
167
- Settings.shared.isAdvertiserIDCollectionEnabled = enabled
168
- promise.resolve(true)
169
- }
170
- }
171
-
172
- // MARK: - TikTok SDK Methods
173
-
174
- AsyncFunction("initializeTikTokSDK") { (appId: String, tiktokAppId: String, accessToken: String?, debug: Bool, promise: Promise) in
175
- DispatchQueue.main.async { [weak self] in
176
- guard let token = accessToken, !token.isEmpty else {
177
- promise.reject("tiktok_init_error", "TikTok accessToken is required. The deprecated init without accessToken has been removed.")
178
- return
179
- }
180
-
181
- let config = TikTokConfig(accessToken: token, appId: appId, tiktokAppId: tiktokAppId)
182
-
183
- if debug {
184
- config?.setLogLevel(TikTokLogLevelDebug)
185
- }
186
-
187
- guard let validConfig = config else {
188
- promise.reject("tiktok_init_error", "Failed to create TikTok config")
189
- return
190
- }
191
-
192
- var initError: NSError?
193
- let success = DatalyrObjCExceptionCatcher.tryBlock({
194
- TikTokBusiness.initializeSdk(validConfig)
195
- }, error: &initError)
196
-
197
- if success {
198
- self?.tiktokInitialized = true
199
- promise.resolve(true)
200
- } else {
201
- let message = initError?.localizedDescription ?? "Unknown ObjC exception during TikTok SDK init"
202
- promise.reject("tiktok_init_error", message)
203
- }
204
- }
205
- }
206
-
207
- AsyncFunction("trackTikTokEvent") { (eventName: String, eventId: String?, properties: [String: Any]?, promise: Promise) in
208
- guard self.tiktokInitialized else {
209
- promise.reject("tiktok_not_initialized", "TikTok SDK not initialized. Call initializeTikTokSDK first.")
210
- return
211
- }
212
-
213
- DispatchQueue.main.async {
214
- let event: TikTokBaseEvent
215
-
216
- if let eid = eventId, !eid.isEmpty {
217
- event = TikTokBaseEvent(eventName: eventName, eventId: eid)
218
- } else {
219
- event = TikTokBaseEvent(eventName: eventName)
220
- }
221
-
222
- if let dict = properties {
223
- for (key, value) in dict {
224
- event.addProperty(withKey: key, value: value)
225
- }
226
- }
227
-
228
- var trackError: NSError?
229
- DatalyrObjCExceptionCatcher.tryBlock({
230
- TikTokBusiness.trackTTEvent(event)
231
- }, error: &trackError)
232
-
233
- if let trackError = trackError {
234
- promise.reject("tiktok_event_error", trackError.localizedDescription)
235
- } else {
236
- promise.resolve(true)
237
- }
238
- }
239
- }
240
-
241
- AsyncFunction("identifyTikTokUser") { (externalId: String, externalUserName: String, phoneNumber: String, email: String, promise: Promise) in
242
- guard self.tiktokInitialized else {
243
- promise.reject("tiktok_not_initialized", "TikTok SDK not initialized. Call initializeTikTokSDK first.")
244
- return
245
- }
246
-
247
- DispatchQueue.main.async {
248
- TikTokBusiness.identify(
249
- withExternalID: externalId.isEmpty ? nil : externalId,
250
- externalUserName: externalUserName.isEmpty ? nil : externalUserName,
251
- phoneNumber: phoneNumber.isEmpty ? nil : phoneNumber,
252
- email: email.isEmpty ? nil : email
253
- )
254
- promise.resolve(true)
255
- }
256
- }
257
-
258
- AsyncFunction("logoutTikTok") { (promise: Promise) in
259
- guard self.tiktokInitialized else {
260
- promise.reject("tiktok_not_initialized", "TikTok SDK not initialized. Call initializeTikTokSDK first.")
261
- return
262
- }
263
-
264
- DispatchQueue.main.async {
265
- TikTokBusiness.logout()
266
- promise.resolve(true)
267
- }
268
- }
269
-
270
- AsyncFunction("updateTikTokTrackingAuthorization") { (enabled: Bool, promise: Promise) in
271
- // TikTok SDK handles ATT automatically, but we track the change
272
- promise.resolve(true)
273
- }
274
-
275
11
  // MARK: - SDK Availability Check
276
12
 
277
13
  AsyncFunction("getSDKAvailability") { (promise: Promise) in
278
14
  promise.resolve([
279
- "meta": true,
280
- "tiktok": true,
281
15
  "appleSearchAds": true
282
16
  ])
283
17
  }
@@ -34,6 +34,13 @@ export declare class DatalyrSDK {
34
34
  * Called automatically during identify() if email is provided
35
35
  */
36
36
  private fetchAndMergeWebAttribution;
37
+ /**
38
+ * Fetch deferred web attribution on first app install.
39
+ * Uses IP-based matching (iOS) or Play Store referrer (Android) to recover
40
+ * attribution data (fbclid, utm_*, etc.) from a prelander web visit.
41
+ * Called automatically during initialize() when a fresh install is detected.
42
+ */
43
+ private fetchDeferredWebAttribution;
37
44
  /**
38
45
  * Alias a user (connect anonymous user to known user)
39
46
  */
@@ -155,8 +162,6 @@ export declare class DatalyrSDK {
155
162
  * Get platform integration status
156
163
  */
157
164
  getPlatformIntegrationStatus(): {
158
- meta: boolean;
159
- tiktok: boolean;
160
165
  appleSearchAds: boolean;
161
166
  playInstallReferrer: boolean;
162
167
  };
@@ -269,9 +274,8 @@ export declare class Datalyr {
269
274
  static trackAddPaymentInfo(success?: boolean): Promise<void>;
270
275
  static getDeferredAttributionData(): DeferredDeepLinkResult | null;
271
276
  static getPlatformIntegrationStatus(): {
272
- meta: boolean;
273
- tiktok: boolean;
274
277
  appleSearchAds: boolean;
278
+ playInstallReferrer: boolean;
275
279
  };
276
280
  static getAppleSearchAdsAttribution(): AppleSearchAdsAttribution | null;
277
281
  static updateTrackingAuthorization(enabled: boolean): Promise<void>;
@@ -7,7 +7,7 @@ import { journeyManager } from './journey';
7
7
  import { AutoEventsManager } from './auto-events';
8
8
  import { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
9
9
  import { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
10
- import { metaIntegration, tiktokIntegration, appleSearchAdsIntegration, playInstallReferrerIntegration } from './integrations';
10
+ import { appleSearchAdsIntegration, playInstallReferrerIntegration } from './integrations';
11
11
  import { AdvertiserInfoBridge } from './native/DatalyrNativeBridge';
12
12
  import { networkStatusManager } from './network-status';
13
13
  export class DatalyrSDK {
@@ -49,7 +49,7 @@ export class DatalyrSDK {
49
49
  * Initialize the SDK with configuration
50
50
  */
51
51
  async initialize(config) {
52
- var _a, _b, _c, _d;
52
+ var _a;
53
53
  try {
54
54
  debugLog('Initializing Datalyr SDK...', { workspaceId: config.workspaceId });
55
55
  // Validate configuration
@@ -152,22 +152,6 @@ export class DatalyrSDK {
152
152
  // Google Play Install Referrer (Android only)
153
153
  playInstallReferrerIntegration.initialize(),
154
154
  ];
155
- // Add Meta initialization if configured
156
- if ((_b = config.meta) === null || _b === void 0 ? void 0 : _b.appId) {
157
- platformInitPromises.push(metaIntegration.initialize(config.meta, config.debug).then(async () => {
158
- // After Meta initializes, fetch deferred deep link
159
- if (config.enableAttribution !== false) {
160
- const deferredLink = await metaIntegration.fetchDeferredDeepLink();
161
- if (deferredLink) {
162
- await this.handleDeferredDeepLink(deferredLink);
163
- }
164
- }
165
- }));
166
- }
167
- // Add TikTok initialization if configured
168
- if (((_c = config.tiktok) === null || _c === void 0 ? void 0 : _c.appId) && ((_d = config.tiktok) === null || _d === void 0 ? void 0 : _d.tiktokAppId)) {
169
- platformInitPromises.push(tiktokIntegration.initialize(config.tiktok, config.debug));
170
- }
171
155
  // Wait for all platform integrations to complete
172
156
  await Promise.all(platformInitPromises);
173
157
  // Cache advertiser info (IDFA/GAID, ATT status) once at init to avoid per-event native bridge calls
@@ -178,8 +162,6 @@ export class DatalyrSDK {
178
162
  errorLog('Failed to cache advertiser info:', error);
179
163
  }
180
164
  debugLog('Platform integrations initialized', {
181
- meta: metaIntegration.isAvailable(),
182
- tiktok: tiktokIntegration.isAvailable(),
183
165
  appleSearchAds: appleSearchAdsIntegration.isAvailable(),
184
166
  playInstallReferrer: playInstallReferrerIntegration.isAvailable(),
185
167
  });
@@ -187,10 +169,15 @@ export class DatalyrSDK {
187
169
  this.state.initialized = true;
188
170
  // Check for app install (after SDK is marked as initialized)
189
171
  if (attributionManager.isInstall()) {
172
+ // iOS: Attempt deferred web-to-app attribution via IP matching before tracking install
173
+ // Android: Play Store referrer is handled by playInstallReferrerIntegration
174
+ if (Platform.OS === 'ios') {
175
+ await this.fetchDeferredWebAttribution();
176
+ }
190
177
  const installData = await attributionManager.trackInstall();
191
178
  await this.track('app_install', {
192
179
  platform: Platform.OS === 'ios' || Platform.OS === 'android' ? Platform.OS : 'android',
193
- sdk_version: '1.4.9',
180
+ sdk_version: '1.6.0',
194
181
  ...installData,
195
182
  });
196
183
  }
@@ -282,28 +269,6 @@ export class DatalyrSDK {
282
269
  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));
283
270
  const gender = properties === null || properties === void 0 ? void 0 : properties.gender;
284
271
  const city = properties === null || properties === void 0 ? void 0 : properties.city;
285
- const state = properties === null || properties === void 0 ? void 0 : properties.state;
286
- 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));
287
- const country = properties === null || properties === void 0 ? void 0 : properties.country;
288
- // Meta Advanced Matching
289
- if (metaIntegration.isAvailable()) {
290
- metaIntegration.setUserData({
291
- email,
292
- firstName,
293
- lastName,
294
- phone,
295
- dateOfBirth,
296
- gender,
297
- city,
298
- state,
299
- zip,
300
- country,
301
- });
302
- }
303
- // TikTok identification
304
- if (tiktokIntegration.isAvailable()) {
305
- tiktokIntegration.identify(email, phone, userId);
306
- }
307
272
  }
308
273
  catch (error) {
309
274
  errorLog('Error identifying user:', error);
@@ -368,6 +333,77 @@ export class DatalyrSDK {
368
333
  // Non-blocking - continue even if attribution fetch fails
369
334
  }
370
335
  }
336
+ /**
337
+ * Fetch deferred web attribution on first app install.
338
+ * Uses IP-based matching (iOS) or Play Store referrer (Android) to recover
339
+ * attribution data (fbclid, utm_*, etc.) from a prelander web visit.
340
+ * Called automatically during initialize() when a fresh install is detected.
341
+ */
342
+ async fetchDeferredWebAttribution() {
343
+ var _a;
344
+ if (!((_a = this.state.config) === null || _a === void 0 ? void 0 : _a.apiKey)) {
345
+ debugLog('API key not available for deferred attribution fetch');
346
+ return;
347
+ }
348
+ try {
349
+ debugLog('Fetching deferred web attribution via IP matching...');
350
+ const baseUrl = this.state.config.endpoint || 'https://api.datalyr.com';
351
+ const controller = new AbortController();
352
+ const timeout = setTimeout(() => controller.abort(), 10000);
353
+ const response = await fetch(`${baseUrl}/attribution/deferred-lookup`, {
354
+ method: 'POST',
355
+ headers: {
356
+ 'Content-Type': 'application/json',
357
+ 'X-Datalyr-API-Key': this.state.config.apiKey,
358
+ },
359
+ body: JSON.stringify({ platform: Platform.OS }),
360
+ signal: controller.signal,
361
+ });
362
+ clearTimeout(timeout);
363
+ if (!response.ok) {
364
+ debugLog('Deferred attribution lookup failed:', response.status);
365
+ return;
366
+ }
367
+ const result = await response.json();
368
+ if (!result.found || !result.attribution) {
369
+ debugLog('No deferred web attribution found for this IP');
370
+ return;
371
+ }
372
+ const webAttribution = result.attribution;
373
+ debugLog('Deferred web attribution found:', {
374
+ visitor_id: webAttribution.visitor_id,
375
+ has_fbclid: !!webAttribution.fbclid,
376
+ has_gclid: !!webAttribution.gclid,
377
+ utm_source: webAttribution.utm_source,
378
+ });
379
+ // Merge web attribution into current session
380
+ attributionManager.mergeWebAttribution(webAttribution);
381
+ // Track match event for analytics
382
+ await this.track('$web_attribution_matched', {
383
+ web_visitor_id: webAttribution.visitor_id,
384
+ web_user_id: webAttribution.user_id,
385
+ fbclid: webAttribution.fbclid,
386
+ gclid: webAttribution.gclid,
387
+ ttclid: webAttribution.ttclid,
388
+ gbraid: webAttribution.gbraid,
389
+ wbraid: webAttribution.wbraid,
390
+ fbp: webAttribution.fbp,
391
+ fbc: webAttribution.fbc,
392
+ utm_source: webAttribution.utm_source,
393
+ utm_medium: webAttribution.utm_medium,
394
+ utm_campaign: webAttribution.utm_campaign,
395
+ utm_content: webAttribution.utm_content,
396
+ utm_term: webAttribution.utm_term,
397
+ web_timestamp: webAttribution.timestamp,
398
+ match_method: 'ip',
399
+ });
400
+ debugLog('Successfully merged deferred web attribution');
401
+ }
402
+ catch (error) {
403
+ errorLog('Error fetching deferred web attribution:', error);
404
+ // Non-blocking - email-based fallback will catch this on identify()
405
+ }
406
+ }
371
407
  /**
372
408
  * Alias a user (connect anonymous user to known user)
373
409
  */
@@ -407,10 +443,6 @@ export class DatalyrSDK {
407
443
  await Storage.removeItem(STORAGE_KEYS.USER_PROPERTIES);
408
444
  // Generate new session
409
445
  this.state.sessionId = await getOrCreateSessionId();
410
- // Clear user data from platform SDKs
411
- if (metaIntegration.isAvailable()) {
412
- metaIntegration.clearUserData();
413
- }
414
446
  debugLog('User data reset completed');
415
447
  }
416
448
  catch (error) {
@@ -556,14 +588,6 @@ export class DatalyrSDK {
556
588
  if (productId)
557
589
  properties.product_id = productId;
558
590
  await this.trackWithSKAdNetwork('purchase', properties);
559
- // Forward to Meta if available
560
- if (metaIntegration.isAvailable()) {
561
- metaIntegration.logPurchase(value, currency, { fb_content_id: productId });
562
- }
563
- // Forward to TikTok if available
564
- if (tiktokIntegration.isAvailable()) {
565
- tiktokIntegration.logPurchase(value, currency, productId, 'product');
566
- }
567
591
  }
568
592
  /**
569
593
  * Track subscription with automatic revenue encoding and platform forwarding
@@ -573,14 +597,6 @@ export class DatalyrSDK {
573
597
  if (plan)
574
598
  properties.plan = plan;
575
599
  await this.trackWithSKAdNetwork('subscribe', properties);
576
- // Forward to Meta if available
577
- if (metaIntegration.isAvailable()) {
578
- metaIntegration.logEvent('Subscribe', value, { subscription_plan: plan });
579
- }
580
- // Forward to TikTok if available
581
- if (tiktokIntegration.isAvailable()) {
582
- tiktokIntegration.logSubscription(value, currency, plan);
583
- }
584
600
  }
585
601
  // MARK: - Standard E-commerce Events
586
602
  /**
@@ -593,18 +609,6 @@ export class DatalyrSDK {
593
609
  if (productName)
594
610
  properties.product_name = productName;
595
611
  await this.trackWithSKAdNetwork('add_to_cart', properties);
596
- // Forward to Meta
597
- if (metaIntegration.isAvailable()) {
598
- metaIntegration.logEvent('AddToCart', value, {
599
- currency,
600
- content_ids: productId ? [productId] : undefined,
601
- content_name: productName,
602
- });
603
- }
604
- // Forward to TikTok
605
- if (tiktokIntegration.isAvailable()) {
606
- tiktokIntegration.logAddToCart(value, currency, productId, 'product');
607
- }
608
612
  }
609
613
  /**
610
614
  * Track view content/product event
@@ -620,19 +624,6 @@ export class DatalyrSDK {
620
624
  if (currency)
621
625
  properties.currency = currency;
622
626
  await this.track('view_content', properties);
623
- // Forward to Meta
624
- if (metaIntegration.isAvailable()) {
625
- metaIntegration.logEvent('ViewContent', value, {
626
- content_ids: contentId ? [contentId] : undefined,
627
- content_name: contentName,
628
- content_type: contentType,
629
- currency,
630
- });
631
- }
632
- // Forward to TikTok
633
- if (tiktokIntegration.isAvailable()) {
634
- tiktokIntegration.logViewContent(contentId, contentName, contentType);
635
- }
636
627
  }
637
628
  /**
638
629
  * Track initiate checkout event
@@ -644,18 +635,6 @@ export class DatalyrSDK {
644
635
  if (productIds)
645
636
  properties.product_ids = productIds;
646
637
  await this.trackWithSKAdNetwork('initiate_checkout', properties);
647
- // Forward to Meta
648
- if (metaIntegration.isAvailable()) {
649
- metaIntegration.logEvent('InitiateCheckout', value, {
650
- currency,
651
- num_items: numItems,
652
- content_ids: productIds,
653
- });
654
- }
655
- // Forward to TikTok
656
- if (tiktokIntegration.isAvailable()) {
657
- tiktokIntegration.logInitiateCheckout(value, currency, numItems);
658
- }
659
638
  }
660
639
  /**
661
640
  * Track complete registration event
@@ -665,14 +644,6 @@ export class DatalyrSDK {
665
644
  if (method)
666
645
  properties.method = method;
667
646
  await this.trackWithSKAdNetwork('complete_registration', properties);
668
- // Forward to Meta
669
- if (metaIntegration.isAvailable()) {
670
- metaIntegration.logEvent('CompleteRegistration', undefined, { registration_method: method });
671
- }
672
- // Forward to TikTok
673
- if (tiktokIntegration.isAvailable()) {
674
- tiktokIntegration.logCompleteRegistration(method);
675
- }
676
647
  }
677
648
  /**
678
649
  * Track search event
@@ -682,17 +653,6 @@ export class DatalyrSDK {
682
653
  if (resultIds)
683
654
  properties.result_ids = resultIds;
684
655
  await this.track('search', properties);
685
- // Forward to Meta
686
- if (metaIntegration.isAvailable()) {
687
- metaIntegration.logEvent('Search', undefined, {
688
- search_string: query,
689
- content_ids: resultIds,
690
- });
691
- }
692
- // Forward to TikTok
693
- if (tiktokIntegration.isAvailable()) {
694
- tiktokIntegration.logSearch(query);
695
- }
696
656
  }
697
657
  /**
698
658
  * Track lead/contact form submission
@@ -704,43 +664,25 @@ export class DatalyrSDK {
704
664
  if (currency)
705
665
  properties.currency = currency;
706
666
  await this.trackWithSKAdNetwork('lead', properties);
707
- // Forward to Meta
708
- if (metaIntegration.isAvailable()) {
709
- metaIntegration.logEvent('Lead', value, { currency });
710
- }
711
- // Forward to TikTok
712
- if (tiktokIntegration.isAvailable()) {
713
- tiktokIntegration.logLead(value, currency);
714
- }
715
667
  }
716
668
  /**
717
669
  * Track add payment info event
718
670
  */
719
671
  async trackAddPaymentInfo(success = true) {
720
672
  await this.track('add_payment_info', { success });
721
- // Forward to Meta
722
- if (metaIntegration.isAvailable()) {
723
- metaIntegration.logEvent('AddPaymentInfo', undefined, { success: success ? 1 : 0 });
724
- }
725
- // Forward to TikTok
726
- if (tiktokIntegration.isAvailable()) {
727
- tiktokIntegration.logAddPaymentInfo(success);
728
- }
729
673
  }
730
674
  // MARK: - Platform Integration Methods
731
675
  /**
732
676
  * Get deferred attribution data from platform SDKs
733
677
  */
734
678
  getDeferredAttributionData() {
735
- return metaIntegration.getDeferredDeepLinkData();
679
+ return null;
736
680
  }
737
681
  /**
738
682
  * Get platform integration status
739
683
  */
740
684
  getPlatformIntegrationStatus() {
741
685
  return {
742
- meta: metaIntegration.isAvailable(),
743
- tiktok: tiktokIntegration.isAvailable(),
744
686
  appleSearchAds: appleSearchAdsIntegration.isAvailable(),
745
687
  playInstallReferrer: playInstallReferrerIntegration.isAvailable(),
746
688
  };
@@ -769,8 +711,6 @@ export class DatalyrSDK {
769
711
  errorLog('SDK not initialized. Call initialize() first.');
770
712
  return;
771
713
  }
772
- metaIntegration.updateTrackingAuthorization(enabled);
773
- tiktokIntegration.updateTrackingAuthorization(enabled);
774
714
  // Refresh cached advertiser info after ATT status change
775
715
  try {
776
716
  this.cachedAdvertiserInfo = await AdvertiserInfoBridge.getAdvertiserInfo();
@@ -881,8 +821,8 @@ export class DatalyrSDK {
881
821
  carrier: deviceInfo.carrier,
882
822
  network_type: getNetworkType(),
883
823
  timestamp: Date.now(),
884
- sdk_version: '1.4.9',
885
- // Advertiser data (IDFA/GAID, ATT status) for Meta CAPI / TikTok Events API
824
+ sdk_version: '1.6.0',
825
+ // Advertiser data (IDFA/GAID, ATT status) for server-side postback
886
826
  ...(advertiserInfo ? {
887
827
  idfa: advertiserInfo.idfa,
888
828
  idfv: advertiserInfo.idfv,
@@ -1142,7 +1082,7 @@ export class Datalyr {
1142
1082
  static updateAutoEventsConfig(config) {
1143
1083
  datalyr.updateAutoEventsConfig(config);
1144
1084
  }
1145
- // Standard e-commerce events (all forward to Meta and TikTok)
1085
+ // Standard e-commerce events
1146
1086
  static async trackAddToCart(value, currency = 'USD', productId, productName) {
1147
1087
  await datalyr.trackAddToCart(value, currency, productId, productName);
1148
1088
  }