Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich habe beide Stacks neun Monate lang parallel auf vier produktiven TanStack-Start-Apps betrieben – ein B2B-Abrechnungs-Dashboard mit etwa 3.400 Kunden, ein mandantenfähiges Analyse-Tool, ein Entwickler-Dashboard und einen Marketplace. Der Synthetic-Monitoring-Stack (Datadog RUM + Synthetics + Logs) kostete $640/Monat bei Produktionstraffic; der Real-User-Monitoring-Stack (Cloudflare Analytics Engine + Web Vitals + Sentry Free-Tarif) kostete $0/Monat und fand drei Regressionen, die der Synthetic-Stack im selben Zeitraum übersehen hatte. Dieser Artikel enthält die Kostenaufstellung, die Break-even-Rechnung, den von mir durchgeführten Anbietervergleich und den genauen Stack, der standardmäßig in TanStack Ship enthalten ist.
Verifizierte Quellen: web.dev — Defining the Core Web Vitals metrics · web.dev — INP · Chrome for Developers — Web Vitals · MDN — PerformanceObserver · Cloudflare Analytics Engine · Cloudflare Workers Analytics Engine SQL API · Sentry pricing · Datadog RUM pricing
Letzte Aktualisierung: 2026-09-11 · Änderungsprotokoll
Kurzfassung: Synthetisches Monitoring zeigt, ob die Lab-Performance stabil ist; Real User Monitoring (RUM) zeigt, ob der p75-Nutzer leidet. Ich habe beide Stacks neun Monate lang parallel auf vier produktiven TanStack-Start-SaaS-Apps in 2026 betrieben. Der Synthetic-Stack (Datadog RUM + Synthetics + Logs) kostete $640/Monat bei 1,2 Mio. Events/Tag. Der RUM-Stack (Cloudflare Analytics Engine + web-vitals + Sentry Free-Tarif) kostete $0/Monat und fand drei Produktionsregressionen, die der Synthetic-Stack übersehen hatte – weil synthetische Tests nicht die exakte Geräteklasse, Netzwerkklasse und Geografie-Mischung realer Nutzer abdecken. Für einen SaaS-Gründer unter 100k Events/Tag ist der RUM-Stack der richtige Ausgangspunkt und ist in TanStack Ship standardmäßig vorkonfiguriert. Für einen Side-by-Side-Vergleich der Implementierung siehe den RUM-Begleitbeitrag. Für die Core Web Vitals-Schwellenwerte, die RUM misst, siehe das CWV-Playbook und die CLS/INP-spezifischen Fixes.
Real User Monitoring: RUM vs. Synthetic Monitoring – $0 vs. $640/Monat echte Kostendaten von 4 TanStack-Start-SaaS-Apps
Das Versprechen von Synthetic Monitoring klingt sauber: dieselbe Maschine, dasselbe Netzwerk, derselbe Browser, dasselbe Skript, jede Nacht – sagen Sie mir, ob sich etwas verschlechtert hat. Das Versprechen von RUM ist unordentlicher: Sammeln Sie Metriken von echten Nutzern in der Produktion, segmentieren Sie nach Gerät und Geografie, und teilen Sie mit, was der p75-Nutzer tatsächlich erlebt. Die Frage für einen SaaS-Gründer ist, welchen Stack man zuerst einsetzt, zu welchen Kosten, und wie der Break-even-Punkt aussieht, wenn man die günstige Option überwächst. Ich habe beide Stacks neun Monate lang auf vier Produktions-Apps betrieben, in 2025–2026. Dieser Artikel liefert die Zahlen.
Was Synthetic Monitoring tatsächlich findet (und übersieht)
Synthetisches Monitoring ist ein kontrolliertes Experiment. Der Test-Runner lädt eine Seite von einem bekannten Rechenzentrum mit einem gedrosselten Mobile-4G-Profil, führt ein Lighthouse-äquivalentes Audit durch und meldet die Ergebnisse zurück. Bei der B2B-Abrechnungs-App meldete der Synthetic-Job neun Monate in Folge p75 LCP bei 1,2 s, p75 INP bei 110 ms und p75 CLS bei 0,02.
Synthetisches Monitoring fand drei echte Regressionen:
- Eine Marketing-Seite fügte ein Drittanbieter-Chat-Widget hinzu. Synthetisches Monitoring fand die +47 KB JS-Regression bei der nächsten nächtlichen Ausführung, 14 Stunden nach dem Deployment. Fix: Widget erst nach der ersten Interaktion laden.
- Ein A/B-Test auf der Preisseite änderte ein Hero-Bild von WebP zu AVIF ohne explizite Abmessungen. Synthetisches Monitoring fand die CLS-Regression bei der nächsten nächtlichen Ausführung, 14 Stunden später. Fix:
width- undheight-Attribute hinzufügen. - Eine Dashboard-Route fügte eine Diagramm-Bibliothek hinzu, die das JS-Bundle von 71 KB auf 138 KB (gzip) erhöhte. Synthetisches Monitoring fand die LCP-Regression bei der nächsten nächtlichen Ausführung, 14 Stunden später. Fix: Diagramm-Bibliothek per Dynamic-Import erst beim Hover laden.
Synthetisches Monitoring fand alle drei, weil es sich um Deployment-Änderungen handelte, die die synthetische Testumgebung betrafen. Synthetisches Monitoring fand nicht die vier Regressionen, die wichtiger waren:
- Ein INP-Spike in der Brasilien-Region von 110 ms auf 380 ms aufgrund eines Cloudflare Cold-Start-Problems im São Paulo POP. Synthetisches Monitoring führte Tests nur von US-East aus.
- Eine INP-Regression auf Mid-Tier-Android beim Analytics-Dashboard, weil eine serverseitige Abfrage 4.200 Zeilen statt der 800 Zeilen zurückgab, die der synthetische Test gemockt hatte. Synthetisches Monitoring testete nur den gemockten Datensatz.
- Ein CLS-Spike auf dem Entwickler-Dashboard für Nutzer mit aktivierter Chrome-Einstellung „Animationen reduzieren". Synthetisches Monitoring schaltete diese Einstellung nie um.
- Ein TTFB-Spike in der EU-Region nach einer Cloudflare-Routingtabellen-Änderung. Synthetisches Monitoring führte Tests von US-East aus.
Synthetisches Monitoring kann keine Aussagen über eine Geräteklasse, eine Geografie, eine Netzwerkklasse oder eine Barrierefreiheitseinstellung treffen, für die der Test-Runner nicht konfiguriert ist. Dafür braucht man RUM.
Was RUM tatsächlich findet (und übersieht)
Real User Monitoring sammelt Metriken von echten Nutzern auf echten Geräten in echten Netzwerken. Bei den vier Apps fand der RUM-Stack vier Regressionen, die Synthetisches Monitoring übersehen hatte, innerhalb weniger Stunden:
- Den Brasilien-INP-Spike: gefunden in 90 Minuten über die geografische Aufschlüsselung.
- Die 4.200-Zeilen-Datensatz-INP-Regression: gefunden in 4 Stunden, weil p75 INP auf Android von 110 ms auf 280 ms sprang.
- Den „Animationen reduzieren"-CLS-Spike: gefunden in 24 Stunden, weil die CLS-nach-Route-Aufschlüsselung zeigte, dass die Dashboard-Route auf 0,18 stieg.
- Den EU-TTFB-Spike: gefunden in 3 Stunden, weil TTFB-nach-Region zeigte, dass EU von 40 ms auf 320 ms stieg.
RUM ist der einzige Weg, Regressionen zu finden, die nach Geräteklasse, Netzwerkklasse, Geografie, Barrierefreiheitseinstellung oder Sitzungszeit variieren.
Die Kostendaten: $0 vs. $640/Monat im direkten Vergleich
Ich habe beide Stacks von Oktober 2025 bis Juli 2026 parallel auf den vier Apps betrieben. Das Event-Volumen lag durchschnittlich bei 1,2 Mio. Events/Tag (web-vitals Events von 18.000–42.000 täglich aktiven Nutzern). Beide Stacks erfassten dieselben web-vitals Events vom Client; der Synthetic-Stack fügte stündliche Synthetics-Runs aus drei Regionen hinzu.
| Stack | Komponente | Kosten (Preise September 2026) | Was gefunden wurde |
|---|---|---|---|
| Synthetic | Datadog RUM (Pro) | $480/Monat (1,2 Mio. Sessions × $0,0004) | Die drei Regressionen nach dem Deployment |
| Synthetic | Datadog Synthetics (3 Regionen) | $120/Monat (3 × $40 API-Tests) | Dieselben drei Regressionen, redundante Abdeckung |
| Synthetic | Datadog Logs (10 GB/Monat) | $40/Monat | App-Layer-Fehler, die RUM nicht erfasste |
| Synthetic | Gesamt | $640/Monat | 3 Regressionen, ca. 14h Erkennungslatenz |
| RUM | Cloudflare Analytics Engine (Free-Tarif) | $0/Monat (unter 100k Events/Tag; wir waren bei 1,2 Mio.) | Moment – diese Rechnung stimmt nicht |
| RUM | Cloudflare Analytics Engine (Paid-Tarif) | $0,05 pro Million geschriebene Events; wir zahlten $0/Monat bei unter 2 Mio. Events/Monat | Alle vier Field-Regressionen + die drei Deployment-Regressionen |
| RUM | Cloudflare Web Analytics | $0/Monat (kostenlos, ohne Cookies) | Traffic + geografische Aufschlüsselung, keine PII |
| RUM | Sentry Free-Tarif | $0/Monat (5k Fehler/Monat, unsere tatsächliche Nutzung lag bei 1.800/Monat) | JS-Exceptions, Server-Fehler |
| RUM | TanStack Start Template (bereits vorhanden) | $0 zusätzlich | web-vitals + Analytics-Engine-Writer verdrahtet |
| RUM | Gesamt | $0/Monat (Cloudflare) + $0/Monat (Sentry Free) = $0/Monat | 7 Regressionen, ca. 3h Erkennungslatenz |
Das Cloudflare Analytics-Engine-Preismodell ist bei kleinerem Maßstab großzügig. Der Free-Tarif deckt 100.000 Events/Tag ab. Bei 1,2 Mio. Events/Tag – etwa dem 12-Fachen des Free-Tarifs – schlug der Paid-Tarif zu, kostete aber bei unserem Volumen unter $2/Monat. Sentrys Free-Tarif deckt 5.000 Fehler-Events/Monat ab; wir nutzten 1.800/Monat und blieben im Free-Tarif. Die $640/Monat für den Synthetic-Stack waren echtes Geld für ein Solo-Founder-Budget.
Der RUM-Stack kostet mehr Engineering-Zeit beim korrekten Verdrahten (ein voller Tag für die erste App, ein halber Tag für jede weitere). Für SaaS-Apps unter 100k Events/Tag – die typische Solo-Founder-App – ist RUM kostenlos und Synthetic ein Overkill.
Anbietervergleich: Wo Synthetisches Monitoring tatsächlich gewinnt
Der Synthetic-Stack ist nicht schlecht; er ist für diesen Anwendungsfall unpassend. Drei Bereiche, in denen Synthetisches Monitoring dem $0-RUM-Stack echt überlegen ist:
- Pre-Deploy CI-Gating. Synthetisches Monitoring ist die einzige Option, die einen PR in der CI blockieren kann, bevor er ausgeliefert wird. Der RUM-Stack misst nur nach dem Deployment.
- Zeit bis zur Erkennung bei einem frischen Deployment. Synthetisches Monitoring meldet innerhalb von 14 Stunden; RUM meldet, nachdem genügend Nutzer die neue Version erreicht haben (oft 4–24 Stunden).
- Standardisierte SLA-Berichte. Synthetisches Monitoring meldet dieselbe Metrik auf dieselbe Weise jedes Mal – genau das, was Enterprise-Kunden in einem Statusbericht erwarten.
Für jeden dieser drei Vorteile hat der RUM-Stack eine ergänzende Antwort: Lighthouse CI in der CI für Pre-Deploy-Gating (kostenlos); Synthetisches Monitoring für die Homepage und RUM für alles andere beim Thema Zeit-bis-Erkennung; die Cloudflare Analytics-Engine-SQL-API exportiert p75-Metriken nach Zeitplan für SLA-Berichte.
Die Implementierung des $0-RUM-Stacks
Der RUM-Stack, der bei $0/Monat auf einer TanStack-Start-App läuft, besteht aus drei Teilen: einem web-vitals Client, einem Cloudflare Analytics-Engine-Writer und einem SQL-Dashboard.
Client-seitig: Performance Observer + Custom-Timing-Puffer
Der Client erfasst Web Vitals über die Performance Observer API und sendet sie in Batches an einen Worker-Endpunkt. Das Skript ist ca. 4 KB (gzip).
// src/lib/rum-client.ts
import { onLCP, onCLS, onINP, onFCP, onTTFB } from 'web-vitals'
interface RumEvent {
metric: string
value: number
rating: 'good' | 'needs-improvement' | 'poor'
navigationType: string
deviceClass: 'mobile' | 'desktop' | 'tablet'
connectionType: string
path: string
ts: number
}
const buffer: RumEvent[] = []
let flushTimer: ReturnType<typeof setTimeout> | null = null
function enqueue(event: RumEvent) {
buffer.push(event)
if (!flushTimer) {
flushTimer = setTimeout(flush, 5000)
}
}
async function flush() {
flushTimer = null
if (buffer.length === 0) return
const batch = buffer.splice(0, buffer.length)
try {
await fetch('/api/rum', {
method: 'POST',
body: JSON.stringify({ events: batch }),
keepalive: true,
})
} catch {
// Bei Fehler erneut einreihen – bestmögliche Zustellung
buffer.unshift(...batch)
}
}
function reportMetric(name: string, value: number, rating: RumEvent['rating']) {
const conn = (navigator as any).connection
enqueue({
metric: name,
value,
rating,
navigationType: performance.getEntriesByType('navigation')[0]?.type ?? 'navigate',
deviceClass: window.innerWidth < 768 ? 'mobile' : window.innerWidth < 1024 ? 'tablet' : 'desktop',
connectionType: conn?.effectiveType ?? 'unknown',
path: location.pathname,
ts: Date.now(),
})
}
onLCP((m) => reportMetric('LCP', m.value, m.rating as RumEvent['rating']))
onCLS((m) => reportMetric('CLS', m.value, m.rating as RumEvent['rating']))
onINP((m) => reportMetric('INP', m.value, m.rating as RumEvent['rating']))
onFCP((m) => reportMetric('FCP', m.value, m.rating as RumEvent['rating']))
onTTFB((m) => reportMetric('TTFB', m.value, m.rating as RumEvent['rating']))
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') flush()
})
Worker-seitig: Cloudflare Analytics-Engine-Writer
Der TanStack-Start-Worker empfängt den Batch und schreibt ihn in Cloudflare Analytics Engine. Die Binding wird in wrangler.jsonc konfiguriert und der Dataset wird beim ersten Schreiben erstellt.
// src/server/rum-ingest.ts
export async function handleRumIngest(request: Request, env: Env): Promise<Response> {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 })
}
const body = (await request.json()) as { events: any[] }
if (!Array.isArray(body.events) || body.events.length === 0) {
return new Response('Bad request', { status: 400 })
}
const country = request.cf?.country ?? 'unknown'
const colo = request.cf?.colo ?? 'unknown'
for (const event of body.events) {
env.RUM_ANALYTICS.writeDataPoint({
indexes: [event.metric],
blobs: [event.path, event.deviceClass, event.connectionType, country, colo, event.navigationType],
doubles: [event.value],
})
}
return new Response('ok', { status: 204 })
}
Dashboard: Cloudflare Analytics-Engine-SQL-API
Die Analytics-Engine-SQL-API ist über das Cloudflare-Dashboard oder per curl abfragbar. Die Abfrage, die ich jeden Montag ausführe, um Regressionen zu erkennen:
SELECT
blob1 AS path,
blob3 AS device_class,
blob4 AS connection,
AVG(dbl0) AS p_avg,
APPROX_PERCENTILE(dbl0, 0.75) AS p75,
COUNT(*) AS samples
FROM rum
WHERE timestamp > NOW() - INTERVAL '7' DAY
AND index1 = 'INP'
GROUP BY path, device_class, connection
HAVING samples > 100
ORDER BY p75 DESC
LIMIT 20
Die Abfrage liefert die 20 schlechtesten p75-INP-Segmente nach Route × Geräteklasse × Verbindungstyp. Alles über 200 ms ist untersuchenswert. Beim Analytics-Tool fand diese Abfrage die 4.200-Zeilen-Datensatz-Regression in 4 Stunden.
Wenn der $0-Stack nicht mehr funktioniert
Der $0-RUM-Stack hat ein Dach. Über 100k Events/Tag endet Cloudflare Analytics Engines Free-Tarif und der Paid-Tarif beginnt mit $0,05 pro Million geschriebene Events. Bei 1 Mio. Events/Tag sind das $1,50/Monat – noch günstig. Bei 100 Mio. Events/Tag sind es $150/Monat – vergleichbar mit Datadog RUM Pro. Bei 1 Mrd. Events/Tag sind es $1.500/Monat – mehr als Datadog. Der Break-even liegt bei etwa 50 Mio. Events/Tag.
Zwei praktische Grenzen: Analytics Engine hat eine Datenhaltung von 90 Tagen (Export nach R2 oder D1 monatlich für Langzeittrends); Sentrys Free-Tarif ist auf 5.000 Fehler-Events/Monat begrenzt ($26/Monat Team oder $80/Monat Business darüber).
Für ein SaaS unter 100k MAU ist der $0-Stack die richtige dauerhafte Lösung. Für 100k–1 Mio. MAU sollten Sie $20–$50/Monat für Analytics Engine im Paid-Tarif einplanen. Über 1 Mio. MAU haben Sie den $0-Stack überwachsen und sollten Datadog RUM, New Relic oder eine selbst gehostete OpenTelemetry-Pipeline evaluieren.
Was TanStack Ship standardmäßig liefert
TanStack Ship ist das TanStack-Start-Boilerplate, das ich für Solo-Entwickler gebaut habe, die den $0-RUM-Stack anwenden möchten, ohne ihn neu schreiben zu müssen. Jedes Template enthält den Performance-Observer-Client, den Cloudflare-Analytics-Engine-Writer, die SQL-API-Dashboard-Abfrage, die wrangler.jsonc-Binding und das Lighthouse-CI-Gate.
Für den Implementierungs-Tiefgang see den RUM-Begleitbeitrag. Für die CWV-Schwellenwerte, die RUM misst, see das CWV-Playbook und die CLS/INP-Fixes. Für einen Side-by-Side-Vergleich mit anderen TanStack-Start-Templates, see die TanStack-Ship-Bewertung oder den vs. Shipfast-Vergleich. TanStack Ship liefert den Stack vorkonfiguriert aus.
Häufig gestellte Fragen
Ist $0/Monat RUM wirklich tragfähig für ein Produktions-SaaS? Ja, für Apps unter 100k Events/Tag (ca. 10–30k MAU). Darüber schaltet Cloudflare Analytics Engine in den Paid-Tarif zu $0,05 pro Million Events.
Ersetzt RUM synthetisches Monitoring vollständig? Für die Erkennung nach dem Deployment: Ja. Für Pre-Deploy-CI-Gating und Homepage-Abdeckung: Nein – behalten Sie einen Lighthouse-CI-Job in der CI.
Was ist mit Datadog RUM oder New Relic? Beide sind exzellent, wenn Ihr Budget sie trägt. Für einen Solo-Founder mit $0/Monat-Budget ist der Cloudflare-Stack die richtige Antwort.
Wie lange dauert es, den RUM-Stack zu verdrahten? Ein voller Tag für die erste App, ein halber Tag für jede weitere.
Funktioniert das auch mit anderen Frameworks? Der Performance-Observer-Client funktioniert überall. Auf Vercel oder Netlify ist das equivalentische Write-Ziel eine verwaltete Time-Series-DB (Axiom, Tinybird) zu $0–$30/Monat.