Der RUM-Beacon
Die JavaScript-Datei, die fastmon an deine Besucher ausliefert. Was sie beobachtet, wann sie sendet und was sie nie tut.
Der Beacon ist die JavaScript-Datei, die fastmon unter https://fastmon.site/s/{source_hash}.js ausliefert. Das ist alles, mehr braucht es nicht und gibt es auch nicht.
Diese Seite ist die technische Referenz. Für das Einrichten geht's zur Implementierung, für Privacy-Fragen zu Privacy: was wir nicht sammeln.
Ein Bundle, zwei Builds
Es gibt ein einziges Beacon (standard.js). Der Server kompiliert es pro Site in einen von zwei Builds, entschieden durch die Einstellung collect_sessions:
| Build | Wann | Speicher auf dem Gerät |
|---|---|---|
| Stateless | collect_sessions aus | Keiner; der sessionStorage-Schreibvorgang wird komplett herauskompiliert |
| Stateful | collect_sessions an | Nur sessionStorage._fms (die Session-ID) |
fastmon setzt überhaupt keine Cookies, in keinem Build. Per Default wird nichts auf das Gerät geschrieben: nur das Preset Full (oder collect_sessions anzuschalten) schreibt die sessionStorage._fms-Session-ID. Ob dieser Schreibvorgang beim Pageload landet oder auf Consent wartet, entscheidet die Einstellung session_consent.
Du wählst den Build nicht im <script>-Tag; der Server löst ihn aus den Site-Einstellungen auf und liefert den passenden aus. Eine Änderung an einer Einstellung, die das ausgelieferte Bundle betrifft, rollt den Script-Cache automatisch.
Warum das zählt
Der Beacon ist die Grenze zwischen fastmon und deinem Besucher: was er misst, wann er flusht und welche Identifier er erzeugt, passiert alles im Browser. Wir halten diese Oberfläche klein und dokumentieren sie hier vollständig, und die Wire-Form wird serverseitig erzwungen, sodass nachvollziehbar und in jedem Datenschutz-Review verteidigbar bleibt, was der Beacon kann und was nicht, unabhängig vom Script selbst.
Das ausgelieferte Script ist bewusst minifiziert und obfuskiert, nicht um zu verbergen, was es tut (das steht alles auf dieser Seite), sondern damit Content- und Ad-Blocker es nicht per Namensmuster erkennen und still blockieren, was Lücken in deinem Monitoring hinterließe.
Was der Beacon beobachtet
| Quelle | Was erfasst wird |
|---|---|
PerformanceObserver | LCP, INP, CLS, FCP, Paint-Einträge, Long Animation Frames, Layout Shifts. |
Navigation Timing | TTFB, Redirect-Count, Navigation-Typ (navigate, reload, back_forward). |
Resource Timing | Pro Resource: Größe, Dauer, Kategorie. Pro Domain aggregiert. |
error-Event | Typ, Anzahl und Stack-Frame-Hosts immer; Pfad + Zeile/Spalte deiner eigenen First-Party-Script-Frames ebenfalls. Message sowie das Detail von Inline-/Third-Party-Frames nur, wenn collect_error_messages / collect_error_frames an sind, und dort erst nach einem immer aktiven PII-Scrubber, der URLs, E-Mails, IDs und Strings in Anführungszeichen maskiert. |
unhandledrejection | Selbe Form wie error. |
| Page Visibility API | Time-to-Hidden, gesamte sichtbare Zeit. |
fetch / XMLHttpRequest | Aggregierte Fetch/XHR-Werte je Endpunkt: Aufrufzahlen, Dauern, Dauer-Buckets und eine Statusfehler-Verteilung, je Endpunkt templated (Methode + Host + Pfad, ohne Query-Strings). Server-gesteuert pro Site (collect_fetch_xhr, Default aus). |
Server-Timing | Die Server-Timing-Metriken, die dein eigenes Backend meldet (Name und Dauer), per Konstruktion First-Party. |
| Document & Window | Seiten-URL (auf Origin + Pfad bereinigt), Referrer, Viewport-Größenklasse. |
Geo-Daten (das Land) werden im Browser nicht gelesen. Der Edge leitet sie aus der Request-IP ab und reicht einen Ländercode als Header weiter; die IP selbst verlässt den Edge nie. Genauso für die in Buckets eingeteilte Browser-/OS-/Geräte-Familie, die als FM-Browser / FM-Browser-Version / FM-OS / FM-Device weitergereicht wird. Zusätzlich berechnet der Edge einen Einweg-FM-Stitch-Header (HMAC-SHA256(rotierendes-24h-Salt, IP | UA | collector_hash | domain) auf 128 Bit gekürzt), den das Backend für begrenzte Cross-Pageview-Joins nutzt (nur gespeichert, wenn store_stitch an ist). Rechtlicher Rahmen unter Privacy → Der am Edge abgeleitete stitch-Identifier.
Was der Beacon nicht tut
localStorage/IndexedDB/Cache Storagelesen oder schreiben, niemals.- Cookies setzen. fastmon setzt überhaupt keine Cookies, in keiner Konfiguration.
- DOM-Inhalt anfassen (kein Scroll-Replay, kein Session-Replay, keine Formularerfassung). Die einzige Ausnahme ist das Opt-in
pagetype_ruleset, das einen einzelnen Body-Controller-Klassen-Token zur Page-Type-Einordnung liest, sonst nichts. - Mediengeräte, Sensoren oder Geolokation des Besuchers anfragen.
- Einen Identifier auf dem Gerät vergeben, der Pageviews verknüpft, außer
collect_sessionsist an (dann die tab-gebundene Session-ID). Die Per-Pageview-IDpvidgibt es in jeder Konfiguration und stirbt mit dem Pageview.
Lebenszyklus eines Pageviews
Seite lädt
├── Beacon-Script wird geladen (async, gecached, ETag-validiert)
├── Beacon registriert PerformanceObserver und Event-Listener
├── Besucher nutzt die Seite
│ └── Beacon puffert Events im Speicher
└── Flush-Trigger (visibilitychange→hidden, pagehide, Soft-Nav,
Fehler-Update oder Terminate) lösen einen POST an
/c/{collector_hash} aus, mit versioniertem Payload
(Lifecycle markiert jede Emission)Beim Flush versuchen wir zuerst navigator.sendBeacon(), damit der Request auch beim Unload sicher rauskommt. Fehlt das, fallen wir auf fetch mit keepalive: true zurück. Schlägt beides fehl (alte Browser, sehr aggressives Extension-Blocking), greift ein GET-Pixel-Fallback an /c/{collector_hash}.gif?…, der eine sichere Teilmenge der Felder in den Query-String serialisiert. Sensible Inhalte (sid, Referrer, Fehler, die großen Third-Party-, Resource- und Long-Animation-Frame-Breakdowns) sind vom Pixel-Fallback per Namen ausgeschlossen; sie wandern nie über eine Access-Log-Oberfläche.
Der Wire-Payload
Der Payload ist JSON mit absichtlich kurzen Keys, um den Body klein zu halten. Der Body ist auf 8 KiB begrenzt. Alle Felder sind optional; ein typischer Envelope sieht so aus:
{
"sid": "01HZX...",
"pvid": "01HZY...",
"ver": 3,
"lcy": "hidden",
"pst": 1746604800000,
"cst": 1746604803456,
"u": "https://acme.com/pricing",
"r": "https://google.com/",
"b": "Chrome",
"v": "120",
"d": "desktop",
"o": "macOS",
"vc": "wide",
"c": "4g",
"ttfb": 320,
"fcp": 1100,
"lcp": 1820,
"inp": 140,
"cls": 0.05,
"errs": [ { "t": "TypeError", "n": 1, "m": "...", "fr": "..." } ],
"tv": "260508-a1b2c3d",
"dlv": "b"
}In der Praxis musst du das nicht lesen; Dashboard und Analytics-API packen das für dich aus. Steht hier zum Nachschlagen.
Schlüssel-Abkürzungen:
sid: Session-ID. Liegt imsessionStorage._fms. Nur wenncollect_sessionsan ist (beim Load oder nachgrantConsent(), je nachsession_consent).pvid: Per-Pageview-ID. Pro Pageview neu, nicht persistiert.ver: monoton steigende Version dieses Pageview-Payloads.lcy: Lifecycle-Marker, einer voninit,loaded,error_update,fetch_xhr_update,softnav,hidden,frozen,terminated. (Gecachte ältere Bundles senden ihn als langenlifecycle-Key, den der Collector ebenfalls akzeptiert.)pst: Page-Started-Timestamp, Besucher-Wallclock (ms seit Epoch).cst: Client-Sent-At-Timestamp, Besucher-Wallclock zum Flush-Zeitpunkt. Server nutzt das, um Clock-Skew gegen die Empfangszeit zu erkennen.u,r: Seiten-URL und Referrer, beide vom Tracker auf Origin + Pathname vorbereinigt (Query und Hash entfernt).rwird serverseitig in gebucketete Source + Medium klassifiziert und der rohe Wert vor jedem Logging-Pfad verworfen. Er persistiert nie, in keinem Modus.us,um,uc,ut,un,ci: Kampagnen-Attribution (utm source / medium / campaign / term / content und das Click-ID-Plattform-Label) auswindow.location.search. Jeweils auf 64 Zeichen begrenzt.ciist nur das Plattform-Label ("gclid"/"fbclid"/ …); der Click-ID-Wert wird vom Tracker verworfen. In jeder Konfiguration auf der Leitung, und ganz weggelassen, wenn leer.b,v,d,o,vc,c: Browser-Familie, Browser-Major, Device-Klasse, OS-Familie, Viewport-Klasse, Connection-Typ. Die ersten vier kommen ausFM-*-Edge-Headern;vcundcaus dem Browser.rtt/dlgesellen sich als Echtzeit-RTT- und Downlink-Schätzungen dazu.pre,ad,vd: Prerender-Flag (Speculation Rules API), Activation-Delta (ms, nur bei prerendered Pages) und Visibility-Dirty (war der Tab während des Pageviews im Hintergrund).- Metrik-Keys sind kurze Mnemonics:
ttfb,fcp,lcp,inp,cls, Page Load (plt), Cache-Hit-Rate (chr), die Resource- und Third-Party-Rollups je Typ sowie die Long-Animation-Frame-Aggregate je Skript. Früher waren es undurchsichtige nummerierte Slots (t1…t36); gecachte ältere Bundles senden diese Namen weiterhin, und der Collector bildet sie auf dieselben Felder ab. errs: Error-Einträge (tTyp,nCount,mMessage,frFrames).tundngehen in jeder Konfiguration raus, ebenso der Host jedes Frames; dazu Pfad und Zeile/Spalte der Frames in deinen eigenen First-Party-External-Scripts. Die Messagemist Opt-in übercollect_error_messages, Pfad/Zeile/Spalte von Inline- und Third-Party-Frames übercollect_error_frames; auch dann läuftmdurch einen Scrubber, der URLs, E-Mails, IDs und Strings in Anführungszeichen maskiert.snl: Route Load für Soft-Navigationen (soft_nav_load): das maximale End-Offset der Same-Site-Requests der Route. Ein Netzwerk-Proxy für den SPA-Routen-Load, bewusst nie in LCP/FCP verrechnet;nullbei Hard-Loads und wenn die Route keinen qualifizierenden Request abgesetzt hat.tv: Tracker-Version, FormatYYMMDD-<git-sha>[-dirty].dlv: Delivery-Methode (bfürsendBeacon, leer fürfetch).- Fetch/XHR und
Server-Timing: aggregierte Fetch/XHR-Werte je Endpunkt (Aufrufzahlen, Dauern, Dauer-Buckets, Statusfehler) und dieServer-Timing-Metriken der Seite. Beide sind templated und werden serverseitig normalisiert (die Leitung ist fälschbar), also tragen Pfade keine Query-Strings oder rohen IDs.
Soft-Navigationen (SPA-Routenwechsel) erzeugen keine nativen Paint- oder Navigation-Timing-Einträge, ihre Loading-Vitals kommen also aus zwei Quellen: dem snl-Netzwerk-Proxy (jeder Browser) und, auf Chromium sobald dessen Soft-Navigations-API ausgeliefert wird, echten LCP/FCP, die in die üblichen lcp/fcp-Keys geschrieben und der Route zugeordnet werden.
Cache und Rollouts
Das Script wird mit starkem Cache und ETag ausgeliefert. Zwei Dinge invalidieren den Cache automatisch:
- Einstellungs-Wechsel. Änderst du eine Einstellung, die das ausgelieferte Bundle betrifft (etwa
collect_sessions), liefert das eine neue Template-Version aus. - Beacon-Upgrade. Fastmon liefert Beacon-Versionen (
source_version); ein Wechsel der gepinnten Version rollt den Cache.
Du musst dafür nicht redeployen. Beim nächsten Cache-Check holt der Browser sich die neue Version automatisch.
Kunden-JS-API
Der Tracker liest ein paar namensstabile Globals von window.
Consent erteilen
Wenn collect_sessions an ist und session_consent auf off steht, wird der Session-ID-Schreibvorgang aufgeschoben, bis dein CMP Consent erteilt:
// In your cookie banner's "Accept" callback, and on every page load
// while consent is granted (most consent managers do this for you):
window.fastmon && window.fastmon.grantConsent && window.fastmon.grantConsent();grantConsent() vergibt die sessionStorage._fms-Session-ID und schaltet ab da die seitenübergreifende Verknüpfung frei. Idempotent, und es gibt keinen Widerruf mitten in der Session: die ID liegt im sessionStorage und stirbt mit dem Tab, Ablehnen heißt also schlicht, dass der Schreibvorgang nie passiert.
Feintuning
Standardmäßig hält der Tracker den Request-Umfang gering: init feuert sofort als Marker „dieser Pageview existiert“, loaded folgt, sobald der LCP final ist, Mid-Pageview-Updates feuern nur bei einem aussagekräftigen Signal (ein neuer First-Party-Endpoint, ein Fehler oder ein langsamer Aufruf), und die Update-Beacons einer pollenden Seite werden gedeckelt. Ein typischer Pageview sendet zwei bis vier Beacons. Für Seiten, die daran etwas ändern müssen, liest er ein paar window-Globals. Die meisten Sites fassen sie nie an; setz einen Wert vor dem <script>-Tag, damit schon das erste Beacon ihn respektiert.
| Global | Default | Wirkung |
|---|---|---|
__FASTMON_SAMPLE_RATE | 1 | Anteil der Pageviews, die Beacons senden (0 bis 1). 0 lässt einen Pageview ganz aus. Die Entscheidung gilt pro Pageview; ein gesampelter Pageview sendet alle seine Lifecycle-Beacons. |
__FASTMON_INIT_COALESCE_MS | 0 | Verzögerung vor dem init-Beacon. Bei 0 (Standard) feuert init sofort, sodass ein Pageview, der vor jedem anderen Beacon endet (ein Bot, ein Crash, ein abruptes Schließen), trotzdem registriert wird. Ein positiver Wert verzögert es wieder. |
__FASTMON_LCP_FINAL_CAP_MS | 10000 | Wie lange der Tracker auf das Finalwerden des LCP wartet, bevor er loaded sendet, wenn keine Interaktion und kein Tab-Wechsel den LCP vorher finalisiert. 0 deaktiviert den Deckel. |
__FASTMON_MAX_VERSION | 20 | Deckelt Mid-Pageview-Update-Beacons pro Pageview, damit eine pollende Seite nicht Tausende feuert. Lifecycle-Beacons werden nie gedeckelt, und die kumulativen Aggregate landen trotzdem auf dem finalen Beacon. 0 hebt den Deckel auf. |
Tracker-Einstellungen
Was der Beacon tut, steuern pro Site die Tracker-Einstellungen: ob Session-ID, Fehler-Message, Fehler-Frame-Detail, Query-Keys, Fetch/XHR-Telemetrie oder der Edge-stitch vorhanden sind. Die drei Ausgangspunkte sind die Presets (Minimal, Standard, Full). Die Datenschutz-Garantien aus Privacy gelten in jeder Konfiguration.
Rate-Limiting
Der Collector rate-limitet pro (collector_hash, Client-IP). Die IP wird am Edge nur für diesen Bucket gelesen; die Anwendung bekommt einen vorbereiteten Bucket-Key zu sehen, nicht die rohe IP, und die IP landet nicht auf der Platte. Das ist eine Schutzmaßnahme: eine kaputte Seite oder ein synthetischer Lasttest soll den Ingest für andere Tenants nicht zumüllen. Mit echtem Traffic läufst du da praktisch nie rein.
Wird ein Beacon rate-limitet, kommt eine 429 zurück. Der Browser wirft den Buffer weg und macht weiter; sonst passiert nichts.
Payloads über 8 KiB werden mit 413 abgelehnt. Liegt cst mehr als 5 Minuten neben der Server-Uhr, fällt der Server auf seine eigene Empfangszeit zurück, statt abzulehnen; der Beacon wird trotzdem akzeptiert.
Was du wissen solltest
- SPA-Route-Wechsel starten einen neuen Pageview. Das Script bleibt geladen, aber Soft-Navs (gepatchtes
history.pushStateundpopstate) generieren einen neuenpvid, setzen die Web-Vitals-Observer zurück und flushen einensoftnav-Beacon für den vorherigen Pageview. Ein Tab kann also viele Pageviews emittieren. - Mehrere Flushes pro Pageview. Geflusht wird bei den Lifecycle- Triggern
init,loaded,error_update,softnav,hidden,frozen,terminated: nicht nur beim Tab-Wechsel. Pro Besuch siehst du in der Regel mehrerePOST /c/.
Verwandt
- Implementierung: wie du den Beacon einbettest.
- Tracker-Einstellungen: was der Beacon erfasst, pro Einstellung.
- Presets: die drei Ausgangspunkte.
- Privacy: was wir nicht sammeln: was wir garantieren.
- Architektur: was nach dem POST passiert.