Blog

NO COMMITMENT REQUIRED

Ready to

feel heard?

We are here for you. Plan your free intake to get started and discover if Flouria is right for you.

The care path with Flouria feels like a gift to myself.

Flouria client, 44 years old, The Netherlands

NO COMMITMENT REQUIRED

Ready to

feel heard?

We are here for you. Plan your free intake to get started and discover if Flouria is right for you.

The care path with Flouria feels like a gift to myself.

Flouria client, 44 years old, The Netherlands

NO COMMITMENT REQUIRED

Ready to

feel heard?

We are here for you. Plan your free intake to get started and discover if Flouria is right for you.

The care path with Flouria feels like a gift to myself.

Flouria client, 44 years old, The Netherlands

NO COMMITMENT REQUIRED

Ready to

feel heard?

We are here for you. Plan your free intake to get started and discover if Flouria is right for you.

The care path with Flouria feels like a gift to myself.

Flouria client, 44 years old, The Netherlands

(function() { const ATTR_KEY = "flouria_attribution_v1"; const SESSION_KEY = "flouria_session_v1"; const APP_DOMAIN = "app.flouria.health"; // First-touch UTMs — stored in localStorage, never overwritten const utmParams = [ "utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "utm_id" ]; // Click IDs — session-only, stored in sessionStorage, always overwritten with latest const clickIdParams = [ "fbclid", // Meta (Facebook / Instagram) "fbadid", // Meta Ad creative ID "gclid", // Google Ads "ttclid", // TikTok "li_fat_id" // LinkedIn ]; const firstTouchFields = ["first_touch_at", "landing_page", "referrer"]; function getStoredAttribution() { try { return JSON.parse(localStorage.getItem(ATTR_KEY) || "{}"); } catch (e) { return {}; } } function storeAttribution(data) { localStorage.setItem(ATTR_KEY, JSON.stringify(data)); } function getSessionClickIds() { try { return JSON.parse(sessionStorage.getItem(SESSION_KEY) || "{}"); } catch (e) { return {}; } } function storeSessionClickIds(data) { sessionStorage.setItem(SESSION_KEY, JSON.stringify(data)); } function captureAttribution() { const existing = getStoredAttribution(); const existingSession = getSessionClickIds(); const urlParams = new URLSearchParams(window.location.search); // --- Persistent first-touch (localStorage) --- const attribution = { first_touch_at: existing.first_touch_at || new Date().toISOString(), landing_page: existing.landing_page || window.location.pathname, referrer: existing.referrer || document.referrer || null }; utmParams.forEach(param => { const value = urlParams.get(param); if (value) { attribution[param] = existing[param] || value; } else if (existing[param]) { attribution[param] = existing[param]; } }); storeAttribution(attribution); // --- Session-only click IDs (sessionStorage) --- const sessionData = { ...existingSession }; clickIdParams.forEach(param => { const value = urlParams.get(param); if (value) { sessionData[param] = value; // always overwrite with the latest click } }); storeSessionClickIds(sessionData); } function decorateUrl(url) { try { const stored = getStoredAttribution(); const session = getSessionClickIds(); const u = new URL(url); utmParams.forEach(param => { if (stored[param] && !u.searchParams.has(param)) { u.searchParams.set(param, stored[param]); } }); firstTouchFields.forEach(param => { if (stored[param] && !u.searchParams.has(param)) { u.searchParams.set(param, stored[param]); } }); clickIdParams.forEach(param => { if (session[param] && !u.searchParams.has(param)) { u.searchParams.set(param, session[param]); } }); return u.toString(); } catch (e) { return url; } } function decorateLinks() { const links = document.querySelectorAll(`a[href*="${APP_DOMAIN}"]`); links.forEach(link => { if (link.dataset.attributionDecorated) return; const original = link.getAttribute("href"); const decorated = decorateUrl(original); if (decorated !== original) { link.setAttribute("href", decorated); } link.dataset.attributionDecorated = "true"; }); } captureAttribution(); decorateLinks(); const observer = new MutationObserver(() => decorateLinks()); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["href"] }); let currentPath = window.location.pathname; setInterval(() => { if (window.location.pathname !== currentPath) { currentPath = window.location.pathname; decorateLinks(); } }, 500); window.decorateAppUrl = function(url) { return decorateUrl(url); }; })();