@datalyr/web 1.6.2 → 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/dist/container.d.ts +22 -0
- package/dist/container.d.ts.map +1 -1
- package/dist/datalyr.cjs.js +132 -51
- package/dist/datalyr.cjs.js.map +1 -1
- package/dist/datalyr.esm.js +132 -51
- package/dist/datalyr.esm.js.map +1 -1
- package/dist/datalyr.esm.min.js +1 -1
- package/dist/datalyr.esm.min.js.map +1 -1
- package/dist/datalyr.js +132 -51
- package/dist/datalyr.js.map +1 -1
- package/dist/datalyr.min.js +1 -1
- package/dist/datalyr.min.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/utils.d.ts +14 -0
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/container.d.ts
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
* Container Script Manager
|
|
3
3
|
* Loads and manages third-party tracking scripts and pixels
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* Identity snapshot read at the moment a third-party pixel initializes.
|
|
7
|
+
* Aligns the browser Pixel's advanced matching with what CAPI sends server-side
|
|
8
|
+
* (meta.js shovels all of {user_id, visitor_id, anonymous_id} into the CAPI
|
|
9
|
+
* external_id array) — so any one of those hashes coincides between surfaces.
|
|
10
|
+
*
|
|
11
|
+
* `externalId` should be the SDK's distinct_id (user_id when identified, else
|
|
12
|
+
* anonymous_id). `email` is only populated after identify(); when present, lets
|
|
13
|
+
* the Pixel match on `em` too.
|
|
14
|
+
*/
|
|
15
|
+
export interface PixelIdentity {
|
|
16
|
+
externalId?: string | null;
|
|
17
|
+
email?: string | null;
|
|
18
|
+
}
|
|
5
19
|
export interface ContainerScript {
|
|
6
20
|
id: string;
|
|
7
21
|
name: string;
|
|
@@ -50,10 +64,12 @@ export declare class ContainerManager {
|
|
|
50
64
|
private sandboxedIframes;
|
|
51
65
|
private iframeCleanupTimeouts;
|
|
52
66
|
private messageHandler;
|
|
67
|
+
private getIdentity?;
|
|
53
68
|
constructor(options: {
|
|
54
69
|
workspaceId: string;
|
|
55
70
|
endpoint?: string;
|
|
56
71
|
debug?: boolean;
|
|
72
|
+
getIdentity?: () => PixelIdentity | undefined;
|
|
57
73
|
});
|
|
58
74
|
/**
|
|
59
75
|
* Initialize container and load scripts
|
|
@@ -110,6 +126,12 @@ export declare class ContainerManager {
|
|
|
110
126
|
private initializePixels;
|
|
111
127
|
/**
|
|
112
128
|
* Initialize Meta (Facebook) Pixel
|
|
129
|
+
*
|
|
130
|
+
* Async because we resolve SHA-256 hashes for advanced matching (Meta's
|
|
131
|
+
* `external_id` / `em`) before calling fbq('init'). Aligning the hashes the
|
|
132
|
+
* browser Pixel sends with what CAPI sends (meta.js shovels user_id /
|
|
133
|
+
* visitor_id / anonymous_id into external_id[], and `em` is sha256 of the
|
|
134
|
+
* lowercased email) is the dedup-quality lift the CAPI side can't fix alone.
|
|
113
135
|
*/
|
|
114
136
|
private initializeMetaPixel;
|
|
115
137
|
/**
|
package/dist/container.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
|
package/dist/datalyr.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @datalyr/web v1.6.
|
|
2
|
+
* @datalyr/web v1.6.3
|
|
3
3
|
* Datalyr Web SDK - Modern attribution tracking for web applications
|
|
4
4
|
* (c) 2026 Datalyr Inc.
|
|
5
5
|
* Released under the MIT License
|
|
@@ -586,6 +586,37 @@ const cookies = new CookieStorage();
|
|
|
586
586
|
/**
|
|
587
587
|
* Utility Functions
|
|
588
588
|
*/
|
|
589
|
+
/**
|
|
590
|
+
* SHA-256 hex digest aligned with the worker's CAPI hashing (cloudflare/
|
|
591
|
+
* postback/core/utils.js `sha256()`). Always lowercases + trims the input
|
|
592
|
+
* before hashing — Meta's matching requires byte-for-byte identical hashes
|
|
593
|
+
* on the Pixel side and the CAPI server side, and the worker uniformly
|
|
594
|
+
* normalizes everything it hashes (em, ph, fn, ln, external_id, etc).
|
|
595
|
+
*
|
|
596
|
+
* Pixel-side hashes that don't match CAPI hashes silently fail to dedupe,
|
|
597
|
+
* which is why this helper does the normalization for callers — easy to
|
|
598
|
+
* forget, hard to debug after release. Returns null when Web Crypto isn't
|
|
599
|
+
* available (very old browsers, non-secure contexts) so callers can
|
|
600
|
+
* gracefully skip advanced matching rather than throwing.
|
|
601
|
+
*/
|
|
602
|
+
function sha256Hex(input) {
|
|
603
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
604
|
+
if (typeof crypto === 'undefined' || !crypto.subtle)
|
|
605
|
+
return null;
|
|
606
|
+
if (!input)
|
|
607
|
+
return null;
|
|
608
|
+
try {
|
|
609
|
+
const bytes = new TextEncoder().encode(input.toLowerCase().trim());
|
|
610
|
+
const digest = yield crypto.subtle.digest('SHA-256', bytes);
|
|
611
|
+
return Array.from(new Uint8Array(digest))
|
|
612
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
613
|
+
.join('');
|
|
614
|
+
}
|
|
615
|
+
catch (_a) {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
589
620
|
/**
|
|
590
621
|
* Generate UUID v4
|
|
591
622
|
*/
|
|
@@ -2315,6 +2346,7 @@ class ContainerManager {
|
|
|
2315
2346
|
// Container scripts use the same endpoint as tracking (ingest)
|
|
2316
2347
|
this.endpoint = options.endpoint || 'https://ingest.datalyr.com';
|
|
2317
2348
|
this.debug = options.debug || false;
|
|
2349
|
+
this.getIdentity = options.getIdentity;
|
|
2318
2350
|
// Load session scripts from storage
|
|
2319
2351
|
const sessionScripts = storage.get('dl_session_scripts', []);
|
|
2320
2352
|
this.sessionLoadedScripts = new Set(sessionScripts);
|
|
@@ -2358,9 +2390,11 @@ class ContainerManager {
|
|
|
2358
2390
|
// Store scripts and pixels
|
|
2359
2391
|
this.scripts = data.scripts || [];
|
|
2360
2392
|
this.pixels = data.pixels || null;
|
|
2361
|
-
// Initialize pixels if configured
|
|
2393
|
+
// Initialize pixels if configured. Awaited so advanced-matching hashes
|
|
2394
|
+
// are resolved before the first dl.track() flushes through trackToPixels
|
|
2395
|
+
// (otherwise fbq('init') would lag fbq('track') in fast-path tracks).
|
|
2362
2396
|
if (this.pixels) {
|
|
2363
|
-
this.initializePixels();
|
|
2397
|
+
yield this.initializePixels();
|
|
2364
2398
|
}
|
|
2365
2399
|
// Load scripts based on trigger
|
|
2366
2400
|
this.loadScriptsByTrigger('page_load');
|
|
@@ -2652,57 +2686,92 @@ class ContainerManager {
|
|
|
2652
2686
|
* Initialize third-party pixels (Meta, Google, TikTok)
|
|
2653
2687
|
*/
|
|
2654
2688
|
initializePixels() {
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
this.
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
this.
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
this.
|
|
2669
|
-
|
|
2689
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2690
|
+
var _a, _b, _c;
|
|
2691
|
+
if (!this.pixels)
|
|
2692
|
+
return;
|
|
2693
|
+
// Initialize Meta Pixel
|
|
2694
|
+
if (((_a = this.pixels.meta) === null || _a === void 0 ? void 0 : _a.enabled) && this.pixels.meta.pixel_id) {
|
|
2695
|
+
yield this.initializeMetaPixel(this.pixels.meta);
|
|
2696
|
+
}
|
|
2697
|
+
// Initialize Google Tag
|
|
2698
|
+
if (((_b = this.pixels.google) === null || _b === void 0 ? void 0 : _b.enabled) && this.pixels.google.tag_id) {
|
|
2699
|
+
this.initializeGoogleTag(this.pixels.google);
|
|
2700
|
+
}
|
|
2701
|
+
// Initialize TikTok Pixel
|
|
2702
|
+
if (((_c = this.pixels.tiktok) === null || _c === void 0 ? void 0 : _c.enabled) && this.pixels.tiktok.pixel_id) {
|
|
2703
|
+
this.initializeTikTokPixel(this.pixels.tiktok);
|
|
2704
|
+
}
|
|
2705
|
+
});
|
|
2670
2706
|
}
|
|
2671
2707
|
/**
|
|
2672
2708
|
* Initialize Meta (Facebook) Pixel
|
|
2709
|
+
*
|
|
2710
|
+
* Async because we resolve SHA-256 hashes for advanced matching (Meta's
|
|
2711
|
+
* `external_id` / `em`) before calling fbq('init'). Aligning the hashes the
|
|
2712
|
+
* browser Pixel sends with what CAPI sends (meta.js shovels user_id /
|
|
2713
|
+
* visitor_id / anonymous_id into external_id[], and `em` is sha256 of the
|
|
2714
|
+
* lowercased email) is the dedup-quality lift the CAPI side can't fix alone.
|
|
2673
2715
|
*/
|
|
2674
2716
|
initializeMetaPixel(config) {
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2717
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2718
|
+
var _a;
|
|
2719
|
+
try {
|
|
2720
|
+
// Load Meta Pixel script
|
|
2721
|
+
(function (f, b, e, v, n, t, s) {
|
|
2722
|
+
if (f.fbq)
|
|
2723
|
+
return;
|
|
2724
|
+
n = f.fbq = function () {
|
|
2725
|
+
n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
|
|
2726
|
+
};
|
|
2727
|
+
if (!f._fbq)
|
|
2728
|
+
f._fbq = n;
|
|
2729
|
+
n.push = n;
|
|
2730
|
+
n.loaded = !0;
|
|
2731
|
+
n.version = '2.0';
|
|
2732
|
+
n.queue = [];
|
|
2733
|
+
t = b.createElement(e);
|
|
2734
|
+
t.async = !0;
|
|
2735
|
+
t.src = v;
|
|
2736
|
+
s = b.getElementsByTagName(e)[0];
|
|
2737
|
+
s.parentNode.insertBefore(t, s);
|
|
2738
|
+
})(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
|
|
2739
|
+
// Build advanced-matching object. Skipped silently if Web Crypto isn't
|
|
2740
|
+
// available — Pixel still initializes, just without advanced matching.
|
|
2741
|
+
// Anonymous_id is stable across the session and always present, so we
|
|
2742
|
+
// never need to re-init on identify(): CAPI carries both anonymous_id
|
|
2743
|
+
// AND user_id in its external_id[] array, so either side matching one
|
|
2744
|
+
// hash slot is enough to dedupe.
|
|
2745
|
+
const advancedMatching = {};
|
|
2746
|
+
const identity = (_a = this.getIdentity) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
2747
|
+
if (identity === null || identity === void 0 ? void 0 : identity.externalId) {
|
|
2748
|
+
const hash = yield sha256Hex(String(identity.externalId));
|
|
2749
|
+
if (hash)
|
|
2750
|
+
advancedMatching.external_id = hash;
|
|
2751
|
+
}
|
|
2752
|
+
if (identity === null || identity === void 0 ? void 0 : identity.email) {
|
|
2753
|
+
const hash = yield sha256Hex(String(identity.email).toLowerCase().trim());
|
|
2754
|
+
if (hash)
|
|
2755
|
+
advancedMatching.em = hash;
|
|
2756
|
+
}
|
|
2757
|
+
// Initialize pixel only — do NOT fire PageView here. The SDK's own pageview
|
|
2758
|
+
// tracking (track('pageview')) routes through trackToPixels and fires a single
|
|
2759
|
+
// mapped PageView with a shared eventID. Firing it again here produced TWO
|
|
2760
|
+
// PageViews per load (one un-deduped). Note: if the host app disables pageview
|
|
2761
|
+
// tracking entirely, no PageView is sent — which is the correct outcome.
|
|
2762
|
+
if (Object.keys(advancedMatching).length > 0) {
|
|
2763
|
+
window.fbq('init', config.pixel_id, advancedMatching);
|
|
2764
|
+
this.log('Meta Pixel initialized with advanced matching:', config.pixel_id, Object.keys(advancedMatching));
|
|
2765
|
+
}
|
|
2766
|
+
else {
|
|
2767
|
+
window.fbq('init', config.pixel_id);
|
|
2768
|
+
this.log('Meta Pixel initialized (no advanced matching):', config.pixel_id);
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
catch (error) {
|
|
2772
|
+
this.log('Error initializing Meta Pixel:', error);
|
|
2773
|
+
}
|
|
2774
|
+
});
|
|
2706
2775
|
}
|
|
2707
2776
|
/**
|
|
2708
2777
|
* Initialize Google Tag
|
|
@@ -3522,7 +3591,19 @@ class Datalyr {
|
|
|
3522
3591
|
this.container = new ContainerManager({
|
|
3523
3592
|
workspaceId: this.config.workspaceId,
|
|
3524
3593
|
endpoint: this.config.endpoint,
|
|
3525
|
-
debug: this.config.debug
|
|
3594
|
+
debug: this.config.debug,
|
|
3595
|
+
// Lazy: invoked at the moment a third-party pixel inits, AFTER the
|
|
3596
|
+
// /container-scripts roundtrip resolves — so a pre-init identify()
|
|
3597
|
+
// already updated this.identity / this.userProperties. distinctId
|
|
3598
|
+
// mirrors what CAPI puts in external_id[] (user_id || anonymous_id);
|
|
3599
|
+
// email lets the Pixel match on em with the same hash CAPI sends.
|
|
3600
|
+
getIdentity: () => {
|
|
3601
|
+
var _a, _b;
|
|
3602
|
+
return ({
|
|
3603
|
+
externalId: (_a = this.identity) === null || _a === void 0 ? void 0 : _a.getDistinctId(),
|
|
3604
|
+
email: (_b = this.userProperties) === null || _b === void 0 ? void 0 : _b.email,
|
|
3605
|
+
});
|
|
3606
|
+
}
|
|
3526
3607
|
});
|
|
3527
3608
|
// Initialize container asynchronously
|
|
3528
3609
|
yield this.container.init().catch(error => {
|
|
@@ -4116,7 +4197,7 @@ class Datalyr {
|
|
|
4116
4197
|
resolution_method: 'browser_sdk',
|
|
4117
4198
|
resolution_confidence: 1.0,
|
|
4118
4199
|
// SDK metadata (keep in sync with package.json version)
|
|
4119
|
-
sdk_version: '1.6.
|
|
4200
|
+
sdk_version: '1.6.3',
|
|
4120
4201
|
sdk_name: 'datalyr-web-sdk'
|
|
4121
4202
|
};
|
|
4122
4203
|
return payload;
|