@datalyr/web 1.5.0 → 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.
package/README.md CHANGED
@@ -438,7 +438,7 @@ interface Attribution {
438
438
  term?: string | null;
439
439
  content?: string | null;
440
440
  clickId?: string | null;
441
- clickIdType?: string | null; // 'fbclid', 'gclid', etc.
441
+ clickIdType?: string | null; // 'fbclid', 'gclid', 'oppref', etc.
442
442
  referrer?: string | null;
443
443
  referrerHost?: string | null;
444
444
  landingPage?: string | null;
@@ -453,7 +453,7 @@ Captured automatically from URLs:
453
453
  | Type | Parameters |
454
454
  |------|------------|
455
455
  | UTM | `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term` |
456
- | Click IDs | `fbclid`, `gclid`, `ttclid`, `twclid`, `li_fat_id`, `msclkid` |
456
+ | Click IDs | `fbclid`, `gclid`, `ttclid`, `oppref`, `twclid`, `li_fat_id`, `msclkid` |
457
457
  | Referrer | `referrer`, `landing_page` |
458
458
 
459
459
  Attribution supports first-touch (90-day window), last-touch, and journey tracking.
@@ -1 +1 @@
1
- {"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../src/attribution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,gBAAgB,CAAuC;IAC/D,OAAO,CAAC,UAAU,CAA2E;IAE7F,OAAO,CAAC,SAAS,CAgBf;IAEF,OAAO,CAAC,sBAAsB,CAO5B;gBAEU,OAAO,GAAE;QACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB;IAMN;;;OAGG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,kBAAkB,IAAI,WAAW;IA8DjC;;;;;OAKG;IACH,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAwB/C;;;OAGG;IACH,aAAa,IAAI,WAAW,GAAG,IAAI;IASnC;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAQ9C;;;OAGG;IACH,YAAY,IAAI,WAAW,GAAG,IAAI;IASlC;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI;IAqBhE;;OAEG;IACH,UAAU,IAAI,UAAU,EAAE;IAI1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA8CxB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAKlB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;OAEG;IACH,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0EzC;;OAEG;IACH,OAAO,CAAC,eAAe;IA6CvB;;OAEG;IACH,OAAO,CAAC,eAAe;IA2BvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACH,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAKvD;;OAEG;IACH,uBAAuB,IAAI,IAAI;CAYhC"}
1
+ {"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../src/attribution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,gBAAgB,CAAuC;IAC/D,OAAO,CAAC,UAAU,CAA2E;IAE7F,OAAO,CAAC,SAAS,CAgBf;IAEF,OAAO,CAAC,sBAAsB,CAO5B;gBAEU,OAAO,GAAE;QACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB;IAMN;;;OAGG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,kBAAkB,IAAI,WAAW;IA8DjC;;;;;OAKG;IACH,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAwB/C;;;OAGG;IACH,aAAa,IAAI,WAAW,GAAG,IAAI;IASnC;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAQ9C;;;OAGG;IACH,YAAY,IAAI,WAAW,GAAG,IAAI;IASlC;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI;IAqBhE;;OAEG;IACH,UAAU,IAAI,UAAU,EAAE;IAI1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAKlB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;OAEG;IACH,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0EzC;;OAEG;IACH,OAAO,CAAC,eAAe;IA6CvB;;OAEG;IACH,OAAO,CAAC,eAAe;IA2BvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACH,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAKvD;;OAEG;IACH,uBAAuB,IAAI,IAAI;CAYhC"}
@@ -123,7 +123,7 @@ export declare class ContainerManager {
123
123
  /**
124
124
  * Track event to all initialized pixels
125
125
  */
126
- trackToPixels(eventName: string, properties?: any): void;
126
+ trackToPixels(eventName: string, properties?: any, eventId?: string): void;
127
127
  /**
128
128
  * Manually trigger a custom script
129
129
  */
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @datalyr/web v1.5.0
2
+ * @datalyr/web v1.6.0
3
3
  * Datalyr Web SDK - Modern attribution tracking for web applications
4
4
  * (c) 2026 Datalyr Inc.
5
5
  * Released under the MIT License
@@ -1506,10 +1506,13 @@ class AttributionManager {
1506
1506
  // Optionally set the cookie for future use
1507
1507
  cookies.set('_fbp', adCookies._fbp, 90);
1508
1508
  }
1509
- // Generate _fbc if we have fbclid but no _fbc
1509
+ // Generate _fbc if we have fbclid but no _fbc.
1510
+ // Meta's fbc format is `fb.{subdomainIndex}.{creationTime}.{fbclid}` where
1511
+ // creationTime is UNIX time in MILLISECONDS (matches the _fbp generation above
1512
+ // and the real _fbc cookie the Meta Pixel writes). Do NOT use seconds here.
1510
1513
  const fbclid = this.getCurrentFbclid();
1511
1514
  if (fbclid && !adCookies._fbc) {
1512
- const timestamp = Math.floor(Date.now() / 1000);
1515
+ const timestamp = Date.now();
1513
1516
  adCookies._fbc = `fb.1.${timestamp}.${fbclid}`;
1514
1517
  // Optionally set the cookie for future use
1515
1518
  cookies.set('_fbc', adCookies._fbc, 90);
@@ -2674,9 +2677,12 @@ class ContainerManager {
2674
2677
  s = b.getElementsByTagName(e)[0];
2675
2678
  s.parentNode.insertBefore(t, s);
2676
2679
  })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
2677
- // Initialize pixel
2680
+ // Initialize pixel only — do NOT fire PageView here. The SDK's own pageview
2681
+ // tracking (track('pageview')) routes through trackToPixels and fires a single
2682
+ // mapped PageView with a shared eventID. Firing it again here produced TWO
2683
+ // PageViews per load (one un-deduped). Note: if the host app disables pageview
2684
+ // tracking entirely, no PageView is sent — which is the correct outcome.
2678
2685
  window.fbq('init', config.pixel_id);
2679
- window.fbq('track', 'PageView');
2680
2686
  this.log('Meta Pixel initialized:', config.pixel_id);
2681
2687
  }
2682
2688
  catch (error) {
@@ -2758,22 +2764,63 @@ class ContainerManager {
2758
2764
  /**
2759
2765
  * Track event to all initialized pixels
2760
2766
  */
2761
- trackToPixels(eventName, properties = {}) {
2762
- var _a, _b, _c, _e, _f, _g;
2767
+ trackToPixels(eventName, properties = {}, eventId) {
2768
+ var _a, _b, _c, _e, _f, _g, _h, _j;
2769
+ // Datalyr-internal events ($identify, $group, $alias, $auto_identify,
2770
+ // $app_download_click, …) are not conversions — never forward them to ad
2771
+ // pixels. (Previously they fired as noise custom events with the $ stripped.)
2772
+ if (eventName.startsWith('$'))
2773
+ return;
2763
2774
  // Sanitize inputs to prevent XSS
2764
2775
  const sanitizedEventName = this.sanitizeEventName(eventName);
2765
2776
  const sanitizedProperties = this.sanitizeProperties(properties);
2766
2777
  // Track to Meta Pixel
2767
2778
  if (((_b = (_a = this.pixels) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.enabled) && window.fbq) {
2768
2779
  try {
2769
- window.fbq('track', sanitizedEventName, sanitizedProperties);
2780
+ // Map our event name to Meta's standard event vocabulary so the browser
2781
+ // Pixel fires e.g. "Purchase", not "purchase". This MUST match the
2782
+ // platform_standard_event the postback worker sends server-side, or Meta
2783
+ // won't dedupe (dedup = event_name + event_id). These defaults mirror the
2784
+ // server-side auto-detect map; custom rule choices may not line up.
2785
+ const metaEventMap = {
2786
+ page_view: 'PageView', pageview: 'PageView',
2787
+ view_content: 'ViewContent', product_viewed: 'ViewContent', view_item: 'ViewContent',
2788
+ add_to_cart: 'AddToCart', product_added: 'AddToCart',
2789
+ add_to_wishlist: 'AddToWishlist',
2790
+ initiate_checkout: 'InitiateCheckout', begin_checkout: 'InitiateCheckout', checkout_started: 'InitiateCheckout',
2791
+ add_payment_info: 'AddPaymentInfo',
2792
+ purchase: 'Purchase', order_completed: 'Purchase', order_paid: 'Purchase',
2793
+ lead: 'Lead',
2794
+ complete_registration: 'CompleteRegistration', sign_up: 'CompleteRegistration', signup: 'CompleteRegistration',
2795
+ search: 'Search',
2796
+ subscribe: 'Subscribe', subscription_created: 'Subscribe',
2797
+ start_trial: 'StartTrial', trial_started: 'StartTrial',
2798
+ contact: 'Contact',
2799
+ schedule: 'Schedule',
2800
+ };
2801
+ // Source of truth: the workspace's Meta conversion-rule map (from
2802
+ // /container-scripts, keyed by the exact trigger event name) — this is what
2803
+ // the server-side CAPI sends, so it guarantees event_name dedup alignment.
2804
+ // Fall back to the static default map, then the sanitized raw name.
2805
+ const ruleEventMap = (_e = (_c = this.pixels) === null || _c === void 0 ? void 0 : _c.meta) === null || _e === void 0 ? void 0 : _e.event_mappings;
2806
+ const metaEvent = (ruleEventMap === null || ruleEventMap === void 0 ? void 0 : ruleEventMap[eventName])
2807
+ || metaEventMap[String(eventName).toLowerCase()]
2808
+ || sanitizedEventName;
2809
+ // Pass the shared eventID so this Pixel event dedupes against the
2810
+ // server-side CAPI event carrying the same event_id.
2811
+ if (eventId) {
2812
+ window.fbq('track', metaEvent, sanitizedProperties, { eventID: eventId });
2813
+ }
2814
+ else {
2815
+ window.fbq('track', metaEvent, sanitizedProperties);
2816
+ }
2770
2817
  }
2771
2818
  catch (error) {
2772
2819
  this.log('Error tracking Meta Pixel event:', error);
2773
2820
  }
2774
2821
  }
2775
2822
  // Track to Google Tag
2776
- if (((_e = (_c = this.pixels) === null || _c === void 0 ? void 0 : _c.google) === null || _e === void 0 ? void 0 : _e.enabled) && window.gtag) {
2823
+ if (((_g = (_f = this.pixels) === null || _f === void 0 ? void 0 : _f.google) === null || _g === void 0 ? void 0 : _g.enabled) && window.gtag) {
2777
2824
  try {
2778
2825
  window.gtag('event', sanitizedEventName, sanitizedProperties);
2779
2826
  }
@@ -2782,7 +2829,7 @@ class ContainerManager {
2782
2829
  }
2783
2830
  }
2784
2831
  // Track to TikTok Pixel
2785
- if (((_g = (_f = this.pixels) === null || _f === void 0 ? void 0 : _f.tiktok) === null || _g === void 0 ? void 0 : _g.enabled) && window.ttq) {
2832
+ if (((_j = (_h = this.pixels) === null || _h === void 0 ? void 0 : _h.tiktok) === null || _j === void 0 ? void 0 : _j.enabled) && window.ttq) {
2786
2833
  try {
2787
2834
  // Map common events to TikTok names
2788
2835
  const tiktokEventMap = {
@@ -3490,6 +3537,15 @@ class Datalyr {
3490
3537
  this.identify(email, { email });
3491
3538
  });
3492
3539
  }
3540
+ // Stamp attribution signals into the Shopify cart (OPT-IN, default off).
3541
+ // Lets server-side order webhooks recover the browser visitor + Meta click
3542
+ // signals (the postback webhook reads these as note_attributes). Inert unless
3543
+ // enabled; best-effort and never blocks init.
3544
+ if (this.config.shopifyCartAttributes === true) {
3545
+ this.syncShopifyCartAttributes().catch((error) => {
3546
+ this.log('Shopify cart attribute sync failed:', error);
3547
+ });
3548
+ }
3493
3549
  // Track initial page view if enabled (AFTER encryption ready)
3494
3550
  if (this.config.trackPageViews) {
3495
3551
  this.page();
@@ -3531,13 +3587,19 @@ class Datalyr {
3531
3587
  // PRIVACY: Heavy fingerprinting removed - using minimal fingerprinting only
3532
3588
  // Update session activity
3533
3589
  this.session.updateActivity(eventName);
3590
+ // Generate the event_id ONCE here so the same value is used for both the
3591
+ // ingested event (→ CAPI dedup key in the postback worker) and the browser
3592
+ // Meta Pixel co-fire below. Sharing it is what lets Meta dedupe the Pixel
3593
+ // event against the server-side CAPI event (dedup = event_id + event_name).
3594
+ const eventId = generateUUID();
3534
3595
  // Create event payload
3535
- const payload = this.createEventPayload(eventName, properties);
3596
+ const payload = this.createEventPayload(eventName, properties, eventId);
3536
3597
  // Queue event
3537
3598
  this.queue.enqueue(payload);
3538
- // Track to third-party pixels if container is initialized
3599
+ // Track to third-party pixels if container is initialized.
3600
+ // Pass the shared eventId so the Meta Pixel fires with the same { eventID }.
3539
3601
  if (this.container) {
3540
- this.container.trackToPixels(eventName, properties);
3602
+ this.container.trackToPixels(eventName, properties, eventId);
3541
3603
  }
3542
3604
  // Call plugin handlers
3543
3605
  if (this.config.plugins) {
@@ -3928,10 +3990,61 @@ class Datalyr {
3928
3990
  getSuperProperties() {
3929
3991
  return Object.assign({}, this.superProperties);
3930
3992
  }
3993
+ /**
3994
+ * Stamp Datalyr attribution signals into the Shopify cart as cart attributes.
3995
+ * Cart attributes become `order.note_attributes` with the same names, which the
3996
+ * server-side order webhook reads to recover the browser visitor_id + Meta click
3997
+ * signals (_fbc/_fbp/fbclid) — enabling accurate Meta CAPI attribution for orders.
3998
+ *
3999
+ * Opt-in (config.shopifyCartAttributes), best-effort, runs once during init.
4000
+ * Merges via Shopify's /cart/update.js (does not clobber other cart attributes).
4001
+ */
4002
+ syncShopifyCartAttributes() {
4003
+ return __awaiter(this, void 0, void 0, function* () {
4004
+ if (typeof window === "undefined" || typeof document === "undefined")
4005
+ return;
4006
+ const isShopify = !!(window.Shopify ||
4007
+ document.querySelector('meta[name="shopify-checkout-api-token"]') ||
4008
+ window.location.hostname.includes(".myshopify.com"));
4009
+ if (!isShopify)
4010
+ return;
4011
+ const attribution = this.attribution.getAttributionData();
4012
+ const fbclid = attribution.clickIdType === "fbclid" ? attribution.clickId : null;
4013
+ // Cookies are freshest (the real Meta Pixel may have just written them);
4014
+ // fall back to whatever the SDK captured in attribution.
4015
+ const attributes = {};
4016
+ const visitorId = this.identity.getAnonymousId();
4017
+ const fbc = this.cookies.get("_fbc") || attribution._fbc;
4018
+ const fbp = this.cookies.get("_fbp") || attribution._fbp;
4019
+ if (visitorId)
4020
+ attributes._datalyr_visitor_id = visitorId;
4021
+ if (fbc)
4022
+ attributes._datalyr_fbc = String(fbc);
4023
+ if (fbp)
4024
+ attributes._datalyr_fbp = String(fbp);
4025
+ if (fbclid)
4026
+ attributes._datalyr_fbclid = String(fbclid);
4027
+ if (Object.keys(attributes).length === 0)
4028
+ return;
4029
+ try {
4030
+ yield fetch("/cart/update.js", {
4031
+ method: "POST",
4032
+ headers: { "Content-Type": "application/json" },
4033
+ credentials: "same-origin",
4034
+ body: JSON.stringify({ attributes }),
4035
+ });
4036
+ this.log("Shopify cart attributes stamped:", Object.keys(attributes));
4037
+ }
4038
+ catch (error) {
4039
+ // Never let cart sync affect tracking — swallow (e.g. no cart yet / CSP).
4040
+ this.log("Shopify /cart/update.js failed:", error);
4041
+ }
4042
+ });
4043
+ }
3931
4044
  /**
3932
4045
  * Create event payload
3933
4046
  */
3934
- createEventPayload(eventName, properties) {
4047
+ createEventPayload(eventName, properties, eventIdArg) {
3935
4048
  // Sanitize and merge properties
3936
4049
  const sanitizedProperties = sanitizeEventData(properties);
3937
4050
  const eventData = deepMerge({}, this.superProperties, sanitizedProperties);
@@ -3961,7 +4074,9 @@ class Datalyr {
3961
4074
  });
3962
4075
  // Create payload using snake_case only (matches backend API and production script)
3963
4076
  const identityFields = this.identity.getIdentityFields();
3964
- const eventId = generateUUID();
4077
+ // Use the caller-provided event_id (shared with the Meta Pixel co-fire for
4078
+ // dedup); fall back to a fresh UUID for any direct caller that omits it.
4079
+ const eventId = eventIdArg !== null && eventIdArg !== void 0 ? eventIdArg : generateUUID();
3965
4080
  // Ensure we have all required identity fields
3966
4081
  const distinctId = identityFields.distinct_id;
3967
4082
  const anonymousId = identityFields.anonymous_id;
@@ -3985,8 +4100,8 @@ class Datalyr {
3985
4100
  // Resolution metadata
3986
4101
  resolution_method: 'browser_sdk',
3987
4102
  resolution_confidence: 1.0,
3988
- // SDK metadata
3989
- sdk_version: '1.4.1',
4103
+ // SDK metadata (keep in sync with package.json version)
4104
+ sdk_version: '1.6.0',
3990
4105
  sdk_name: 'datalyr-web-sdk'
3991
4106
  };
3992
4107
  return payload;