Skip to main content
The MoleSignal Flutter App RUM SDK sends mobile telemetry in the same event format as the Browser RUM SDK. Flutter-native instrumentation preserves the same investigation workflow without inventing browser-only metrics.

Capability parity

Browser-only metrics such as LCP and CLS are not generated for Flutter applications. Flutter reports its build, raster, refresh-rate, slow-frame, frozen-frame, and memory data.

Requirements

  • Flutter 3.35 or later;
  • Dart 3.9 or later;
  • Android 24+ or iOS 13+ when using the default persistent identity store.
Device brand, model, operating system version, battery level, and connectivity are read with device_info_plus, battery_plus, and connectivity_plus, which the package depends on. Set trackDeviceInfo: false to send only what Flutter itself exposes.

Install and initialize

clientToken ships in the application and must be treated as public. Use the application-bound msrum_ client token of the RUM application.
1

Create the application

Open RUM → Applications, click Create application, and choose the Flutter platform. Open the setup guide shows the endpoint, the token, and the configuration filled in with the identifier.
2

Add the package

Run flutter pub get after updating pubspec.yaml.
3

Initialize before runApp

Call initRum as early as possible: the cold-start time is measured from it to the first frame. RumApp installs the replay boundary, automatic tap collection, and frustration detection. Replay remains disabled unless sessionReplaySampleRate selects the current session or recording is started manually.
4

Verify the first session

Open RUM → Explorer, select a time range that includes the current time, and confirm that the session of checkout-mobile appears. Open it to inspect the views and the device context.
site accepts the MoleSignal origin, or a base that ends in /api, /api/v1, or /api/v1/rum. The SDK completes the path and sends events to POST /api/v1/rum/events. applicationId must be the application of the token: it is sent as application.id, and MoleSignal rejects events that name another application.

Sessions and views

A session is identified by a UUID kept in shared preferences. It ends after 15 minutes without activity or after four hours, and is sampled once, when it starts. The SDK sends no session event: MoleSignal derives sessions from the views. Every event carries session.id, session.type, and session.start; a view also carries session.has_replay, which is true once a segment of the session was recorded. A view never spans two sessions: when a session is renewed under a showing view, that view ends and the same screen continues in a new view with loading_type: session_renewal. RumNavigationObserver records visible named routes. Supply the observer through the router integration for Router or go_router applications. Call startView when a route has no stable name or when navigation is managed outside Navigator.
view.url is the route path, without query and fragment unless trackUrlQueryString is set, and view.name is the name. Starting a view ends the previous one. A view is reported again with a higher view.revision and its counts so far whenever something in it changed: at most once per flushInterval, and immediately when it starts, ends, or the app is flushed. Views end when the app goes to the background and are shown again, as view_controller_redisplay, when it returns. Events that happen before the first startView belong to an ApplicationLaunch view.

Identify users and record application activity

The SDK chains existing FlutterError.onError and PlatformDispatcher.onError handlers. Forward errors from additional isolates to the main isolate and call addError. Call clearUser() after sign-out when the next activity must no longer use the identified user. Actions are tap, custom, back, and the automatic application_start. Automatic taps use the generic name Tap so no screen content is read. Wrap important controls with RumUserAction to attach a stable business name without taking ownership of Flutter’s gesture arena:
A tap stays open while the requests it started are in flight, for at most five seconds. The errors, crashes, and resources in that time carry its action.id, and the action reports their counts. Three taps within 50 logical pixels in a second make the last a rage_tap, and a tap that caused an error is an error_tap. Set trackUserInteractions: true to collect taps; trackFrustrations follows it by default. Errors carry source, type, message, stack, structured frames, and handling. Framework errors are unhandled, and errors from PlatformDispatcher.onError are also crashes. addError reports a handled error with the source you choose, custom by default. A request that failed before a response is a network error; an HTTP error status is only a resource. The SDK does not set error.fingerprint; pass fingerprint: to choose the grouping.

Monitor HTTP resources and backend traces

Wrap package:http with MoleSignalHttpClient:
Declare http: ^1.6.0 as a direct application dependency when the application does not already use package:http. The wrapper records the sanitized URL, method, duration, status code, response size, and available W3C trace identifiers. The duration ends when the response body is consumed, fails, or is cancelled. Trace context is read in this order: response traceparent, a traceparent entry in Server-Timing, then request traceparent. Restrict trace-header reading when only selected services are trusted:
The SDK does not globally intercept networking. Dio and other clients call startResource and stopResource from their interceptors, or addResource for a finished request.

Rendering performance fields

Upload release symbols

Set version, architecture, and debugId from immutable release-pipeline values. Use the same values for every debug artifact produced by that build. Runtime-detected or derived fallbacks are useful for development, but do not provide a stable production symbolication identity. Build Android and iOS releases with --obfuscate and --split-debug-info, and pass the identity with --dart-define:
With --split-debug-info, each error frame carries artifact_kind: flutter_symbols, the absolute and relative addresses a symbol file resolves, and the debug_id the build was configured with. Upload every generated .symbols file with kind=flutter_symbols, the matching android or ios platform, canonical architecture, and Debug ID. Upload native Android ELF symbols and Apple dSYM DWARF files separately when native crash frames are forwarded with RumStackFrame. Artifact upload requires a management token with streams.configure. Never use the application-bound msrum_ client token for artifact management.

Source maps & symbols

Generate, upload, match, and verify Flutter, Android, iOS, and Web debug artifacts.

Enable session replay

Flutter has no DOM. The first captured frame becomes rrweb Meta and FullSnapshot events. Changed frames become incremental image mutations, and unchanged frames are skipped. The existing MoleSignal replay player can therefore render browser and Flutter sessions through the same workflow.
sessionReplaySampleRate applies within sessions included by sessionSampleRate; multiply both rates to calculate effective replay coverage. Manual recording also applies only to an included session. Replay uses a separate queue, a 10-second default flush interval, per-session sequence numbers, approximately 1 MiB target segments, and an 8 MiB request ceiling. Segments go to POST /api/v1/rum/replay.

Protect replay content

The default RumPrivacyLevel.mask covers Text, RichText, and editable regions before PNG encoding. Input fields stay masked in allow mode. The SDK also removes URL queries and fragments and recursively redacts common sensitive context keys. Raw stack text is sent only with RumPrivacyLevel.allow; otherwise error.stack is rebuilt from the sanitized frames. Wrap sensitive images, maps, custom-painted content, platform views, or complete components in an explicit privacy boundary:
RumReplayMask and RumReplayBlock both replace the captured region with an opaque block. Raw, unmasked pixels never enter the event queue.
Text drawn by CustomPainter cannot be detected from the widget type. Wrap the custom-painted region explicitly. Platform-view capture depends on platform composition; verify sensitive platform views on real Android and iOS devices.

Delivery

Events are batched into a JSON array and sent to POST {site}/api/v1/rum/events with the client token. Batches of more than 1 KiB are gzip-compressed where dart:io is available; set compressRequests: false to turn it off. A request holds at most 48 KiB of events, far below the 5000 events and 5 MiB the receiver accepts.
  • An event that MoleSignal rejects is reported through onError and RumFlushResult, and is never sent again.
  • Network errors, timeouts, 408, 429, and 5xx are retried with exponential backoff and jitter, never sooner than the Retry-After the receiver sent. Events survive in a persisted offline queue.
  • Any other 4xx drops the batch.
The queue is bounded by item count, bytes, and age (maxQueueSize, maxQueueBytes, queueItemTtl). A newer revision of a view replaces the older ones that are still waiting, so the revision numbers MoleSignal sees may skip values.

Main configuration

RumSessionReplayConfiguration defaults to a 5-second capture interval, capture after actions, 0.5 output pixels per logical pixel, a 900-pixel maximum image edge, and mask color #6B7280. excludedUrls, allowedTracingUrls, queue bounds, retry delays, timeouts, diagnostics, custom transport, and persistence are also configurable.

Flush and stop

Call flush() before a controlled transition that must wait for queued events. Call stop() during final teardown to end the active view with a last report, remove instrumentation, and flush both event queues. Both return a RumFlushResult that separates accepted, retried, dropped, remaining, and timed-out events.

Browser RUM SDK

Compare the Browser SDK setup and browser-specific instrumentation.

RUM event format

The events the SDK sends, and the fields of each.

Source maps & symbols

Restore Flutter, Android, iOS, and Web release stacks.
Last modified on October 26, 2026