. * * What it does: * 1. When a visitor lands with ad parameters (utm_*, click IDs, campaign/adset/ad IDs), it remembers them * for this visit (sessionStorage, this tab only). * 2. It adds them to links that open the quiz (*.web.app/quiz…) or a Typeform (parasym.typeform.com), * e.g. the "Start assessment" button #short-quiz-button, so the quiz can send them back to the store. * What it never does: * - never changes the address bar or any store link, never sets or reads cookies, never redirects * - never changes a parameter a link already has; if the link already has any utm_*, none of ours are added * - if the visitor came without ad parameters, it changes nothing at all * - it remembers parameters across pages only with statistics/marketing consent (Shopify Customer Privacy API or * Cookiebot); without consent it only decorates links on the page the visitor landed on */ (function () { 'use strict'; var KEY = 'ps_land_v1'; var PASS = /^(utm_(source|medium|campaign|content|term|id)|campaign_id|adset_id|ad_id|fbclid|gclid|gbraid|wbraid|msclkid|ttclid|tblci)$/; function isQuizLink(u) { return (/\.web\.app$/i.test(u.hostname) && /^\/quiz/i.test(u.pathname)) || /^parasym\.typeform\.com$/i.test(u.hostname); } // EU/UK: we only keep parameters across pages (sessionStorage) when the visitor allowed statistics or marketing // (Shopify Customer Privacy API or Cookiebot). Without consent, only links on the current page are decorated. function storageAllowed() { try { var cp = window.Shopify && window.Shopify.customerPrivacy; if (cp && typeof cp.analyticsProcessingAllowed === 'function') { return !!(cp.analyticsProcessingAllowed() || (cp.marketingAllowed && cp.marketingAllowed())); } if (window.Cookiebot && window.Cookiebot.consent) { return !!(window.Cookiebot.consent.statistics || window.Cookiebot.consent.marketing); } } catch (e) {} return false; } var pending = null; function persist() { if (!pending || !storageAllowed()) return; try { sessionStorage.setItem(KEY, JSON.stringify(pending)); pending = null; } catch (e) {} } ['CookiebotOnAccept', 'CookiebotOnConsentReady', 'visitorConsentCollected'].forEach(function (t) { window.addEventListener(t, persist); document.addEventListener(t, persist); }); window.addEventListener('pagehide', persist); var params = null; try { var fresh = {}; new URLSearchParams(location.search).forEach(function (v, k) { if (PASS.test(k) && v) fresh[k] = v.slice(0, 500); }); // our own quiz return (quiz=…) is not a new source; keep what we stored on arrival if (Object.keys(fresh).length && !new URLSearchParams(location.search).has('quiz')) { params = fresh; pending = fresh; persist(); } else { try { params = JSON.parse(sessionStorage.getItem(KEY) || 'null'); } catch (e) {} } } catch (e) { return; } if (!params) return; function decorate(a) { try { if (!a || !a.href || a.getAttribute('data-ps-pass') === '1') return; var u = new URL(a.href, location.href); if (!/^https?:$/.test(u.protocol) || !isQuizLink(u)) return; var linkHasUtm = false; u.searchParams.forEach(function (v, k) { if (/^utm_/.test(k)) linkHasUtm = true; }); var changed = false; Object.keys(params).forEach(function (k) { if (linkHasUtm && /^utm_/.test(k)) return; if (!u.searchParams.has(k)) { u.searchParams.set(k, params[k]); changed = true; } }); if (changed) a.href = u.toString(); a.setAttribute('data-ps-pass', '1'); } catch (e) {} } function decorateAll() { var links = document.querySelectorAll('a[href]'); for (var i = 0; i < links.length; i++) decorate(links[i]); } function onEvent(ev) { var el = ev.target; while (el && el !== document && el.tagName !== 'A') el = el.parentNode; if (el && el.tagName === 'A') decorate(el); } ['pointerdown', 'mousedown', 'touchstart', 'click', 'auxclick', 'keydown'].forEach(function (t) { document.addEventListener(t, onEvent, true); }); if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', decorateAll); else decorateAll(); window.addEventListener('load', decorateAll); })();