Diese Dokumentation entsteht gerade: einzelne Seiten können noch unvollständig oder stellenweise ungenau sein.
fastmon Docs
Konzepte

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:

BuildWannSpeicher auf dem Gerät
Statelesscollect_sessions ausKeiner; der sessionStorage-Schreibvorgang wird komplett herauskompiliert
Statefulcollect_sessions anNur 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

QuelleWas erfasst wird
PerformanceObserverLCP, INP, CLS, FCP, Paint-Einträge, Long Animation Frames, Layout Shifts.
Navigation TimingTTFB, Redirect-Count, Navigation-Typ (navigate, reload, back_forward).
Resource TimingPro Resource: Größe, Dauer, Kategorie. Pro Domain aggregiert.
error-EventTyp, 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.
unhandledrejectionSelbe Form wie error.
Page Visibility APITime-to-Hidden, gesamte sichtbare Zeit.
fetch / XMLHttpRequestAggregierte 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-TimingDie Server-Timing-Metriken, die dein eigenes Backend meldet (Name und Dauer), per Konstruktion First-Party.
Document & WindowSeiten-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 Storage lesen 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_sessions ist an (dann die tab-gebundene Session-ID). Die Per-Pageview-ID pvid gibt 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 im sessionStorage._fms. Nur wenn collect_sessions an ist (beim Load oder nach grantConsent(), je nach session_consent).
  • pvid: Per-Pageview-ID. Pro Pageview neu, nicht persistiert.
  • ver: monoton steigende Version dieses Pageview-Payloads.
  • lcy: Lifecycle-Marker, einer von init, loaded, error_update, fetch_xhr_update, softnav, hidden, frozen, terminated. (Gecachte ältere Bundles senden ihn als langen lifecycle-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). r wird 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) aus window.location.search. Jeweils auf 64 Zeichen begrenzt. ci ist 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 aus FM-*-Edge-Headern; vc und c aus dem Browser. rtt / dl gesellen 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 (t1t36); gecachte ältere Bundles senden diese Namen weiterhin, und der Collector bildet sie auf dieselben Felder ab.
  • errs: Error-Einträge (t Typ, n Count, m Message, fr Frames). t und n gehen in jeder Konfiguration raus, ebenso der Host jedes Frames; dazu Pfad und Zeile/Spalte der Frames in deinen eigenen First-Party-External-Scripts. Die Message m ist Opt-in über collect_error_messages, Pfad/Zeile/Spalte von Inline- und Third-Party-Frames über collect_error_frames; auch dann läuft m durch 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; null bei Hard-Loads und wenn die Route keinen qualifizierenden Request abgesetzt hat.
  • tv: Tracker-Version, Format YYMMDD-<git-sha>[-dirty].
  • dlv: Delivery-Methode (b für sendBeacon, leer für fetch).
  • Fetch/XHR und Server-Timing: aggregierte Fetch/XHR-Werte je Endpunkt (Aufrufzahlen, Dauern, Dauer-Buckets, Statusfehler) und die Server-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.

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.

GlobalDefaultWirkung
__FASTMON_SAMPLE_RATE1Anteil 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_MS0Verzö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_MS10000Wie 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_VERSION20Deckelt 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.pushState und popstate) generieren einen neuen pvid, setzen die Web-Vitals-Observer zurück und flushen einen softnav-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 mehrere POST /c/.

Verwandt

On this page