OpenTelemetry RUM: real user monitoring without a vendor SDK
TL;DR: Most real user monitoring SDKs speak only to the vendor that wrote them, so switching platforms means changing code in every app and shipping a release to every user. OpenTelemetry RUM emits standard spans, metrics, and logs over OTLP instead, so the destination is configuration rather than a rewrite. base14's Flutter and React SDKs work this way, and the resulting telemetry is billed as signals rather than per session.
Backend observability settled this argument years ago. You instrument with OpenTelemetry, you point a collector wherever you want, and changing vendor is a config change. Nobody rewrites their tracing code to move from one backend to another anymore.
The frontend never got there. Browser and mobile RUM is still where the proprietary agent lives.
Why RUM lock-in costs more than backend lock-in
A backend agent runs on infrastructure you control. Swapping it out is a deploy.
A RUM SDK runs on devices you do not control. Replacing it in a mobile app means changing code, shipping a release, waiting for app store review, and then waiting for users to update. Some fraction never will. For months you are running two SDKs, paying two vendors, and reconciling two datasets that disagree.
That is why RUM instrumentation tends to outlive the decision that introduced it. The cost of changing it is the release cycle, not the license fee.
What OpenTelemetry RUM means
It means the SDK produces OpenTelemetry signals, not a vendor payload:
- A click is a
user_interactionspan. - A route change is a
screen_viewspan. - A Core Web Vital is a
web_vitalspan with a name, value, and rating. - A crash is a
native_crashspan carrying the stack and the session that died. - A
fetchcall is anhttp.requestspan that propagatestraceparent.
The last one carries the most weight. Because the browser span carries W3C trace context, the click that started a request and the backend work it caused end up in the same trace, rather than in two dashboards lined up by timestamp.
Because the wire format is OTLP, the receiving end is your choice.
What the SDKs capture
scout_flutter covers Flutter on iOS, Android, macOS, and web.
@base-14/scout-react covers React Native on iOS and Android plus React in
the browser. Both auto-capture the full RUM event set except Session Replay
and Profiling, with no manual tracking calls in your application code.
| Area | Captured |
|---|---|
| Interaction | Taps, clicks, scroll depth, rage clicks, dead clicks, error clicks |
| Navigation | Screen and route views, load time, referrer, foreground periods |
| Network | fetch and XHR with status, duration, phase breakdown, GraphQL operation, third-party classification |
| Errors | Handled and unhandled errors with fingerprint, cause chain, and breadcrumbs |
| Crashes | Native iOS crashes via KSCrash and MetricKit; Android via NDK signal handler and ApplicationExitInfo |
| Responsiveness | ANRs with thread dumps, iOS UI hangs, long tasks, frozen frames, frame rate |
| Web vitals | LCP, INP, CLS, FCP, TTFB with sub-part timings |
| Context | Session and user identity, feature flags, device, OS, network, locale, ~20 accessibility flags |
Delivery is built for real networks: batched export, exponential backoff with jitter, an on-disk buffer that survives being offline, and a forced flush when the app goes to the background.
Two limitations to check before you commit
Session replay is not there. Neither SDK captures it, and neither captures profiling. If replay is on your requirements list, this is the wrong tool and the rest of the page does not matter.
RUM does sample sessions. The SDK defaults to a 1% session sample rate, which is normal for RUM at consumer volume and is what keeps the cost of high-traffic apps sane. What matters is what sampling does not touch: crash, error, and ANR telemetry bypasses the session sample rate. So crash-free rate and error counts stay accurate even at 1%. You lose routine session detail, not failure visibility.
Both are worth confirming before you start an evaluation.
How the pricing model differs
Most RUM is billed per session, sometimes per user, usually with session replay as a separate line. That model ties your monitoring bill to your product's success, so a traffic spike lands as an unplanned invoice for the platform team.
Signal-based pricing bills RUM as what it is, telemetry. base14 Scout charges a $250/month platform fee plus $0.10 per million metrics and $0.25 per million logs and traces. Spans from a browser cost the same as spans from a backend service, there is no per-seat charge, and there is no separate RUM tier to buy.
The practical difference is which lever you pull when the bill grows. Under per-session pricing you reduce the number of sessions you observe. Under signal pricing you tune what each session emits, which is a decision about detail rather than coverage.
Getting started
The instrumentation side takes one call:
- React web - install
@base-14/scout-react, callScout.initialize()on boot. - React Native - same package, native entry point, Expo module auto-links.
- Flutter - add
scout_flutter, wrap your app. - Browser JavaScript - the manual path, for vanilla JS or when you want to choose every span.
Once telemetry is arriving, Scout's RUM views cover sessions, screens, crashes, errors, ANRs, and network.
FAQ
What is OpenTelemetry RUM?
OpenTelemetry RUM is real user monitoring where the browser or mobile SDK emits standard OpenTelemetry spans, metrics, and logs over OTLP, rather than a vendor-specific wire format. A click becomes a span, a Core Web Vital becomes a span, a crash becomes a span. Because the output is OTLP, any OpenTelemetry backend can receive it and the same trace context links a browser click to the backend request it triggered.
Can I send OpenTelemetry RUM data to any backend?
Yes. Both base14 SDKs, scout_flutter and @base-14/scout-react, export
OTLP. You can point them at a Scout collector, at your own OpenTelemetry
Collector, or at another OTLP-compatible backend, and you can fan out to
more than one at once by adding exporters to a collector you control.
Changing destination is a configuration change, not a reinstrumentation
project.
How is OpenTelemetry RUM different from Datadog RUM or New Relic Browser?
Datadog and New Relic ship their own browser and mobile agents that report to their own backends in their own formats. The instrumentation is tied to the vendor, so moving platforms means replacing the SDK in every app and shipping a new release to every user. With OpenTelemetry RUM the instrumentation is standard and only the export destination changes.
Does base14 Scout RUM support session replay?
No. Session Replay and Profiling are the two parts of the RUM event set the SDKs do not capture. Everything else is covered, including clicks, navigation, HTTP requests, errors, native crashes, ANRs, Core Web Vitals, long tasks, frozen frames, and scroll depth. If session replay is a requirement, Scout RUM is not a fit today.
How much does OpenTelemetry RUM cost with signal-based pricing?
RUM telemetry is billed as ordinary signals rather than per session or per user. Under base14 Scout's pricing that is a $250/month platform fee plus $0.10 per million metrics and $0.25 per million logs and traces, with no per-seat charges. Cost tracks the volume of telemetry produced, so a session on a busy screen costs more than a quiet one. The Startup tier includes up to 50 authorized users and Enterprise raises the limit.
Does RUM session sampling cause you to miss crashes?
No. The SDK samples sessions and defaults to 1%, but crash, error, and ANR telemetry bypasses the session sample rate. Crash-free rate and total error counts stay accurate at low sample rates. Sampling reduces the volume of routine session detail, not your visibility into failures.
Want to see browser and backend telemetry in one trace? Book a 15-minute demo.