/*! * FlowPowerUser LCP-Spur — misst LCP, INP (Näherung) und CLS im Browser * echter Besucher und meldet je Seitenaufruf EINEN Datensatz: Kennzahlen * plus Selektor des LCP-Elements. Keine Cookies, keine Besucherdaten. * * Einbau (Webflow: Site Settings → Custom Code → Footer): * * Die Site erkennt sich selbst über data-wf-site am -Element. */ (function () { "use strict"; var siteId = document.documentElement.getAttribute("data-wf-site"); if (!siteId || typeof PerformanceObserver === "undefined" || navigator.webdriver) return; var ziel = ""; try { var skript = document.currentScript; ziel = new URL(skript.src).origin + "/api/tempo/eingang"; } catch { return; } function selektor(el) { if (!el || !el.tagName) return null; var tag = el.tagName.toLowerCase(); if (el.id) return tag + "#" + el.id; var klasse = (el.getAttribute("class") || "").trim().split(/\s+/)[0]; return klasse ? tag + "." + klasse : tag; } var lcp = null; var lcpEl = null; var lcpRes = null; var cls = 0; var inp = 0; try { new PerformanceObserver(function (liste) { var e = liste.getEntries(); var letzter = e[e.length - 1]; if (letzter) { lcp = letzter.startTime; lcpEl = selektor(letzter.element); lcpRes = letzter.url || null; } }).observe({ type: "largest-contentful-paint", buffered: true }); } catch {} // CLS nach Session-Windows (wie web-vitals): grösstes Fenster zählt, // nicht die Summe aller Shifts — sonst wird jede lange Sitzung rot. var fensterWert = 0; var fensterStart = 0; var fensterEnde = 0; try { new PerformanceObserver(function (liste) { liste.getEntries().forEach(function (eintrag) { if (eintrag.hadRecentInput) return; if ( fensterWert > 0 && eintrag.startTime - fensterEnde < 1000 && eintrag.startTime - fensterStart < 5000 ) { fensterWert += eintrag.value; } else { fensterWert = eintrag.value; fensterStart = eintrag.startTime; } fensterEnde = eintrag.startTime; if (fensterWert > cls) cls = fensterWert; }); }).observe({ type: "layout-shift", buffered: true }); } catch {} try { // Näherung an INP: längste Interaktion statt 98. Perzentil. new PerformanceObserver(function (liste) { liste.getEntries().forEach(function (eintrag) { if (eintrag.interactionId && eintrag.duration > inp) inp = eintrag.duration; }); }).observe({ type: "event", buffered: true, durationThreshold: 40 }); } catch {} var geschickt = false; function senden() { if (geschickt || lcp === null) return; geschickt = true; var daten = JSON.stringify({ s: siteId, p: location.pathname, lcp: Math.round(lcp), inp: Math.round(inp), cls: Math.round(cls * 1000) / 1000, el: lcpEl, res: lcpRes, }); // sendBeacon kann false liefern (Queue voll) — dann fetch als Rückfall. var angenommen = false; if (navigator.sendBeacon) { try { angenommen = navigator.sendBeacon(ziel, daten); } catch {} } if (!angenommen) { try { fetch(ziel, { method: "POST", body: daten, keepalive: true, mode: "no-cors" }); } catch {} } } document.addEventListener("visibilitychange", function () { if (document.visibilityState === "hidden") senden(); }); addEventListener("pagehide", senden); })();