@datalyr/react-native 1.6.1 → 1.6.3

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/README.md CHANGED
@@ -12,13 +12,20 @@ Mobile analytics and attribution SDK for React Native and Expo. Track events, id
12
12
  - [Custom Events](#custom-events)
13
13
  - [Screen Views](#screen-views)
14
14
  - [E-Commerce Events](#e-commerce-events)
15
+ - [Revenue Events](#revenue-events)
15
16
  - [User Identity](#user-identity)
16
17
  - [Anonymous ID](#anonymous-id)
17
18
  - [Identifying Users](#identifying-users)
19
+ - [Alias](#alias)
18
20
  - [User Properties](#user-properties)
21
+ - [Logout](#logout)
22
+ - [Sessions](#sessions)
19
23
  - [Attribution](#attribution)
20
24
  - [Automatic Capture](#automatic-capture)
25
+ - [Manual Attribution](#manual-attribution)
21
26
  - [Web-to-App Attribution](#web-to-app-attribution)
27
+ - [Deferred Attribution](#deferred-attribution)
28
+ - [Customer Journey](#customer-journey)
22
29
  - [Event Queue](#event-queue)
23
30
  - [Auto Events](#auto-events)
24
31
  - [SKAdNetwork](#skadnetwork)
@@ -27,12 +34,16 @@ Mobile analytics and attribution SDK for React Native and Expo. Track events, id
27
34
  - [TikTok](#tiktok)
28
35
  - [Google Ads](#google-ads)
29
36
  - [Apple Search Ads](#apple-search-ads)
37
+ - [Google Play Install Referrer](#google-play-install-referrer)
38
+ - [App Tracking Transparency](#app-tracking-transparency)
39
+ - [Enhanced App Campaigns](#enhanced-app-campaigns)
30
40
  - [Third-Party Integrations](#third-party-integrations)
31
41
  - [Superwall](#superwall)
32
42
  - [RevenueCat](#revenuecat)
33
43
  - [Migrating from AppsFlyer / Adjust](#migrating-from-appsflyer--adjust)
34
44
  - [Expo Support](#expo-support)
35
45
  - [TypeScript](#typescript)
46
+ - [API Reference](#api-reference)
36
47
  - [Troubleshooting](#troubleshooting)
37
48
  - [License](#license)
38
49
 
@@ -125,24 +136,62 @@ Every event includes:
125
136
 
126
137
  ## Configuration
127
138
 
139
+ All fields except `apiKey` are optional.
140
+
128
141
  ```typescript
129
142
  await Datalyr.initialize({
130
143
  // Required
131
- apiKey: string,
144
+ apiKey: string, // API key from dashboard (starts with 'dk_')
145
+
146
+ // Optional: workspace
147
+ workspaceId?: string, // Workspace ID for multi-workspace setups
148
+
149
+ // Debugging
150
+ debug?: boolean, // Console logging (default: false)
151
+
152
+ // Network
153
+ endpoint?: string, // API endpoint URL (default: 'https://api.datalyr.com')
154
+ useServerTracking?: boolean, // Use server-side tracking (default: true)
155
+ maxRetries?: number, // Max retry attempts for failed requests (default: 3)
156
+ retryDelay?: number, // Delay between retries in ms (default: 1000)
157
+ timeout?: number, // Request timeout in ms (default: 15000)
132
158
 
133
159
  // Features
134
- debug?: boolean, // Console logging
135
- enableAutoEvents?: boolean, // Track app lifecycle
136
- enableAttribution?: boolean, // Capture attribution data
160
+ enableAutoEvents?: boolean, // Track app lifecycle automatically (default: true)
161
+ enableAttribution?: boolean, // Capture attribution data (default: true)
162
+ enableWebToAppAttribution?: boolean, // Web-to-app attribution matching (default: true)
137
163
 
138
- // Event Queue
139
- batchSize?: number, // Events per batch (default: 10)
140
- flushInterval?: number, // Send interval ms (default: 30000)
141
- maxQueueSize?: number, // Max queued events (default: 100)
164
+ // Event queue
165
+ batchSize?: number, // Events per batch (default: 10)
166
+ flushInterval?: number, // Auto-flush interval in ms (default: 30000)
167
+ maxQueueSize?: number, // Max queued events (default: 100)
168
+
169
+ // Auto events
170
+ autoEventConfig?: AutoEventConfig, // Fine-grained auto-event settings (see below)
142
171
 
143
172
  // iOS
144
- skadTemplate?: 'ecommerce' | 'gaming' | 'subscription',
173
+ skadTemplate?: 'ecommerce' | 'gaming' | 'subscription', // SKAdNetwork conversion template
174
+ });
175
+ ```
176
+
177
+ ### AutoEventConfig
178
+
179
+ ```typescript
180
+ interface AutoEventConfig {
181
+ trackSessions?: boolean; // Track session_start / session_end
182
+ trackScreenViews?: boolean; // Track screen views automatically
183
+ trackAppUpdates?: boolean; // Track app_update events
184
+ trackPerformance?: boolean; // Track performance metrics
185
+ sessionTimeoutMs?: number; // Session timeout in ms
186
+ }
187
+ ```
188
+
189
+ Update at runtime:
145
190
 
191
+ ```typescript
192
+ Datalyr.updateAutoEventsConfig({
193
+ trackSessions: true,
194
+ sessionTimeoutMs: 1800000, // 30 minutes
146
195
  });
147
196
  ```
148
197
 
@@ -152,8 +201,6 @@ await Datalyr.initialize({
152
201
 
153
202
  ### Custom Events
154
203
 
155
- Track any action in your app:
156
-
157
204
  ```typescript
158
205
  // Simple event
159
206
  await Datalyr.track('signup_started');
@@ -177,8 +224,6 @@ await Datalyr.track('level_completed', {
177
224
 
178
225
  ### Screen Views
179
226
 
180
- Track navigation:
181
-
182
227
  ```typescript
183
228
  await Datalyr.screen('Home');
184
229
 
@@ -221,6 +266,26 @@ await Datalyr.trackLead(100.0, 'USD');
221
266
  await Datalyr.trackAddPaymentInfo(true);
222
267
  ```
223
268
 
269
+ ### Revenue Events
270
+
271
+ Track revenue with automatic SKAdNetwork encoding:
272
+
273
+ ```typescript
274
+ await Datalyr.trackRevenue('in_app_purchase', {
275
+ value: 4.99,
276
+ currency: 'USD',
277
+ product_id: 'gems_500',
278
+ });
279
+ ```
280
+
281
+ ### App Update Tracking
282
+
283
+ Manually track version changes:
284
+
285
+ ```typescript
286
+ await Datalyr.trackAppUpdate('1.0.0', '1.1.0');
287
+ ```
288
+
224
289
  ---
225
290
 
226
291
  ## User Identity
@@ -253,6 +318,18 @@ After `identify()`:
253
318
  - All future events include `user_id`
254
319
  - Historical anonymous events can be linked server-side
255
320
 
321
+ ### Alias
322
+
323
+ Associate a new user ID with a previous one. Use this when a user's identity changes (e.g., after account merge):
324
+
325
+ ```typescript
326
+ // Link new ID to the currently identified user
327
+ await Datalyr.alias('new_user_456');
328
+
329
+ // Or specify the previous ID explicitly
330
+ await Datalyr.alias('new_user_456', 'old_user_123');
331
+ ```
332
+
256
333
  ### User Properties
257
334
 
258
335
  Pass any user attributes:
@@ -286,6 +363,20 @@ This:
286
363
 
287
364
  ---
288
365
 
366
+ ## Sessions
367
+
368
+ ```typescript
369
+ // Get current session data
370
+ const session = Datalyr.getCurrentSession();
371
+
372
+ // Force end the current session
373
+ await Datalyr.endSession();
374
+ ```
375
+
376
+ Sessions are managed automatically when `enableAutoEvents` is enabled. A new session starts on app launch, and the current session ends after 30 minutes of inactivity (configurable via `autoEventConfig.sessionTimeoutMs`).
377
+
378
+ ---
379
+
289
380
  ## Attribution
290
381
 
291
382
  ### Automatic Capture
@@ -304,13 +395,24 @@ Captured parameters:
304
395
  | Click IDs | `fbclid`, `gclid`, `ttclid`, `twclid`, `li_click_id`, `msclkid` |
305
396
  | Campaign | `campaign_id`, `adset_id`, `ad_id` |
306
397
 
398
+ ### Manual Attribution
399
+
400
+ Set attribution programmatically:
401
+
402
+ ```typescript
403
+ await Datalyr.setAttributionData({
404
+ utm_source: 'newsletter',
405
+ utm_campaign: 'spring_sale',
406
+ });
407
+ ```
408
+
307
409
  ### Web-to-App Attribution
308
410
 
309
411
  Automatically recover attribution from a web prelander when users install the app from an ad.
310
412
 
311
413
  **How it works:**
312
- - **Android**: Attribution params are passed through the Play Store `referrer` URL parameter (set by the web SDK's `trackAppDownloadClick()`). The mobile SDK reads these via the Play Install Referrer API deterministic, ~95% accuracy.
313
- - **iOS**: On first install, the SDK calls the Datalyr API to match the device's IP against recent `$app_download_click` web events within 24 hours ~90%+ accuracy for immediate installs.
414
+ - **Android**: Attribution params are passed through the Play Store `referrer` URL parameter (set by the web SDK's `trackAppDownloadClick()`). The mobile SDK reads these via the Play Install Referrer API -- deterministic, ~95% accuracy.
415
+ - **iOS**: On first install, the SDK calls the Datalyr API to match the device's IP against recent `$app_download_click` web events within 24 hours -- ~90%+ accuracy for immediate installs.
314
416
 
315
417
  No additional mobile code is needed. Attribution is recovered automatically during `initialize()` on first install, before the `app_install` event fires.
316
418
 
@@ -321,15 +423,43 @@ After a match, the SDK:
321
423
 
322
424
  **Fallback:** If IP matching misses (e.g., VPN toggle during install), email-based attribution is still recovered when `identify()` is called with the user's email.
323
425
 
324
- ### Manual Attribution
426
+ ### Deferred Attribution
325
427
 
326
- Set attribution programmatically:
428
+ Retrieve deferred attribution data captured from deep links or install referrers:
327
429
 
328
430
  ```typescript
329
- await Datalyr.setAttributionData({
330
- utm_source: 'newsletter',
331
- utm_campaign: 'spring_sale',
332
- });
431
+ const deferred = Datalyr.getDeferredAttributionData();
432
+ if (deferred) {
433
+ console.log(deferred.url); // Deep link URL
434
+ console.log(deferred.source); // Attribution source
435
+ console.log(deferred.fbclid); // Facebook click ID
436
+ console.log(deferred.gclid); // Google click ID
437
+ console.log(deferred.ttclid); // TikTok click ID
438
+ console.log(deferred.utmSource); // UTM source
439
+ console.log(deferred.utmMedium); // UTM medium
440
+ console.log(deferred.utmCampaign); // UTM campaign
441
+ console.log(deferred.utmContent); // UTM content
442
+ console.log(deferred.utmTerm); // UTM term
443
+ console.log(deferred.campaignId); // Campaign ID
444
+ console.log(deferred.adsetId); // Adset ID
445
+ console.log(deferred.adId); // Ad ID
446
+ }
447
+ ```
448
+
449
+ ---
450
+
451
+ ## Customer Journey
452
+
453
+ Access multi-touch attribution journey data via the `datalyr` singleton instance:
454
+
455
+ ```typescript
456
+ import { datalyr } from '@datalyr/react-native';
457
+
458
+ // Summary: first/last touch, touchpoint count
459
+ const summary = datalyr.getJourneySummary();
460
+
461
+ // Full journey: all touchpoints in order
462
+ const journey = datalyr.getJourney();
333
463
  ```
334
464
 
335
465
  ---
@@ -407,7 +537,10 @@ await Datalyr.initialize({
407
537
  skadTemplate: 'ecommerce',
408
538
  });
409
539
 
410
- // E-commerce events update conversion values
540
+ // Track with automatic SKAN conversion value encoding
541
+ await Datalyr.trackWithSKAdNetwork('purchase', { value: 99.99 });
542
+
543
+ // Or use e-commerce helpers (also update SKAN automatically)
411
544
  await Datalyr.trackPurchase(99.99, 'USD');
412
545
  ```
413
546
 
@@ -417,6 +550,15 @@ await Datalyr.trackPurchase(99.99, 'USD');
417
550
  | `gaming` | level_complete, tutorial_complete, purchase, achievement_unlocked |
418
551
  | `subscription` | trial_start, subscribe, upgrade, cancel, signup |
419
552
 
553
+ ### Test Conversion Values
554
+
555
+ Preview the conversion value an event would produce without sending it to Apple:
556
+
557
+ ```typescript
558
+ const value = Datalyr.getConversionValue('purchase', { value: 49.99 });
559
+ // Returns a number (0-63) or null if no template is configured
560
+ ```
561
+
420
562
  ---
421
563
 
422
564
  ## Platform Integrations
@@ -434,7 +576,7 @@ Conversions are sent to Meta via the [Conversions API (CAPI)](https://developers
434
576
  **Setup:**
435
577
  1. Connect your Meta ad account in the Datalyr dashboard (Settings > Connections)
436
578
  2. Select your Meta Pixel
437
- 3. Create postback rules to map events (e.g., `purchase` `Purchase`, `lead` `Lead`)
579
+ 3. Create postback rules to map events (e.g., `purchase` -> `Purchase`, `lead` -> `Lead`)
438
580
 
439
581
  No Facebook SDK needed in your app. No `Info.plist` changes, no `FacebookAppID`.
440
582
 
@@ -449,7 +591,7 @@ Conversions are sent to TikTok via the [Events API](https://business-api.tiktok.
449
591
  **Setup:**
450
592
  1. Connect your TikTok Ads account in the Datalyr dashboard (Settings > Connections)
451
593
  2. Select your TikTok Pixel
452
- 3. Create postback rules to map events (e.g., `purchase` `CompletePayment`, `add_to_cart` `AddToCart`)
594
+ 3. Create postback rules to map events (e.g., `purchase` -> `CompletePayment`, `add_to_cart` -> `AddToCart`)
453
595
 
454
596
  No TikTok SDK needed in your app. No access tokens, no native configuration.
455
597
 
@@ -464,7 +606,7 @@ Conversions are sent to Google via the [Google Ads API](https://developers.googl
464
606
  **Setup:**
465
607
  1. Connect your Google Ads account in the Datalyr dashboard (Settings > Connections)
466
608
  2. Select your conversion actions
467
- 3. Create postback rules to map events (e.g., `purchase` your Google conversion action)
609
+ 3. Create postback rules to map events (e.g., `purchase` -> your Google conversion action)
468
610
 
469
611
  No Google SDK needed in your app beyond the Play Install Referrer (already included for Android).
470
612
 
@@ -494,6 +636,52 @@ Attribution data is automatically included in all events with the `asa_` prefix:
494
636
 
495
637
  No additional configuration needed. The SDK uses Apple's AdServices API.
496
638
 
639
+ ### Google Play Install Referrer
640
+
641
+ Android-only. Captures UTM parameters and click IDs from the Google Play Store install referrer URL. This data is retrieved automatically on first launch via the Play Install Referrer API.
642
+
643
+ **How it works:**
644
+ 1. User clicks an ad or link with UTM parameters
645
+ 2. Google Play Store stores the referrer URL
646
+ 3. On first app launch, the SDK retrieves the referrer
647
+ 4. Attribution data (utm_source, utm_medium, gclid, etc.) is extracted and merged into the session
648
+
649
+ **Access the raw referrer data:**
650
+
651
+ ```typescript
652
+ import { datalyr } from '@datalyr/react-native';
653
+
654
+ const referrer = datalyr.getPlayInstallReferrer();
655
+ if (referrer) {
656
+ // Google Ads click IDs
657
+ console.log(referrer.gclid); // Standard Google Ads click ID
658
+ console.log(referrer.gbraid); // Privacy-safe click ID (iOS App campaigns)
659
+ console.log(referrer.wbraid); // Privacy-safe click ID (Web-to-App campaigns)
660
+
661
+ // UTM parameters
662
+ console.log(referrer.utmSource);
663
+ console.log(referrer.utmMedium);
664
+ console.log(referrer.utmCampaign);
665
+ console.log(referrer.utmTerm);
666
+ console.log(referrer.utmContent);
667
+
668
+ // Timestamps
669
+ console.log(referrer.referrerClickTimestamp); // When the referrer link was clicked (ms)
670
+ console.log(referrer.installBeginTimestamp); // When the install began (ms)
671
+ console.log(referrer.installCompleteTimestamp); // When the install completed (ms)
672
+
673
+ // Raw referrer URL
674
+ console.log(referrer.referrerUrl);
675
+ }
676
+ ```
677
+
678
+ **Requirements:**
679
+ - Android only (returns `null` on iOS)
680
+ - Requires the Google Play Install Referrer Library in `android/app/build.gradle`:
681
+ ```groovy
682
+ implementation 'com.android.installreferrer:installreferrer:2.2'
683
+ ```
684
+
497
685
  ### App Tracking Transparency
498
686
 
499
687
  Update after ATT dialog:
@@ -503,37 +691,219 @@ const { status } = await requestTrackingPermissionsAsync();
503
691
  await Datalyr.updateTrackingAuthorization(status === 'granted');
504
692
  ```
505
693
 
506
- ### Check Status
694
+ ### Integration Status
507
695
 
508
696
  ```typescript
509
697
  const status = Datalyr.getPlatformIntegrationStatus();
510
- // { appleSearchAds: true }
698
+ // { appleSearchAds: boolean, playInstallReferrer: boolean }
511
699
  ```
512
700
 
513
701
  ---
514
702
 
515
- ## Expo Support
703
+ ## Enhanced App Campaigns
704
+
705
+ Run mobile app ads through web campaigns (Meta Sales, TikTok Traffic, Google Ads) that redirect users to the app store through your own domain. This bypasses SKAN restrictions, ATT requirements, and adset limits -- ad platforms treat these as regular web campaigns.
706
+
707
+ ### How It Works
708
+
709
+ 1. User clicks your ad -> lands on a page on your domain with the Datalyr web SDK (`dl.js`)
710
+ 2. SDK captures attribution (fbclid, ttclid, gclid, UTMs, ad cookies like `_fbp`/`_fbc`/`_ttp`)
711
+ 3. User redirects to app store (via button click or auto-redirect)
712
+ 4. User installs app -> mobile SDK matches via Play Store referrer (Android, ~95%) or IP matching (iOS, ~90%+)
713
+ 5. In-app events fire -> conversions sent to Meta/TikTok/Google server-side via postbacks
714
+
715
+ ### Setup
716
+
717
+ **1. Create a tracking link** in the Datalyr dashboard: Track -> Create Link -> App Link. Enter your prelander page URL and app store URLs.
718
+
719
+ **2. Host a page on your domain** with one of these options:
720
+
721
+ #### Option A: Prelander (Recommended)
722
+
723
+ A real landing page with a download button. Better ad platform compliance, higher intent.
724
+
725
+ ```html
726
+ <!DOCTYPE html>
727
+ <html>
728
+ <head>
729
+ <meta charset="utf-8">
730
+ <meta name="viewport" content="width=device-width, initial-scale=1">
731
+ <title>Download Your App</title>
732
+ <script src="https://cdn.datalyr.com/dl.js" data-workspace="YOUR_WORKSPACE_ID"></script>
733
+ </head>
734
+ <body>
735
+ <h1>Download Our App</h1>
736
+ <button id="ios-download">Download for iOS</button>
737
+ <button id="android-download">Download for Android</button>
738
+
739
+ <script>
740
+ document.getElementById('ios-download').addEventListener('click', function() {
741
+ Datalyr.trackAppDownloadClick({
742
+ targetPlatform: 'ios',
743
+ appStoreUrl: 'https://apps.apple.com/app/idXXXXXXXXXX'
744
+ });
745
+ });
746
+ document.getElementById('android-download').addEventListener('click', function() {
747
+ Datalyr.trackAppDownloadClick({
748
+ targetPlatform: 'android',
749
+ appStoreUrl: 'https://play.google.com/store/apps/details?id=com.example.app'
750
+ });
751
+ });
752
+ </script>
753
+ </body>
754
+ </html>
755
+ ```
516
756
 
517
- ```typescript
518
- import { Datalyr } from '@datalyr/react-native/expo';
757
+ #### Option B: Redirect Page
758
+
759
+ Instant redirect -- no visible content, user goes straight to app store.
760
+
761
+ > **Note:** Some ad platforms (particularly Meta) may flag redirect pages with no visible content as low-quality landing pages or cloaking. Use the prelander option if compliance is a concern.
762
+
763
+ ```html
764
+ <!DOCTYPE html>
765
+ <html>
766
+ <head>
767
+ <script src="https://cdn.datalyr.com/dl.js" data-workspace="YOUR_WORKSPACE_ID"></script>
768
+ <script>
769
+ window.addEventListener('DOMContentLoaded', function() {
770
+ var isAndroid = /android/i.test(navigator.userAgent);
771
+ Datalyr.trackAppDownloadClick({
772
+ targetPlatform: isAndroid ? 'android' : 'ios',
773
+ appStoreUrl: isAndroid
774
+ ? 'https://play.google.com/store/apps/details?id=com.example.app'
775
+ : 'https://apps.apple.com/app/idXXXXXXXXXX'
776
+ });
777
+ });
778
+ </script>
779
+ </head>
780
+ <body></body>
781
+ </html>
519
782
  ```
520
783
 
521
- Same API as standard React Native.
784
+ **3. Set up your ad campaign:**
785
+
786
+ - **Meta Ads**: Campaign objective -> Sales, conversion location -> Website, placements -> Mobile only. Paste your page URL as the Website URL. No SKAN, no ATT, no adset limits.
787
+ - **TikTok Ads**: Campaign objective -> Website Conversions, paste your page URL as destination. Select your TikTok Pixel from Datalyr.
788
+ - **Google Ads**: Performance Max or Search campaign. Use your page URL as the landing page.
789
+
790
+ Add UTM parameters to the URL so attribution flows through:
791
+ - Meta: `?utm_source=facebook&utm_medium=cpc&utm_campaign={{campaign.name}}&utm_content={{adset.name}}&utm_term={{ad.name}}`
792
+ - TikTok: `?utm_source=tiktok&utm_medium=cpc&utm_campaign=__CAMPAIGN_NAME__&utm_content=__AID_NAME__&utm_term=__CID_NAME__`
793
+ - Google: `?utm_source=google&utm_medium=cpc&utm_campaign={campaignid}&utm_content={adgroupid}&utm_term={keyword}`
794
+
795
+ ### Important
796
+
797
+ - The page **must load JavaScript**. Server-side redirects (301/302, nginx, Cloudflare Page Rules) will NOT work.
798
+ - Host on your own domain -- do not use `datalyr.com` or shared domains.
799
+ - The redirect page adds ~100-200ms for the SDK to load. Prelander has no latency since the user clicks a button.
522
800
 
523
801
  ---
524
802
 
525
- ## TypeScript
803
+ ## Third-Party Integrations
804
+
805
+ ### Superwall
806
+
807
+ Pass Datalyr attribution data to Superwall to personalize paywalls by ad source, campaign, ad set, and keyword.
526
808
 
527
809
  ```typescript
528
- import {
529
- Datalyr,
530
- DatalyrConfig,
531
- EventData,
532
- UserProperties,
533
- AttributionData,
534
- } from '@datalyr/react-native';
810
+ import { Datalyr } from '@datalyr/react-native';
811
+ import Superwall from '@superwall/react-native-superwall';
812
+
813
+ // After both SDKs are initialized
814
+ Superwall.setUserAttributes(Datalyr.getSuperwallAttributes());
815
+
816
+ // Your placements will now have attribution data available as filters
817
+ Superwall.register({ placement: 'onboarding_paywall' });
818
+ ```
819
+
820
+ Call after `Datalyr.initialize()` completes. If using ATT on iOS, call again after the user responds to the ATT prompt to include the IDFA.
821
+
822
+ **Returned attribute keys:**
823
+
824
+ | Key | Description |
825
+ |-----|-------------|
826
+ | `datalyr_id` | The user's DATALYR visitor ID |
827
+ | `media_source` | Traffic source (e.g., `facebook`, `google`) |
828
+ | `campaign` | Campaign name from the ad |
829
+ | `adgroup` | Ad group or ad set name |
830
+ | `ad` | Individual ad ID |
831
+ | `keyword` | Search keyword that triggered the ad |
832
+ | `network` | Ad network name |
833
+ | `utm_source` | UTM source parameter |
834
+ | `utm_medium` | UTM medium parameter (e.g., `cpc`) |
835
+ | `utm_campaign` | UTM campaign parameter |
836
+ | `utm_term` | UTM term parameter |
837
+ | `utm_content` | UTM content parameter |
838
+ | `lyr` | DATALYR tracking link ID |
839
+ | `fbclid` | Meta click ID from the ad URL |
840
+ | `gclid` | Google click ID from the ad URL |
841
+ | `ttclid` | TikTok click ID from the ad URL |
842
+ | `idfa` | Apple advertising ID (only if ATT authorized) |
843
+ | `gaid` | Google advertising ID (Android) |
844
+ | `att_status` | App Tracking Transparency status (`0`-`3`) |
845
+
846
+ Only non-empty values are included.
847
+
848
+ ### RevenueCat
849
+
850
+ Pass Datalyr attribution data to RevenueCat for revenue attribution and offering targeting.
851
+
852
+ ```typescript
853
+ import { Datalyr } from '@datalyr/react-native';
854
+ import Purchases from 'react-native-purchases';
855
+
856
+ // After both SDKs are configured
857
+ Purchases.setAttributes(Datalyr.getRevenueCatAttributes());
535
858
  ```
536
859
 
860
+ Call after configuring the Purchases SDK and before the first purchase. If using ATT, call again after permission is granted to include IDFA.
861
+
862
+ **Reserved attributes (`$`-prefixed):**
863
+
864
+ | Key | Description |
865
+ |-----|-------------|
866
+ | `$datalyrId` | The user's DATALYR visitor ID |
867
+ | `$mediaSource` | Traffic source (e.g., `facebook`, `google`) |
868
+ | `$campaign` | Campaign name from the ad |
869
+ | `$adGroup` | Ad group or ad set name |
870
+ | `$ad` | Individual ad ID |
871
+ | `$keyword` | Search keyword that triggered the ad |
872
+ | `$idfa` | Apple advertising ID (only if ATT authorized) |
873
+ | `$gpsAdId` | Google advertising ID (Android) |
874
+ | `$attConsentStatus` | ATT consent status (see mapping below) |
875
+
876
+ **ATT status mapping for `$attConsentStatus`:**
877
+
878
+ | ATT Value | String |
879
+ |-----------|--------|
880
+ | 0 | `notDetermined` |
881
+ | 1 | `restricted` |
882
+ | 2 | `denied` |
883
+ | 3 | `authorized` |
884
+
885
+ **Custom attributes:**
886
+
887
+ | Key | Description |
888
+ |-----|-------------|
889
+ | `utm_source` | UTM source parameter |
890
+ | `utm_medium` | UTM medium parameter (e.g., `cpc`) |
891
+ | `utm_campaign` | UTM campaign parameter |
892
+ | `utm_term` | UTM term parameter |
893
+ | `utm_content` | UTM content parameter |
894
+ | `lyr` | DATALYR tracking link ID |
895
+ | `fbclid` | Meta click ID from the ad URL |
896
+ | `gclid` | Google click ID from the ad URL |
897
+ | `ttclid` | TikTok click ID from the ad URL |
898
+ | `wbraid` | Google web-to-app click ID |
899
+ | `gbraid` | Google app click ID |
900
+ | `network` | Ad network |
901
+ | `creative_id` | Creative ID |
902
+
903
+ Only non-empty values are included.
904
+
905
+ > Datalyr also receives Superwall and RevenueCat events via server-side webhooks for analytics. The SDK methods and webhook integration are independent -- you can use one or both.
906
+
537
907
  ---
538
908
 
539
909
  ## Migrating from AppsFlyer / Adjust
@@ -587,40 +957,132 @@ await Datalyr.trackPurchase(99.99, 'USD');
587
957
 
588
958
  ---
589
959
 
590
- ## Third-Party Integrations
960
+ ## Expo Support
591
961
 
592
- ### Superwall
962
+ ```typescript
963
+ import { Datalyr } from '@datalyr/react-native/expo';
964
+ ```
593
965
 
594
- Pass Datalyr attribution data to Superwall to personalize paywalls by ad source, campaign, ad set, and keyword.
966
+ Same API as standard React Native.
595
967
 
596
- ```typescript
597
- import Datalyr from '@datalyr/react-native';
598
- import Superwall from '@superwall/react-native-superwall';
968
+ ---
599
969
 
600
- // After both SDKs are initialized
601
- Superwall.setUserAttributes(Datalyr.getSuperwallAttributes());
970
+ ## TypeScript
602
971
 
603
- // Your placements will now have attribution data available as filters
604
- Superwall.register({ placement: 'onboarding_paywall' });
972
+ ```typescript
973
+ import {
974
+ Datalyr,
975
+ DatalyrConfig,
976
+ EventData,
977
+ UserProperties,
978
+ AttributionData,
979
+ AutoEventConfig,
980
+ DeferredDeepLinkResult,
981
+ } from '@datalyr/react-native';
605
982
  ```
606
983
 
607
- Call after `Datalyr.initialize()` completes. If using ATT on iOS, call again after the user responds to the ATT prompt to include the IDFA.
984
+ ---
608
985
 
609
- ### RevenueCat
986
+ ## API Reference
610
987
 
611
- Pass Datalyr attribution data to RevenueCat for revenue attribution and offering targeting.
988
+ All methods are static on the `Datalyr` class unless noted otherwise.
612
989
 
613
- ```typescript
614
- import Datalyr from '@datalyr/react-native';
615
- import Purchases from 'react-native-purchases';
990
+ ### Initialization
616
991
 
617
- // After both SDKs are configured
618
- Purchases.setAttributes(Datalyr.getRevenueCatAttributes());
619
- ```
992
+ | Method | Description |
993
+ |--------|-------------|
994
+ | `initialize(config: DatalyrConfig)` | Initialize the SDK. Must be called before any other method. |
620
995
 
621
- Call after configuring the Purchases SDK and before the first purchase. If using ATT, call again after permission is granted to include IDFA.
996
+ ### Event Tracking
997
+
998
+ | Method | Description |
999
+ |--------|-------------|
1000
+ | `track(eventName, eventData?)` | Track a custom event |
1001
+ | `screen(screenName, properties?)` | Track a screen view |
1002
+ | `trackWithSKAdNetwork(event, properties?)` | Track event with SKAN conversion value encoding |
1003
+ | `trackPurchase(value, currency?, productId?)` | Track a purchase |
1004
+ | `trackSubscription(value, currency?, plan?)` | Track a subscription |
1005
+ | `trackRevenue(eventName, properties?)` | Track a revenue event |
1006
+ | `trackAddToCart(value, currency?, productId?, productName?)` | Track add-to-cart |
1007
+ | `trackViewContent(contentId?, contentName?, contentType?, value?, currency?)` | Track content view |
1008
+ | `trackInitiateCheckout(value, currency?, numItems?, productIds?)` | Track checkout start |
1009
+ | `trackCompleteRegistration(method?)` | Track registration |
1010
+ | `trackSearch(query, resultIds?)` | Track a search |
1011
+ | `trackLead(value?, currency?)` | Track a lead |
1012
+ | `trackAddPaymentInfo(success?)` | Track payment info added |
1013
+ | `trackAppUpdate(previousVersion, currentVersion)` | Track an app version update |
1014
+
1015
+ ### User Identity
1016
+
1017
+ | Method | Description |
1018
+ |--------|-------------|
1019
+ | `identify(userId, properties?)` | Identify a user |
1020
+ | `alias(newUserId, previousId?)` | Associate a new user ID with a previous one |
1021
+ | `reset()` | Clear user ID and start new session |
1022
+ | `getAnonymousId()` | Get the persistent anonymous device ID |
1023
+
1024
+ ### Sessions
1025
+
1026
+ | Method | Description |
1027
+ |--------|-------------|
1028
+ | `getCurrentSession()` | Get current session data |
1029
+ | `endSession()` | Force end the current session |
1030
+
1031
+ ### Attribution
1032
+
1033
+ | Method | Description |
1034
+ |--------|-------------|
1035
+ | `getAttributionData()` | Get captured attribution data |
1036
+ | `setAttributionData(data)` | Set attribution data manually |
1037
+ | `getDeferredAttributionData()` | Get deferred attribution from deep links / install referrer |
1038
+
1039
+ ### Configuration
1040
+
1041
+ | Method | Description |
1042
+ |--------|-------------|
1043
+ | `updateAutoEventsConfig(config)` | Update auto-event settings at runtime |
1044
+
1045
+ ### Platform Integrations
1046
+
1047
+ | Method | Description |
1048
+ |--------|-------------|
1049
+ | `getAppleSearchAdsAttribution()` | Get Apple Search Ads attribution (iOS) |
1050
+ | `getPlatformIntegrationStatus()` | Check which platform integrations are active |
1051
+ | `updateTrackingAuthorization(enabled)` | Update ATT status after user responds to dialog |
1052
+
1053
+ ### SKAdNetwork
1054
+
1055
+ | Method | Description |
1056
+ |--------|-------------|
1057
+ | `getConversionValue(event, properties?)` | Preview conversion value without sending to Apple |
1058
+
1059
+ ### Third-Party Integrations
1060
+
1061
+ | Method | Description |
1062
+ |--------|-------------|
1063
+ | `getSuperwallAttributes()` | Get attribution formatted for Superwall |
1064
+ | `getRevenueCatAttributes()` | Get attribution formatted for RevenueCat |
1065
+
1066
+ ### Status
1067
+
1068
+ | Method | Description |
1069
+ |--------|-------------|
1070
+ | `getStatus()` | Get SDK status (initialized, queue stats, online) |
1071
+ | `flush()` | Send all queued events immediately |
1072
+
1073
+ ### Instance Methods (via `datalyr` singleton)
1074
+
1075
+ These methods are available on the `datalyr` instance export, not on the static `Datalyr` class:
1076
+
1077
+ ```typescript
1078
+ import { datalyr } from '@datalyr/react-native';
1079
+ ```
622
1080
 
623
- > Datalyr also receives Superwall and RevenueCat events via server-side webhooks for analytics. The SDK methods and webhook integration are independent — you can use one or both.
1081
+ | Method | Description |
1082
+ |--------|-------------|
1083
+ | `getJourneySummary()` | Get journey summary (first/last touch, touchpoint count) |
1084
+ | `getJourney()` | Get full customer journey (all touchpoints) |
1085
+ | `getPlayInstallReferrer()` | Get raw Play Install Referrer data (Android) |
624
1086
 
625
1087
  ---
626
1088
 
@@ -23,7 +23,7 @@ export class DatalyrSDK {
23
23
  workspaceId: '',
24
24
  apiKey: '',
25
25
  debug: false,
26
- endpoint: 'https://api.datalyr.com', // Updated to server-side API
26
+ endpoint: 'https://ingest.datalyr.com/track',
27
27
  useServerTracking: true, // Default to server-side
28
28
  maxRetries: 3,
29
29
  retryDelay: 1000,
@@ -63,7 +63,7 @@ export class DatalyrSDK {
63
63
  // Set up configuration
64
64
  this.state.config = { ...this.state.config, ...config };
65
65
  // Initialize HTTP client with server-side API
66
- this.httpClient = new HttpClient(this.state.config.endpoint || 'https://api.datalyr.com', {
66
+ this.httpClient = new HttpClient(this.state.config.endpoint || 'https://ingest.datalyr.com/track', {
67
67
  maxRetries: this.state.config.maxRetries || 3,
68
68
  retryDelay: this.state.config.retryDelay || 1000,
69
69
  timeout: this.state.config.timeout || 15000,
@@ -347,10 +347,9 @@ export class DatalyrSDK {
347
347
  }
348
348
  try {
349
349
  debugLog('Fetching deferred web attribution via IP matching...');
350
- const baseUrl = this.state.config.endpoint || 'https://api.datalyr.com';
351
350
  const controller = new AbortController();
352
351
  const timeout = setTimeout(() => controller.abort(), 10000);
353
- const response = await fetch(`${baseUrl}/attribution/deferred-lookup`, {
352
+ const response = await fetch('https://api.datalyr.com/attribution/deferred-lookup', {
354
353
  method: 'POST',
355
354
  headers: {
356
355
  'Content-Type': 'application/json',
@@ -5,7 +5,7 @@ export class HttpClient {
5
5
  this.requestCount = 0;
6
6
  // Use server-side API if flag is set (default to true for v1.0.0)
7
7
  this.endpoint = config.useServerTracking !== false
8
- ? 'https://api.datalyr.com'
8
+ ? 'https://ingest.datalyr.com/track'
9
9
  : endpoint;
10
10
  this.config = config;
11
11
  }
@@ -142,6 +142,7 @@ export class HttpClient {
142
142
  transformForServerAPI(payload) {
143
143
  return {
144
144
  event: payload.eventName,
145
+ eventId: payload.eventId,
145
146
  userId: payload.userId || payload.visitorId,
146
147
  anonymousId: payload.anonymousId || payload.visitorId,
147
148
  properties: {
@@ -152,8 +153,8 @@ export class HttpClient {
152
153
  },
153
154
  context: {
154
155
  library: '@datalyr/react-native',
155
- version: '1.5.0',
156
- source: 'mobile_app', // Explicitly set source for mobile
156
+ version: '1.6.2',
157
+ source: 'mobile_app',
157
158
  userProperties: payload.userProperties,
158
159
  },
159
160
  timestamp: payload.timestamp,
package/lib/types.d.ts CHANGED
@@ -42,11 +42,11 @@ export interface DatalyrConfig {
42
42
  /** Enable console logging for debugging. Default: false */
43
43
  debug?: boolean;
44
44
  /**
45
- * API endpoint URL. Default: 'https://api.datalyr.com'
45
+ * API endpoint URL. Default: 'https://ingest.datalyr.com/track'
46
46
  * @deprecated Use `endpoint` instead
47
47
  */
48
48
  apiUrl?: string;
49
- /** API endpoint URL. Default: 'https://api.datalyr.com' */
49
+ /** API endpoint URL. Default: 'https://ingest.datalyr.com/track' */
50
50
  endpoint?: string;
51
51
  /** Use server-side tracking. Default: true */
52
52
  useServerTracking?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalyr/react-native",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "Datalyr SDK for React Native & Expo - Server-side attribution tracking for iOS and Android",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -55,7 +55,7 @@ export class DatalyrSDKExpo {
55
55
  workspaceId: '',
56
56
  apiKey: '',
57
57
  debug: false,
58
- endpoint: 'https://api.datalyr.com',
58
+ endpoint: 'https://ingest.datalyr.com/track',
59
59
  useServerTracking: true,
60
60
  maxRetries: 3,
61
61
  retryDelay: 1000,
@@ -92,7 +92,7 @@ export class DatalyrSDKExpo {
92
92
 
93
93
  this.state.config = { ...this.state.config, ...config };
94
94
 
95
- this.httpClient = new HttpClient(this.state.config.endpoint || 'https://api.datalyr.com', {
95
+ this.httpClient = new HttpClient(this.state.config.endpoint || 'https://ingest.datalyr.com/track', {
96
96
  maxRetries: this.state.config.maxRetries || 3,
97
97
  retryDelay: this.state.config.retryDelay || 1000,
98
98
  timeout: this.state.config.timeout || 15000,
@@ -54,7 +54,7 @@ export class DatalyrSDK {
54
54
  workspaceId: '',
55
55
  apiKey: '',
56
56
  debug: false,
57
- endpoint: 'https://api.datalyr.com', // Updated to server-side API
57
+ endpoint: 'https://ingest.datalyr.com/track',
58
58
  useServerTracking: true, // Default to server-side
59
59
  maxRetries: 3,
60
60
  retryDelay: 1000,
@@ -99,7 +99,7 @@ export class DatalyrSDK {
99
99
  this.state.config = { ...this.state.config, ...config };
100
100
 
101
101
  // Initialize HTTP client with server-side API
102
- this.httpClient = new HttpClient(this.state.config.endpoint || 'https://api.datalyr.com', {
102
+ this.httpClient = new HttpClient(this.state.config.endpoint || 'https://ingest.datalyr.com/track', {
103
103
  maxRetries: this.state.config.maxRetries || 3,
104
104
  retryDelay: this.state.config.retryDelay || 1000,
105
105
  timeout: this.state.config.timeout || 15000,
@@ -425,11 +425,10 @@ export class DatalyrSDK {
425
425
  try {
426
426
  debugLog('Fetching deferred web attribution via IP matching...');
427
427
 
428
- const baseUrl = this.state.config.endpoint || 'https://api.datalyr.com';
429
428
  const controller = new AbortController();
430
429
  const timeout = setTimeout(() => controller.abort(), 10000);
431
430
 
432
- const response = await fetch(`${baseUrl}/attribution/deferred-lookup`, {
431
+ const response = await fetch('https://api.datalyr.com/attribution/deferred-lookup', {
433
432
  method: 'POST',
434
433
  headers: {
435
434
  'Content-Type': 'application/json',
@@ -26,8 +26,8 @@ export class HttpClient {
26
26
 
27
27
  constructor(endpoint: string, config: HttpClientConfig) {
28
28
  // Use server-side API if flag is set (default to true for v1.0.0)
29
- this.endpoint = config.useServerTracking !== false
30
- ? 'https://api.datalyr.com'
29
+ this.endpoint = config.useServerTracking !== false
30
+ ? 'https://ingest.datalyr.com/track'
31
31
  : endpoint;
32
32
  this.config = config;
33
33
  }
@@ -187,6 +187,7 @@ export class HttpClient {
187
187
  private transformForServerAPI(payload: EventPayload): any {
188
188
  return {
189
189
  event: payload.eventName,
190
+ eventId: payload.eventId,
190
191
  userId: payload.userId || payload.visitorId,
191
192
  anonymousId: payload.anonymousId || payload.visitorId,
192
193
  properties: {
@@ -197,8 +198,8 @@ export class HttpClient {
197
198
  },
198
199
  context: {
199
200
  library: '@datalyr/react-native',
200
- version: '1.5.0',
201
- source: 'mobile_app', // Explicitly set source for mobile
201
+ version: '1.6.2',
202
+ source: 'mobile_app',
202
203
  userProperties: payload.userProperties,
203
204
  },
204
205
  timestamp: payload.timestamp,
package/src/types.ts CHANGED
@@ -49,12 +49,12 @@ export interface DatalyrConfig {
49
49
  debug?: boolean;
50
50
 
51
51
  /**
52
- * API endpoint URL. Default: 'https://api.datalyr.com'
52
+ * API endpoint URL. Default: 'https://ingest.datalyr.com/track'
53
53
  * @deprecated Use `endpoint` instead
54
54
  */
55
55
  apiUrl?: string;
56
56
 
57
- /** API endpoint URL. Default: 'https://api.datalyr.com' */
57
+ /** API endpoint URL. Default: 'https://ingest.datalyr.com/track' */
58
58
  endpoint?: string;
59
59
 
60
60
  /** Use server-side tracking. Default: true */