Flutter RUM

The Middleware Flutter RUM SDK collects user activity, performance data, and errors from Flutter applications. It helps you investigate navigation problems, rendering delays, crashes, and slow or failed requests.

Session data and supported recordings provide context for application problems. Custom events and spans can describe operations such as login, checkout, or data synchronization, making it easier to identify which part of a workflow failed or took longer than expected.

Prerequisites#

Before installing the SDK, make sure you have:

  • Flutter 3.7.0 or later.
  • Dart 3.7.0 or later.
  • A Middleware account and RUM application credentials.
  • Access to your Flutter application source code.
  • HTTPS connectivity to the Middleware ingestion endpoint.

For mobile applications, additional requirements apply:

PlatformRequirements
AndroidcompileSdk 35+, Kotlin Gradle Plugin 2.0+, core library desugaring
iOSiOS 13.0+, CocoaPods support

The Flutter SDK includes native Middleware SDKs for Android and iOS to support crash reporting, ANR detection, and native Session Replay.

Installation#

1 Create a RUM application#

  1. Log in to Middleware.
  2. Go to Installation → RUM.
  3. Select Flutter as the platform.
  4. Click New Application.
  5. Enter your application name and click Create Application.
  6. Copy the generated account key and target URL.

2 Install the Flutter SDK#

Add the Middleware SDK to your pubspec.yaml:

1dependencies:
2  flutter:
3    sdk: flutter
4  middleware_flutter_opentelemetry: ^1.1.1

The documented SDK version also requires the following dependency override:

1dependency_overrides:
2  path_provider_android: 2.2.12

This avoids a dependency compatibility issue with newer path_provider_android releases.

Install the dependencies:

1flutter pub get

For iOS, install the native pods:

1cd ios
2pod install
3cd ..

Note: Review the dependency override when upgrading the Flutter SDK or Middleware package.

3 Initialize Middleware#

Initialize the SDK in main.dart before calling runApp().

1import 'dart:async';
2import 'package:flutter/material.dart';
3import 'package:middleware_flutter_opentelemetry/flutterrific_otel.dart';
4
5void main() {
6  FlutterError.onError = (FlutterErrorDetails details) {
7    FlutterOTel.reportError(
8      'FlutterError.onError',
9      details.exception,
10      details.stack,
11    );
12  };
13
14  runZonedGuarded(() {
15    FlutterOTel.initialize(
16      serviceName: 'my-flutter-app',
17      serviceVersion: '1.0.0',
18      tracerName: 'main',
19      middlewareAccountKey: '<MW_ACCOUNT_KEY>',
20      endpoint: 'https://<MW_UID>.middleware.io',
21      resourceAttributes: {
22        'env': 'production',
23        'service.namespace': 'mobile-apps',
24      },
25    );
26
27    runApp(const MyApp());
28  }, (error, stack) {
29    FlutterOTel.reportError('Zone Error', error, stack);
30  });
31}

Replace the placeholders with your Middleware credentials.

ParameterRequiredDescription
serviceNameYesName used to identify your Flutter application
serviceVersionNoApplication version
tracerNameNoName of the OpenTelemetry tracer
middlewareAccountKeyYesMiddleware account key
endpointYesMiddleware ingestion endpoint
resourceAttributesNoAdditional attributes such as environment or namespace

Initialize Middleware as early as possible to capture startup activity, navigation, and errors.

Alternative: You can enable automatic Flutter error capture using autoCaptureErrors: true in FlutterOTel.initialize(), instead of registering error handlers manually.

4 Run and verify#

Run your Flutter application:

1flutter run

To verify data collection:

  1. Open the application on an emulator or physical device.
  2. Navigate between screens and interact with the application.
  3. Go to RUM → Session Explorer in Middleware.
  4. Verify that new sessions and navigation events appear.

Read more about RUM explorer and see what data to monitor for frontend performance.

Optional configuration#

Configure Session Replay#

Session Replay is supported on Android, iOS, and Web, with platform-specific recording behavior.

Android and iOS#

With Flutter SDK 1.1.x, Session Replay uses the embedded native Middleware SDKs.

Recording starts automatically when Middleware initializes.

No additional RepaintBoundary, startSessionRecording(), or stopSessionRecording() calls are required.

To disable Session Replay:

1FlutterOTel.initialize(
2  serviceName: 'my-flutter-app',
3  middlewareAccountKey: '<MW_ACCOUNT_KEY>',
4  endpoint: 'https://<MW_UID>.middleware.io',
5  enableSessionRecording: false,
6);

To opt out of native Session Replay and use the Dart recorder instead:

1disableSessionRecordingV3: true

Flutter Web#

For Flutter Web, the SDK uses a Dart-based recording implementation.

Wrap your application in a RepaintBoundary:

1RepaintBoundary(
2  key: FlutterOTel.repaintBoundaryKey,
3  child: const MyApp(),
4)

Start recording after the widget tree is initialized:

1FlutterOTel.startSessionRecording();

Stop recording when it is no longer needed:

1FlutterOTel.stopSessionRecording();

For example, you can start recording in initState() after a short delay and stop it in dispose().

Session limits#

  • Maximum session duration: 4 hours.
  • Idle timeout: 15 minutes.

A new session begins after the inactivity timeout.

Privacy recommendation: Review sensitive screens and user inputs before enabling Session Replay in production. Avoid including passwords, tokens, payment details, or personal information in custom telemetry attributes.

Monitor HTTP requests#

Instrument HTTP requests to capture request duration, response status, and errors.

You can use manual spans or an instrumented HTTP client.

Option 1: Manual HTTP instrumentation#

Create an OpenTelemetry span around an HTTP request:

1final span = FlutterOTel.tracer.startSpan(
2  'HTTP GET /users',
3  attributes: {
4    'event.type': 'xhr',
5    'url.full': 'https://api.example.com/users',
6  },
7);
8
9try {
10  final response = await apiClient.getUsers();
11
12  if (response.statusCode >= 400) {
13    span.setStatus(
14      SpanStatusCode.Error,
15      'HTTP ${response.statusCode}',
16    );
17  } else {
18    span.setStatus(SpanStatusCode.Ok);
19  }
20} catch (error, stackTrace) {
21  span.recordException(error, stackTrace: stackTrace);
22  span.setStatus(SpanStatusCode.Error, error.toString());
23  rethrow;
24} finally {
25  span.end();
26}

This example assumes apiClient.getUsers() is a method in your application's HTTP client.

Option 2: Instrument HttpClient#

For applications using dart:io's HttpClient, use the OpenTelemetry HTTP wrapper:

1import 'dart:io';
2import 'package:middleware_dart_opentelemetry/middleware_dart_opentelemetry.dart';
3
4final client = OTelHttpClient(HttpClient());
5
6final request = await client.getUrl(
7  Uri.parse('https://api.example.com/users'),
8);
9
10final response = await request.close();
11
12print('HTTP status: ${response.statusCode}');

The wrapper automatically creates HTTP spans, captures request metadata, and propagates W3C Trace Context.

Note: Initialize the OpenTelemetry SDK before using OTelHttpClient. The HTTP wrapper is intended for platforms supporting dart:io; browser networking requires a different approach.

Configure distributed tracing#

Distributed tracing connects Flutter HTTP requests with backend APM traces.

When using OTelHttpClient, the SDK propagates W3C Trace Context headers, including traceparent and tracestate.

Prerequisites#

  • Your backend must have Middleware APM instrumentation enabled.
  • The backend must support W3C Trace Context.
  • Flutter HTTP requests must use an instrumented client or manually propagate trace context.

Verify trace correlation#

  1. Open the Flutter application.
  2. Trigger a request to an instrumented backend service.
  3. Go to RUM → Session Explorer.
  4. Open the corresponding session and network event.
  5. Follow the associated backend trace when available.

If backend spans are missing, verify that tracing headers reach the backend and that its APM instrumentation is configured correctly.

Track user interactions#

Use widget extensions to record application-specific interactions.

Track button clicks#

1ElevatedButton(
2  onPressed: handleSubmit,
3  child: const Text('Submit'),
4).withOTelButtonTracking('submit_form');

Track text field interactions#

1TextField(
2  decoration: const InputDecoration(
3    labelText: 'Enter something',
4  ),
5).withOTelTextFieldTracking('demo_text_field');

Add an error boundary#

1RiskyWidget().withOTelErrorBoundary('risky_operation');

These events provide additional context when investigating what happened before an error.

Avoid collecting sensitive text field values.

Add custom spans#

Use custom spans to track important application workflows, such as login, checkout, or data synchronization.

1final tracer = FlutterOTel.tracer;
2
3final span = tracer.startSpan(
4  'checkout',
5  attributes: {
6    'operation': 'payment',
7    'screen': 'checkout',
8  },
9);
10
11try {
12  await processPayment();
13
14  span.setStatus(SpanStatusCode.Ok);
15} catch (error, stackTrace) {
16  span.recordException(error, stackTrace: stackTrace);
17  span.setStatus(SpanStatusCode.Error, error.toString());
18  rethrow;
19} finally {
20  span.end();
21}

Custom spans help identify which application operation failed or took longer than expected.

Configure environment-specific settings#

Use Flutter's --dart-define arguments to pass different settings for development, staging, and production.

For example:

1flutter run \
2  --dart-define=OTEL_SERVICE_NAME=my-flutter-app \
3  --dart-define=OTEL_SERVICE_VERSION=1.0.0 \
4  --dart-define=OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector:4317 \
5  --dart-define=OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
6  --dart-define=OTEL_EXPORTER_OTLP_HEADERS=Authorization=your-api-key

These values can also be used in CI/CD pipelines to configure different environments.

Important: --dart-define values are embedded in the application build and should not be treated as secrets. Use only credentials intended for client-side SDKs.

Configuration reference#

All parameters accepted by FlutterOTel.initialize():

ParameterDescription
serviceNameApplication service name
serviceVersionApplication version
tracerNameOpenTelemetry tracer name
middlewareAccountKeyMiddleware account key
endpointMiddleware ingestion endpoint
resourceAttributesCustom resource attributes
autoCaptureErrorsAutomatically registers Flutter error handlers
enableSessionRecordingEnables or disables Session Replay
disableSessionRecordingV3Uses the Dart recorder instead of native Session Replay

Troubleshooting#

No RUM data appears#

If the application runs but telemetry does not appear:

  • Verify that the Middleware package is installed.
  • Confirm that FlutterOTel.initialize() runs before runApp().
  • Check the account key and ingestion endpoint.
  • Verify that the device can connect to Middleware.
  • Review the Flutter console for SDK initialization or export errors.

Flutter errors are not captured#

  • Verify that FlutterError.onError is configured.
  • Use runZonedGuarded() to capture uncaught asynchronous errors.
  • Alternatively, enable autoCaptureErrors: true.
  • Confirm that errors are reported through FlutterOTel.reportError().

HTTP requests are missing#

  • Confirm that HTTP requests are instrumented manually or use OTelHttpClient.
  • Check whether your networking library uses a separate HTTP implementation.
  • Verify that spans are ended after requests complete.
  • Review exporter logs for failed telemetry uploads.

Backend traces are not correlated#

  • Verify that backend APM instrumentation is enabled.
  • Confirm that the backend supports W3C Trace Context.
  • Check that traceparent headers are propagated with instrumented requests.
  • Ensure that gateways or proxies do not remove tracing headers.

Session Replay is missing#

For Android and iOS:#

  • Confirm that enableSessionRecording is not set to false.
  • Verify that the native Middleware SDK initializes successfully.
  • Check that the application has generated user activity.

For Flutter Web:#

  • Confirm that your application uses FlutterOTel.repaintBoundaryKey.
  • Verify that startSessionRecording() is called.
  • Check that recording is stopped and uploaded correctly.

Android build errors#

  • Verify that compileSdk is 35 or later.
  • Confirm that Kotlin Gradle Plugin 2.0+ is configured.
  • Enable core library desugaring.
  • Check the path_provider_android dependency override.
  • Run flutter clean and reinstall dependencies if required.

iOS build errors#

  • Verify that the deployment target is iOS 13 or later.
  • Run cd ios && pod install.
  • Check CocoaPods static framework linking.
  • Rebuild the iOS project after installing the SDK.

If the issue persists, contact Middleware Support at [email protected].

Need assistance or want to learn more about Middleware? Get in touch with us via our Contact Us or join our Slack channel.

What did you think of this content?