@blotoutio/providers-audiohook-sdk 1.53.0 → 1.54.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/index.cjs.js +156 -1
- package/index.js +156 -1
- package/index.mjs +156 -1
- package/package.json +1 -1
package/index.cjs.js
CHANGED
|
@@ -56,6 +56,40 @@ const init = ({ manifest }) => {
|
|
|
56
56
|
initAudiohook(manifest.variables['pixelId']);
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Known ad-network click ID query parameters and the human-readable provider
|
|
61
|
+
* label each one maps to. Used by the CDN worker to resolve `inSessionTouch`
|
|
62
|
+
* and by the analytics API to classify paid-media touch sessions.
|
|
63
|
+
*
|
|
64
|
+
* Keep this list in sync with `defaultParams` in queryParams.ts when new
|
|
65
|
+
* click ID providers are added.
|
|
66
|
+
*/
|
|
67
|
+
const CLICK_IDS = [
|
|
68
|
+
{ param: 'fbclid', label: 'Facebook' }, // Facebook Ads
|
|
69
|
+
{ param: 'gclid', label: 'Google' }, // Google Ads (click)
|
|
70
|
+
{ param: 'gbraid', label: 'Google' }, // Google Ads (iOS app)
|
|
71
|
+
{ param: 'wbraid', label: 'Google' }, // Google Ads (iOS web)
|
|
72
|
+
{ param: 'msclkid', label: 'Bing' }, // Microsoft Bing Ads
|
|
73
|
+
{ param: 'ttclid', label: 'TikTok' }, // TikTok Ads
|
|
74
|
+
{ param: 'ScCid', label: 'Snapchat' }, // Snapchat Ads
|
|
75
|
+
{ param: 'epik', label: 'Pinterest' }, // Pinterest Ads
|
|
76
|
+
{ param: 'li_fat_id', label: 'LinkedIn' }, // LinkedIn Ads
|
|
77
|
+
{ param: 'twclid', label: 'Twitter' }, // X (Twitter) Ads
|
|
78
|
+
{ param: 'rdt_cid', label: 'Reddit' }, // Reddit Ads
|
|
79
|
+
{ param: 'aleid', label: 'AppLovin' }, // AppLovin
|
|
80
|
+
{ param: 'tabclid', label: 'Taboola' }, // Taboola
|
|
81
|
+
{ param: 'obclid', label: 'Outbrain' }, // Outbrain
|
|
82
|
+
{ param: 'trybe', label: 'Trybe' }, // Trybe
|
|
83
|
+
{ param: '_kx', label: 'Klaviyo' }, // Klaviyo email campaigns
|
|
84
|
+
{ param: 'mc_eid', label: 'Mailchimp' }, // Mailchimp email campaigns
|
|
85
|
+
{ param: 'ttd_id', label: 'The Trade Desk' }, // The Trade Desk programmatic
|
|
86
|
+
{ param: 'evsclid', label: 'EvoSearch' }, // EvoSearch
|
|
87
|
+
{ param: 'li_did', label: 'Live Intent' }, // LiveIntent device-level ad
|
|
88
|
+
{ param: '_raclid', label: 'Rumble' }, // Rumble Ads
|
|
89
|
+
{ param: 'ref_id', label: 'StackAdapt' }, // StackAdapt programmatic
|
|
90
|
+
{ param: 'duel_a', label: 'Duel' }, // Duel referral/advocacy
|
|
91
|
+
];
|
|
92
|
+
|
|
59
93
|
const expand = (str) => str.split(',').flatMap((entry) => {
|
|
60
94
|
if (!entry.includes('-')) {
|
|
61
95
|
return entry;
|
|
@@ -441,6 +475,127 @@ const usStates = new Map([
|
|
|
441
475
|
]);
|
|
442
476
|
new Set([...isoCountries.keys(), ...usStates.keys()]);
|
|
443
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Exact utm_source normalization (lowercase key → canonical name).
|
|
480
|
+
*
|
|
481
|
+
* Use exact match when the key is short, generic, or must not accidentally
|
|
482
|
+
* absorb variant spellings (e.g. "impact" must not match "impact_radius").
|
|
483
|
+
*
|
|
484
|
+
* Ordering: Paid (search/social → ad networks → affiliates) →
|
|
485
|
+
* Organic (AI/discovery) → Retention (email → SMS → push → post-purchase)
|
|
486
|
+
*/
|
|
487
|
+
const UTM_SOURCE_EXACT = {
|
|
488
|
+
// ── Paid – Search & Social ────────────────────────────────────────────────
|
|
489
|
+
google: 'Google',
|
|
490
|
+
adwords: 'Google',
|
|
491
|
+
youtube: 'Google',
|
|
492
|
+
yt: 'Google',
|
|
493
|
+
meta: 'Facebook',
|
|
494
|
+
facebook: 'Facebook',
|
|
495
|
+
instagram: 'Facebook',
|
|
496
|
+
ig: 'Facebook',
|
|
497
|
+
igshopping: 'Facebook',
|
|
498
|
+
threads: 'Facebook',
|
|
499
|
+
twitter: 'Twitter',
|
|
500
|
+
snapchat: 'Snapchat',
|
|
501
|
+
pinterest: 'Pinterest',
|
|
502
|
+
bing: 'Bing',
|
|
503
|
+
microsoft: 'Bing',
|
|
504
|
+
tiktok: 'TikTok',
|
|
505
|
+
// ── Paid – Ad Networks ───────────────────────────────────────────────────
|
|
506
|
+
rtbhouse: 'RTB House',
|
|
507
|
+
applovin: 'AppLovin',
|
|
508
|
+
ttd: 'The Trade Desk',
|
|
509
|
+
amazondsp: 'Amazon DSP',
|
|
510
|
+
axon: 'Axon',
|
|
511
|
+
duel: 'Duel',
|
|
512
|
+
// ── Paid – Affiliates ────────────────────────────────────────────────────
|
|
513
|
+
awin: 'Awin',
|
|
514
|
+
'affiliate-cj': 'CJ Affiliate',
|
|
515
|
+
impact: 'Impact',
|
|
516
|
+
rakuten: 'Rakuten',
|
|
517
|
+
superfiliate: 'Superfiliate',
|
|
518
|
+
// ── Organic – AI & Discovery ─────────────────────────────────────────────
|
|
519
|
+
perplexity: 'Perplexity',
|
|
520
|
+
chatgpt: 'ChatGPT',
|
|
521
|
+
'chatgpt.com': 'ChatGPT',
|
|
522
|
+
openai: 'ChatGPT',
|
|
523
|
+
'copilot.com': 'Microsoft Copilot',
|
|
524
|
+
copilot: 'Microsoft Copilot',
|
|
525
|
+
applenews: 'Apple News',
|
|
526
|
+
whatsapp: 'WhatsApp',
|
|
527
|
+
podcast: 'Podcast',
|
|
528
|
+
// ── Retention – Email ────────────────────────────────────────────────────
|
|
529
|
+
mailchimp: 'Mailchimp',
|
|
530
|
+
omnisend: 'Omnisend',
|
|
531
|
+
iterable: 'Iterable',
|
|
532
|
+
listrak: 'Listrak',
|
|
533
|
+
sailthru: 'Sailthru',
|
|
534
|
+
// ── Retention – Push ─────────────────────────────────────────────────────
|
|
535
|
+
pushowl: 'PushOwl',
|
|
536
|
+
// ── Retention – Post-purchase / Payment ──────────────────────────────────
|
|
537
|
+
narvar: 'Narvar',
|
|
538
|
+
shop_app: 'Shop App',
|
|
539
|
+
salesforce: 'Salesforce',
|
|
540
|
+
yotpo: 'Yotpo',
|
|
541
|
+
};
|
|
542
|
+
/**
|
|
543
|
+
* Partial utm_source normalization (startsWith prefix check, lowercase).
|
|
544
|
+
*
|
|
545
|
+
* Checked after exact match so short exact keys (e.g. "ig", "yt") win first.
|
|
546
|
+
*/
|
|
547
|
+
const UTM_SOURCE_PARTIAL = [
|
|
548
|
+
// ── Paid – Social ─────────────────────────────────────────────────────────
|
|
549
|
+
{ prefix: 'tiktok', name: 'TikTok' },
|
|
550
|
+
// ── Paid – Ad Networks ───────────────────────────────────────────────────
|
|
551
|
+
{ prefix: 'criteo', name: 'Criteo' },
|
|
552
|
+
// ── Retention – Email ────────────────────────────────────────────────────
|
|
553
|
+
{ prefix: 'klaviyo', name: 'Klaviyo' },
|
|
554
|
+
// ── Retention – SMS ──────────────────────────────────────────────────────
|
|
555
|
+
{ prefix: 'attentive', name: 'Attentive' },
|
|
556
|
+
{ prefix: 'postscript', name: 'Postscript' },
|
|
557
|
+
// ── Retention – Post-purchase / Payment ──────────────────────────────────
|
|
558
|
+
{ prefix: 'afterpay', name: 'Afterpay' },
|
|
559
|
+
{ prefix: 'klarna', name: 'Klarna' },
|
|
560
|
+
];
|
|
561
|
+
const ORGANIC_SEARCH_ENGINES = [
|
|
562
|
+
{ match: 'google', name: 'Google' },
|
|
563
|
+
{ match: 'bing', name: 'Bing' },
|
|
564
|
+
{ match: 'yahoo', name: 'Yahoo' },
|
|
565
|
+
{ match: 'duckduckgo', name: 'DuckDuckGo' },
|
|
566
|
+
{ match: 'baidu', name: 'Baidu' },
|
|
567
|
+
{ match: 'yandex', name: 'Yandex' },
|
|
568
|
+
{ match: 'brave', name: 'Brave' },
|
|
569
|
+
];
|
|
570
|
+
const KNOWN_REFERRAL_PLATFORMS = [
|
|
571
|
+
{ match: 'facebook', name: 'Facebook' },
|
|
572
|
+
{ match: 'instagram', name: 'Facebook' },
|
|
573
|
+
{ match: 'twitter', name: 'Twitter' },
|
|
574
|
+
{ match: 'x.com', name: 'Twitter' },
|
|
575
|
+
{ match: 'tiktok', name: 'TikTok' },
|
|
576
|
+
{ match: 'pinterest', name: 'Pinterest' },
|
|
577
|
+
{ match: 'linkedin', name: 'LinkedIn' },
|
|
578
|
+
{ match: 'youtube', name: 'YouTube' },
|
|
579
|
+
{ match: 'chatgpt', name: 'ChatGPT' },
|
|
580
|
+
{ match: 'claude', name: 'Claude' },
|
|
581
|
+
{ match: 'perplexity', name: 'Perplexity' },
|
|
582
|
+
{ match: 'shop.app', name: 'Shop App' },
|
|
583
|
+
{ match: 'amazon', name: 'Amazon' },
|
|
584
|
+
{ match: 'attentive', name: 'Attentive' },
|
|
585
|
+
];
|
|
586
|
+
const OFFLINE_TOUCH = 'Blotout_Offline';
|
|
587
|
+
new Set([
|
|
588
|
+
...CLICK_IDS.map((c) => c.label),
|
|
589
|
+
...Object.values(UTM_SOURCE_EXACT),
|
|
590
|
+
...UTM_SOURCE_PARTIAL.map((e) => e.name),
|
|
591
|
+
...ORGANIC_SEARCH_ENGINES.map((e) => `Organic Search - ${e.name}`),
|
|
592
|
+
...KNOWN_REFERRAL_PLATFORMS.map((e) => `Referral - ${e.name}`),
|
|
593
|
+
'Referral - Other',
|
|
594
|
+
'Direct Traffic',
|
|
595
|
+
'Other',
|
|
596
|
+
OFFLINE_TOUCH,
|
|
597
|
+
]);
|
|
598
|
+
|
|
444
599
|
const prepareData = (data) => {
|
|
445
600
|
const payload = {};
|
|
446
601
|
if (data['value'] || data['value'] === 0) {
|
|
@@ -486,7 +641,7 @@ const prepareData = (data) => {
|
|
|
486
641
|
};
|
|
487
642
|
const tag = ({ data, eventName, manifestVariables, eventId }) => {
|
|
488
643
|
const payload = {
|
|
489
|
-
sdkVersion: "1.
|
|
644
|
+
sdkVersion: "1.54.0" ,
|
|
490
645
|
};
|
|
491
646
|
const windowWithAH = window;
|
|
492
647
|
if (windowWithAH.ahTrack &&
|
package/index.js
CHANGED
|
@@ -57,6 +57,40 @@ var ProvidersAudiohookSdk = (function () {
|
|
|
57
57
|
initAudiohook(manifest.variables['pixelId']);
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Known ad-network click ID query parameters and the human-readable provider
|
|
62
|
+
* label each one maps to. Used by the CDN worker to resolve `inSessionTouch`
|
|
63
|
+
* and by the analytics API to classify paid-media touch sessions.
|
|
64
|
+
*
|
|
65
|
+
* Keep this list in sync with `defaultParams` in queryParams.ts when new
|
|
66
|
+
* click ID providers are added.
|
|
67
|
+
*/
|
|
68
|
+
const CLICK_IDS = [
|
|
69
|
+
{ param: 'fbclid', label: 'Facebook' }, // Facebook Ads
|
|
70
|
+
{ param: 'gclid', label: 'Google' }, // Google Ads (click)
|
|
71
|
+
{ param: 'gbraid', label: 'Google' }, // Google Ads (iOS app)
|
|
72
|
+
{ param: 'wbraid', label: 'Google' }, // Google Ads (iOS web)
|
|
73
|
+
{ param: 'msclkid', label: 'Bing' }, // Microsoft Bing Ads
|
|
74
|
+
{ param: 'ttclid', label: 'TikTok' }, // TikTok Ads
|
|
75
|
+
{ param: 'ScCid', label: 'Snapchat' }, // Snapchat Ads
|
|
76
|
+
{ param: 'epik', label: 'Pinterest' }, // Pinterest Ads
|
|
77
|
+
{ param: 'li_fat_id', label: 'LinkedIn' }, // LinkedIn Ads
|
|
78
|
+
{ param: 'twclid', label: 'Twitter' }, // X (Twitter) Ads
|
|
79
|
+
{ param: 'rdt_cid', label: 'Reddit' }, // Reddit Ads
|
|
80
|
+
{ param: 'aleid', label: 'AppLovin' }, // AppLovin
|
|
81
|
+
{ param: 'tabclid', label: 'Taboola' }, // Taboola
|
|
82
|
+
{ param: 'obclid', label: 'Outbrain' }, // Outbrain
|
|
83
|
+
{ param: 'trybe', label: 'Trybe' }, // Trybe
|
|
84
|
+
{ param: '_kx', label: 'Klaviyo' }, // Klaviyo email campaigns
|
|
85
|
+
{ param: 'mc_eid', label: 'Mailchimp' }, // Mailchimp email campaigns
|
|
86
|
+
{ param: 'ttd_id', label: 'The Trade Desk' }, // The Trade Desk programmatic
|
|
87
|
+
{ param: 'evsclid', label: 'EvoSearch' }, // EvoSearch
|
|
88
|
+
{ param: 'li_did', label: 'Live Intent' }, // LiveIntent device-level ad
|
|
89
|
+
{ param: '_raclid', label: 'Rumble' }, // Rumble Ads
|
|
90
|
+
{ param: 'ref_id', label: 'StackAdapt' }, // StackAdapt programmatic
|
|
91
|
+
{ param: 'duel_a', label: 'Duel' }, // Duel referral/advocacy
|
|
92
|
+
];
|
|
93
|
+
|
|
60
94
|
const expand = (str) => str.split(',').flatMap((entry) => {
|
|
61
95
|
if (!entry.includes('-')) {
|
|
62
96
|
return entry;
|
|
@@ -442,6 +476,127 @@ var ProvidersAudiohookSdk = (function () {
|
|
|
442
476
|
]);
|
|
443
477
|
new Set([...isoCountries.keys(), ...usStates.keys()]);
|
|
444
478
|
|
|
479
|
+
/**
|
|
480
|
+
* Exact utm_source normalization (lowercase key → canonical name).
|
|
481
|
+
*
|
|
482
|
+
* Use exact match when the key is short, generic, or must not accidentally
|
|
483
|
+
* absorb variant spellings (e.g. "impact" must not match "impact_radius").
|
|
484
|
+
*
|
|
485
|
+
* Ordering: Paid (search/social → ad networks → affiliates) →
|
|
486
|
+
* Organic (AI/discovery) → Retention (email → SMS → push → post-purchase)
|
|
487
|
+
*/
|
|
488
|
+
const UTM_SOURCE_EXACT = {
|
|
489
|
+
// ── Paid – Search & Social ────────────────────────────────────────────────
|
|
490
|
+
google: 'Google',
|
|
491
|
+
adwords: 'Google',
|
|
492
|
+
youtube: 'Google',
|
|
493
|
+
yt: 'Google',
|
|
494
|
+
meta: 'Facebook',
|
|
495
|
+
facebook: 'Facebook',
|
|
496
|
+
instagram: 'Facebook',
|
|
497
|
+
ig: 'Facebook',
|
|
498
|
+
igshopping: 'Facebook',
|
|
499
|
+
threads: 'Facebook',
|
|
500
|
+
twitter: 'Twitter',
|
|
501
|
+
snapchat: 'Snapchat',
|
|
502
|
+
pinterest: 'Pinterest',
|
|
503
|
+
bing: 'Bing',
|
|
504
|
+
microsoft: 'Bing',
|
|
505
|
+
tiktok: 'TikTok',
|
|
506
|
+
// ── Paid – Ad Networks ───────────────────────────────────────────────────
|
|
507
|
+
rtbhouse: 'RTB House',
|
|
508
|
+
applovin: 'AppLovin',
|
|
509
|
+
ttd: 'The Trade Desk',
|
|
510
|
+
amazondsp: 'Amazon DSP',
|
|
511
|
+
axon: 'Axon',
|
|
512
|
+
duel: 'Duel',
|
|
513
|
+
// ── Paid – Affiliates ────────────────────────────────────────────────────
|
|
514
|
+
awin: 'Awin',
|
|
515
|
+
'affiliate-cj': 'CJ Affiliate',
|
|
516
|
+
impact: 'Impact',
|
|
517
|
+
rakuten: 'Rakuten',
|
|
518
|
+
superfiliate: 'Superfiliate',
|
|
519
|
+
// ── Organic – AI & Discovery ─────────────────────────────────────────────
|
|
520
|
+
perplexity: 'Perplexity',
|
|
521
|
+
chatgpt: 'ChatGPT',
|
|
522
|
+
'chatgpt.com': 'ChatGPT',
|
|
523
|
+
openai: 'ChatGPT',
|
|
524
|
+
'copilot.com': 'Microsoft Copilot',
|
|
525
|
+
copilot: 'Microsoft Copilot',
|
|
526
|
+
applenews: 'Apple News',
|
|
527
|
+
whatsapp: 'WhatsApp',
|
|
528
|
+
podcast: 'Podcast',
|
|
529
|
+
// ── Retention – Email ────────────────────────────────────────────────────
|
|
530
|
+
mailchimp: 'Mailchimp',
|
|
531
|
+
omnisend: 'Omnisend',
|
|
532
|
+
iterable: 'Iterable',
|
|
533
|
+
listrak: 'Listrak',
|
|
534
|
+
sailthru: 'Sailthru',
|
|
535
|
+
// ── Retention – Push ─────────────────────────────────────────────────────
|
|
536
|
+
pushowl: 'PushOwl',
|
|
537
|
+
// ── Retention – Post-purchase / Payment ──────────────────────────────────
|
|
538
|
+
narvar: 'Narvar',
|
|
539
|
+
shop_app: 'Shop App',
|
|
540
|
+
salesforce: 'Salesforce',
|
|
541
|
+
yotpo: 'Yotpo',
|
|
542
|
+
};
|
|
543
|
+
/**
|
|
544
|
+
* Partial utm_source normalization (startsWith prefix check, lowercase).
|
|
545
|
+
*
|
|
546
|
+
* Checked after exact match so short exact keys (e.g. "ig", "yt") win first.
|
|
547
|
+
*/
|
|
548
|
+
const UTM_SOURCE_PARTIAL = [
|
|
549
|
+
// ── Paid – Social ─────────────────────────────────────────────────────────
|
|
550
|
+
{ prefix: 'tiktok', name: 'TikTok' },
|
|
551
|
+
// ── Paid – Ad Networks ───────────────────────────────────────────────────
|
|
552
|
+
{ prefix: 'criteo', name: 'Criteo' },
|
|
553
|
+
// ── Retention – Email ────────────────────────────────────────────────────
|
|
554
|
+
{ prefix: 'klaviyo', name: 'Klaviyo' },
|
|
555
|
+
// ── Retention – SMS ──────────────────────────────────────────────────────
|
|
556
|
+
{ prefix: 'attentive', name: 'Attentive' },
|
|
557
|
+
{ prefix: 'postscript', name: 'Postscript' },
|
|
558
|
+
// ── Retention – Post-purchase / Payment ──────────────────────────────────
|
|
559
|
+
{ prefix: 'afterpay', name: 'Afterpay' },
|
|
560
|
+
{ prefix: 'klarna', name: 'Klarna' },
|
|
561
|
+
];
|
|
562
|
+
const ORGANIC_SEARCH_ENGINES = [
|
|
563
|
+
{ match: 'google', name: 'Google' },
|
|
564
|
+
{ match: 'bing', name: 'Bing' },
|
|
565
|
+
{ match: 'yahoo', name: 'Yahoo' },
|
|
566
|
+
{ match: 'duckduckgo', name: 'DuckDuckGo' },
|
|
567
|
+
{ match: 'baidu', name: 'Baidu' },
|
|
568
|
+
{ match: 'yandex', name: 'Yandex' },
|
|
569
|
+
{ match: 'brave', name: 'Brave' },
|
|
570
|
+
];
|
|
571
|
+
const KNOWN_REFERRAL_PLATFORMS = [
|
|
572
|
+
{ match: 'facebook', name: 'Facebook' },
|
|
573
|
+
{ match: 'instagram', name: 'Facebook' },
|
|
574
|
+
{ match: 'twitter', name: 'Twitter' },
|
|
575
|
+
{ match: 'x.com', name: 'Twitter' },
|
|
576
|
+
{ match: 'tiktok', name: 'TikTok' },
|
|
577
|
+
{ match: 'pinterest', name: 'Pinterest' },
|
|
578
|
+
{ match: 'linkedin', name: 'LinkedIn' },
|
|
579
|
+
{ match: 'youtube', name: 'YouTube' },
|
|
580
|
+
{ match: 'chatgpt', name: 'ChatGPT' },
|
|
581
|
+
{ match: 'claude', name: 'Claude' },
|
|
582
|
+
{ match: 'perplexity', name: 'Perplexity' },
|
|
583
|
+
{ match: 'shop.app', name: 'Shop App' },
|
|
584
|
+
{ match: 'amazon', name: 'Amazon' },
|
|
585
|
+
{ match: 'attentive', name: 'Attentive' },
|
|
586
|
+
];
|
|
587
|
+
const OFFLINE_TOUCH = 'Blotout_Offline';
|
|
588
|
+
new Set([
|
|
589
|
+
...CLICK_IDS.map((c) => c.label),
|
|
590
|
+
...Object.values(UTM_SOURCE_EXACT),
|
|
591
|
+
...UTM_SOURCE_PARTIAL.map((e) => e.name),
|
|
592
|
+
...ORGANIC_SEARCH_ENGINES.map((e) => `Organic Search - ${e.name}`),
|
|
593
|
+
...KNOWN_REFERRAL_PLATFORMS.map((e) => `Referral - ${e.name}`),
|
|
594
|
+
'Referral - Other',
|
|
595
|
+
'Direct Traffic',
|
|
596
|
+
'Other',
|
|
597
|
+
OFFLINE_TOUCH,
|
|
598
|
+
]);
|
|
599
|
+
|
|
445
600
|
const prepareData = (data) => {
|
|
446
601
|
const payload = {};
|
|
447
602
|
if (data['value'] || data['value'] === 0) {
|
|
@@ -487,7 +642,7 @@ var ProvidersAudiohookSdk = (function () {
|
|
|
487
642
|
};
|
|
488
643
|
const tag = ({ data, eventName, manifestVariables, eventId }) => {
|
|
489
644
|
const payload = {
|
|
490
|
-
sdkVersion: "1.
|
|
645
|
+
sdkVersion: "1.54.0" ,
|
|
491
646
|
};
|
|
492
647
|
const windowWithAH = window;
|
|
493
648
|
if (windowWithAH.ahTrack &&
|
package/index.mjs
CHANGED
|
@@ -54,6 +54,40 @@ const init = ({ manifest }) => {
|
|
|
54
54
|
initAudiohook(manifest.variables['pixelId']);
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Known ad-network click ID query parameters and the human-readable provider
|
|
59
|
+
* label each one maps to. Used by the CDN worker to resolve `inSessionTouch`
|
|
60
|
+
* and by the analytics API to classify paid-media touch sessions.
|
|
61
|
+
*
|
|
62
|
+
* Keep this list in sync with `defaultParams` in queryParams.ts when new
|
|
63
|
+
* click ID providers are added.
|
|
64
|
+
*/
|
|
65
|
+
const CLICK_IDS = [
|
|
66
|
+
{ param: 'fbclid', label: 'Facebook' }, // Facebook Ads
|
|
67
|
+
{ param: 'gclid', label: 'Google' }, // Google Ads (click)
|
|
68
|
+
{ param: 'gbraid', label: 'Google' }, // Google Ads (iOS app)
|
|
69
|
+
{ param: 'wbraid', label: 'Google' }, // Google Ads (iOS web)
|
|
70
|
+
{ param: 'msclkid', label: 'Bing' }, // Microsoft Bing Ads
|
|
71
|
+
{ param: 'ttclid', label: 'TikTok' }, // TikTok Ads
|
|
72
|
+
{ param: 'ScCid', label: 'Snapchat' }, // Snapchat Ads
|
|
73
|
+
{ param: 'epik', label: 'Pinterest' }, // Pinterest Ads
|
|
74
|
+
{ param: 'li_fat_id', label: 'LinkedIn' }, // LinkedIn Ads
|
|
75
|
+
{ param: 'twclid', label: 'Twitter' }, // X (Twitter) Ads
|
|
76
|
+
{ param: 'rdt_cid', label: 'Reddit' }, // Reddit Ads
|
|
77
|
+
{ param: 'aleid', label: 'AppLovin' }, // AppLovin
|
|
78
|
+
{ param: 'tabclid', label: 'Taboola' }, // Taboola
|
|
79
|
+
{ param: 'obclid', label: 'Outbrain' }, // Outbrain
|
|
80
|
+
{ param: 'trybe', label: 'Trybe' }, // Trybe
|
|
81
|
+
{ param: '_kx', label: 'Klaviyo' }, // Klaviyo email campaigns
|
|
82
|
+
{ param: 'mc_eid', label: 'Mailchimp' }, // Mailchimp email campaigns
|
|
83
|
+
{ param: 'ttd_id', label: 'The Trade Desk' }, // The Trade Desk programmatic
|
|
84
|
+
{ param: 'evsclid', label: 'EvoSearch' }, // EvoSearch
|
|
85
|
+
{ param: 'li_did', label: 'Live Intent' }, // LiveIntent device-level ad
|
|
86
|
+
{ param: '_raclid', label: 'Rumble' }, // Rumble Ads
|
|
87
|
+
{ param: 'ref_id', label: 'StackAdapt' }, // StackAdapt programmatic
|
|
88
|
+
{ param: 'duel_a', label: 'Duel' }, // Duel referral/advocacy
|
|
89
|
+
];
|
|
90
|
+
|
|
57
91
|
const expand = (str) => str.split(',').flatMap((entry) => {
|
|
58
92
|
if (!entry.includes('-')) {
|
|
59
93
|
return entry;
|
|
@@ -439,6 +473,127 @@ const usStates = new Map([
|
|
|
439
473
|
]);
|
|
440
474
|
new Set([...isoCountries.keys(), ...usStates.keys()]);
|
|
441
475
|
|
|
476
|
+
/**
|
|
477
|
+
* Exact utm_source normalization (lowercase key → canonical name).
|
|
478
|
+
*
|
|
479
|
+
* Use exact match when the key is short, generic, or must not accidentally
|
|
480
|
+
* absorb variant spellings (e.g. "impact" must not match "impact_radius").
|
|
481
|
+
*
|
|
482
|
+
* Ordering: Paid (search/social → ad networks → affiliates) →
|
|
483
|
+
* Organic (AI/discovery) → Retention (email → SMS → push → post-purchase)
|
|
484
|
+
*/
|
|
485
|
+
const UTM_SOURCE_EXACT = {
|
|
486
|
+
// ── Paid – Search & Social ────────────────────────────────────────────────
|
|
487
|
+
google: 'Google',
|
|
488
|
+
adwords: 'Google',
|
|
489
|
+
youtube: 'Google',
|
|
490
|
+
yt: 'Google',
|
|
491
|
+
meta: 'Facebook',
|
|
492
|
+
facebook: 'Facebook',
|
|
493
|
+
instagram: 'Facebook',
|
|
494
|
+
ig: 'Facebook',
|
|
495
|
+
igshopping: 'Facebook',
|
|
496
|
+
threads: 'Facebook',
|
|
497
|
+
twitter: 'Twitter',
|
|
498
|
+
snapchat: 'Snapchat',
|
|
499
|
+
pinterest: 'Pinterest',
|
|
500
|
+
bing: 'Bing',
|
|
501
|
+
microsoft: 'Bing',
|
|
502
|
+
tiktok: 'TikTok',
|
|
503
|
+
// ── Paid – Ad Networks ───────────────────────────────────────────────────
|
|
504
|
+
rtbhouse: 'RTB House',
|
|
505
|
+
applovin: 'AppLovin',
|
|
506
|
+
ttd: 'The Trade Desk',
|
|
507
|
+
amazondsp: 'Amazon DSP',
|
|
508
|
+
axon: 'Axon',
|
|
509
|
+
duel: 'Duel',
|
|
510
|
+
// ── Paid – Affiliates ────────────────────────────────────────────────────
|
|
511
|
+
awin: 'Awin',
|
|
512
|
+
'affiliate-cj': 'CJ Affiliate',
|
|
513
|
+
impact: 'Impact',
|
|
514
|
+
rakuten: 'Rakuten',
|
|
515
|
+
superfiliate: 'Superfiliate',
|
|
516
|
+
// ── Organic – AI & Discovery ─────────────────────────────────────────────
|
|
517
|
+
perplexity: 'Perplexity',
|
|
518
|
+
chatgpt: 'ChatGPT',
|
|
519
|
+
'chatgpt.com': 'ChatGPT',
|
|
520
|
+
openai: 'ChatGPT',
|
|
521
|
+
'copilot.com': 'Microsoft Copilot',
|
|
522
|
+
copilot: 'Microsoft Copilot',
|
|
523
|
+
applenews: 'Apple News',
|
|
524
|
+
whatsapp: 'WhatsApp',
|
|
525
|
+
podcast: 'Podcast',
|
|
526
|
+
// ── Retention – Email ────────────────────────────────────────────────────
|
|
527
|
+
mailchimp: 'Mailchimp',
|
|
528
|
+
omnisend: 'Omnisend',
|
|
529
|
+
iterable: 'Iterable',
|
|
530
|
+
listrak: 'Listrak',
|
|
531
|
+
sailthru: 'Sailthru',
|
|
532
|
+
// ── Retention – Push ─────────────────────────────────────────────────────
|
|
533
|
+
pushowl: 'PushOwl',
|
|
534
|
+
// ── Retention – Post-purchase / Payment ──────────────────────────────────
|
|
535
|
+
narvar: 'Narvar',
|
|
536
|
+
shop_app: 'Shop App',
|
|
537
|
+
salesforce: 'Salesforce',
|
|
538
|
+
yotpo: 'Yotpo',
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* Partial utm_source normalization (startsWith prefix check, lowercase).
|
|
542
|
+
*
|
|
543
|
+
* Checked after exact match so short exact keys (e.g. "ig", "yt") win first.
|
|
544
|
+
*/
|
|
545
|
+
const UTM_SOURCE_PARTIAL = [
|
|
546
|
+
// ── Paid – Social ─────────────────────────────────────────────────────────
|
|
547
|
+
{ prefix: 'tiktok', name: 'TikTok' },
|
|
548
|
+
// ── Paid – Ad Networks ───────────────────────────────────────────────────
|
|
549
|
+
{ prefix: 'criteo', name: 'Criteo' },
|
|
550
|
+
// ── Retention – Email ────────────────────────────────────────────────────
|
|
551
|
+
{ prefix: 'klaviyo', name: 'Klaviyo' },
|
|
552
|
+
// ── Retention – SMS ──────────────────────────────────────────────────────
|
|
553
|
+
{ prefix: 'attentive', name: 'Attentive' },
|
|
554
|
+
{ prefix: 'postscript', name: 'Postscript' },
|
|
555
|
+
// ── Retention – Post-purchase / Payment ──────────────────────────────────
|
|
556
|
+
{ prefix: 'afterpay', name: 'Afterpay' },
|
|
557
|
+
{ prefix: 'klarna', name: 'Klarna' },
|
|
558
|
+
];
|
|
559
|
+
const ORGANIC_SEARCH_ENGINES = [
|
|
560
|
+
{ match: 'google', name: 'Google' },
|
|
561
|
+
{ match: 'bing', name: 'Bing' },
|
|
562
|
+
{ match: 'yahoo', name: 'Yahoo' },
|
|
563
|
+
{ match: 'duckduckgo', name: 'DuckDuckGo' },
|
|
564
|
+
{ match: 'baidu', name: 'Baidu' },
|
|
565
|
+
{ match: 'yandex', name: 'Yandex' },
|
|
566
|
+
{ match: 'brave', name: 'Brave' },
|
|
567
|
+
];
|
|
568
|
+
const KNOWN_REFERRAL_PLATFORMS = [
|
|
569
|
+
{ match: 'facebook', name: 'Facebook' },
|
|
570
|
+
{ match: 'instagram', name: 'Facebook' },
|
|
571
|
+
{ match: 'twitter', name: 'Twitter' },
|
|
572
|
+
{ match: 'x.com', name: 'Twitter' },
|
|
573
|
+
{ match: 'tiktok', name: 'TikTok' },
|
|
574
|
+
{ match: 'pinterest', name: 'Pinterest' },
|
|
575
|
+
{ match: 'linkedin', name: 'LinkedIn' },
|
|
576
|
+
{ match: 'youtube', name: 'YouTube' },
|
|
577
|
+
{ match: 'chatgpt', name: 'ChatGPT' },
|
|
578
|
+
{ match: 'claude', name: 'Claude' },
|
|
579
|
+
{ match: 'perplexity', name: 'Perplexity' },
|
|
580
|
+
{ match: 'shop.app', name: 'Shop App' },
|
|
581
|
+
{ match: 'amazon', name: 'Amazon' },
|
|
582
|
+
{ match: 'attentive', name: 'Attentive' },
|
|
583
|
+
];
|
|
584
|
+
const OFFLINE_TOUCH = 'Blotout_Offline';
|
|
585
|
+
new Set([
|
|
586
|
+
...CLICK_IDS.map((c) => c.label),
|
|
587
|
+
...Object.values(UTM_SOURCE_EXACT),
|
|
588
|
+
...UTM_SOURCE_PARTIAL.map((e) => e.name),
|
|
589
|
+
...ORGANIC_SEARCH_ENGINES.map((e) => `Organic Search - ${e.name}`),
|
|
590
|
+
...KNOWN_REFERRAL_PLATFORMS.map((e) => `Referral - ${e.name}`),
|
|
591
|
+
'Referral - Other',
|
|
592
|
+
'Direct Traffic',
|
|
593
|
+
'Other',
|
|
594
|
+
OFFLINE_TOUCH,
|
|
595
|
+
]);
|
|
596
|
+
|
|
442
597
|
const prepareData = (data) => {
|
|
443
598
|
const payload = {};
|
|
444
599
|
if (data['value'] || data['value'] === 0) {
|
|
@@ -484,7 +639,7 @@ const prepareData = (data) => {
|
|
|
484
639
|
};
|
|
485
640
|
const tag = ({ data, eventName, manifestVariables, eventId }) => {
|
|
486
641
|
const payload = {
|
|
487
|
-
sdkVersion: "1.
|
|
642
|
+
sdkVersion: "1.54.0" ,
|
|
488
643
|
};
|
|
489
644
|
const windowWithAH = window;
|
|
490
645
|
if (windowWithAH.ahTrack &&
|