import type { Cookies } from '@sveltejs/kit'; import log from 'loglevel'; export type EnsureFbcOptions = { days?: number; // cookie lifetime, default 180 domain?: string; // optional cookie domain sameSite?: 'Lax' | 'Strict' | 'None'; // default Lax secure?: boolean; // default inferred from location.protocol === 'https:' pixelLoaded?: boolean; // if true, skip manual set and let Pixel handle it }; function getParam(name: string): string | undefined { const params = new URLSearchParams(location.search); const v = params.get(name); return v || undefined; } function getCookie(name: string): string | undefined { return document.cookie .split('; ') .find((c) => c.startsWith(name + '=')) ?.split('=')[1]; } function setCookie( name: string, value: string, { days = 180, domain, sameSite = 'Lax', secure }: Pick = {} ) { const d = new Date(); d.setTime(d.getTime() + days * 864e5); const parts = [ `${name}=${encodeURIComponent(value)}`, `expires=${d.toUTCString()}`, 'path=/', `SameSite=${sameSite}` ]; if (domain) parts.push(`domain=${domain}`); const isSecure = secure ?? location.protocol === 'https:'; if (isSecure) parts.push('Secure'); document.cookie = parts.join('; '); } function isValidFbc(value: string | undefined): boolean { if (!value) return false; // Expect "fb.1.." if (!value.startsWith('fb.1.')) return false; const parts = value.split('.'); return parts.length >= 4 && /^\d+$/.test(parts[2]) && parts[3].length > 0; } /** * Ensure _fbc cookie exists when landing URL contains fbclid. * Call after consent. If pixelLoaded is true, it skips manual setting. */ export function ensureFbc(options: EnsureFbcOptions = {}) { try { const { pixelLoaded = false, ...cookieOpts } = options; if (pixelLoaded) throw new Error('Pixel loaded, skipping manual _fbc set'); // Let the Pixel set _fbc if it’s active const fbclid = getParam('fbclid'); if (!fbclid) throw new Error('No fbclid param present'); const existing = getCookie('_fbc'); if (isValidFbc(existing)) throw new Error('_fbc cookie already present and valid'); const ts = Math.floor(Date.now() / 1000); const fbc = `fb.1.${ts}.${fbclid}`; setCookie('_fbc', fbc, cookieOpts); log.debug('[ensureFbc] Set _fbc cookie:', fbc); } catch (e) { log.debug('[ensureFbc]', (e as Error).message); } } /** * Helper to read both _fbp and _fbc for your CAPI payload from browser cookies. */ export function getFbpFbc(): { fbp?: string; fbc?: string } { const fbp = getCookie('_fbp'); const fbc = getCookie('_fbc'); return { fbp, fbc }; } /** * Helper to read both _fbp and _fbc for your CAPI payload from cookies object. */ export function getFbpFbcFromCookies(cookies: Cookies): { fbp?: string; fbc?: string } { const fbp = cookies.get('_fbp') || undefined; const fbc = cookies.get('_fbc') || undefined; return { fbp, fbc }; }