---
title: "Flutter"
description: "Set up Middleware RUM for Flutter applications to track user interactions and monitor performance."
section: "RUM"
breadcrumb: "RUM > Mobile > Flutter"
canonical: "https://docs.middleware.io/get-started/rum/flutter"
---
# Flutter

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.29.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:

| Platform | Requirements |
| --- | --- |
| Android | `compileSdk` 35+, Kotlin Gradle Plugin 2.0+, core library desugaring |
| iOS | iOS 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`:

```yml
dependencies:
  flutter:
    sdk: flutter
  middleware_flutter_opentelemetry: ^2.2.3
```

Install the dependencies:

```bash
flutter pub get
```

For iOS, add the Middleware specs repo and the CocoaPods CDN to the top of `ios/Podfile`:

```ruby
source 'https://github.com/middleware-labs/cocoapods-specs.git'
source 'https://cdn.cocoapods.org/'
```

Keep both sources: new `MiddlewareRum` versions are published to the Middleware repo, and the SDK's dependencies still come from the CocoaPods CDN. CocoaPods trunk stops accepting new pods on December 2, 2026, so without the Middleware source your app stays on the last version published to trunk.

Then install the native pods:

```bash
cd ios
pod install
cd ..
```

**Note**: If you're upgrading from an earlier SDK version, run `pod update MiddlewareRum` in `ios/` instead of `pod install`. The SDK needs `MiddlewareRum` 2.3.1 or later, and `pod install` fails when `Podfile.lock` pins an older version.

#### 3 Initialize Middleware

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

```js
import 'package:flutter/material.dart';
import 'package:middleware_flutter_opentelemetry/middleware_flutter_opentelemetry.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await FlutterOTel.initialize(
    serviceName: 'my-flutter-app',
    serviceVersion: '1.0.0',
    tracerName: 'main',
    middlewareAccountKey: '<MW_ACCOUNT_KEY>',
    endpoint: 'https://<MW_UID>.middleware.io',
    resourceAttributes: OTel.attributesFromMap({
      'env': 'production',
      'service.namespace': 'mobile-apps',
    }),
  );

  runApp(const MyApp());
}
```

Replace the placeholders with your Middleware credentials.

| Parameter | Required | Description |
| --- | --- | --- |
| `serviceName` | Yes | Name used to identify your Flutter application |
| `serviceVersion` | No | Application version |
| `tracerName` | No | Name of the OpenTelemetry tracer |
| `middlewareAccountKey` | Yes | Middleware account key |
| `endpoint` | Yes | Middleware ingestion endpoint |
| `resourceAttributes` | No | Additional attributes such as environment or namespace |

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

Flutter and platform errors are captured automatically (`autoCaptureErrors`, on by default). Error handlers you set before `initialize()` keep running. To report errors you catch yourself, call `FlutterOTel.reportError()`.

To track navigation, add the route observer. For GoRouter:

```js
final router = GoRouter(
  observers: [FlutterOTel.routeObserver],
  routes: [ /* ... */ ],
);
```

For `Navigator`:

```js
MaterialApp(
  navigatorObservers: [FlutterOTel.routeObserver],
  // ...
);
```

#### 4 Run and verify

Run your Flutter application:

```bash
flutter 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](https://docs.middleware.io/features/rum/session-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

On Android and iOS, Session Replay uses the embedded native Middleware SDKs.

Recording starts automatically when Middleware initializes.

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

#### Flutter Web

For Flutter Web, the SDK uses a Dart-based recorder. It starts by itself after the first frame and captures the whole app, so no widget wrapping is needed.

To record only part of the UI, wrap it in a `RepaintBoundary` with the SDK key:

```js
RepaintBoundary(
  key: FlutterOTel.repaintBoundaryKey,
  child: const MyApp(),
)
```

#### Turn recording off or on

To disable Session Replay:

```js
await FlutterOTel.initialize(
  serviceName: 'my-flutter-app',
  middlewareAccountKey: '<MW_ACCOUNT_KEY>',
  endpoint: 'https://<MW_UID>.middleware.io',
  enableSessionRecording: false,
);
```

To pause and resume recording at runtime:

```js
await FlutterOTel.stopSessionRecording();
await FlutterOTel.startSessionRecording();
```

On Android and iOS, both calls stay in effect across new sessions until you call the other one, and `startSessionRecording()` also overrides `enableSessionRecording: false`. You can use this to record only a specific flow, such as checkout. On Flutter Web, `enableSessionRecording: false` turns the recorder off completely.

### 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

The SDK records HTTP requests automatically, with request duration, response status, and errors.

- **Android and iOS**: every request made through `dart:io`, including `package:http` and `dio`, gets an HTTP span and trace headers. No client wrapping is needed. Clients created before `FlutterOTel.initialize()` aren't covered.
- **Flutter Web**: the browser instrumentation records `fetch` and `XMLHttpRequest` requests.

To turn off automatic HTTP capture on Android and iOS, set `enableAutomaticNetworkInstrumentation: false`.

## Configure distributed tracing

Distributed tracing connects Flutter HTTP requests with backend APM traces.

On Android and iOS, the SDK adds W3C Trace Context (`traceparent`) and B3 (`b3`, `x-b3-*`) headers to traced requests. On Flutter Web, trace headers are added to same-origin requests; add other backends with `webInstrumentation: WebInstrumentationOptions(tracePropagationTargets: [...])`.

### Prerequisites

- Your backend must have Middleware APM instrumentation enabled.
- The backend must support W3C Trace Context or B3.
- On Flutter Web, cross-origin backends must allow the trace headers in their CORS policy.

### 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

```js
ElevatedButton(
  onPressed: handleSubmit,
  child: const Text('Submit'),
).withOTelButtonTracking('submit_form');
```

### Track text field interactions

```js
TextField(
  decoration: const InputDecoration(
    labelText: 'Enter something',
  ),
).withOTelTextFieldTracking('demo_text_field');
```

### Add an error boundary

```js
RiskyWidget().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.

`SpanStatusCode` comes from `middleware_dart_opentelemetry`, which the Flutter SDK already uses. Add it as a direct dependency so you can import it:

```bash
flutter pub add middleware_dart_opentelemetry
```

```js
import 'package:middleware_dart_opentelemetry/middleware_dart_opentelemetry.dart'
    show SpanStatusCode;
import 'package:middleware_flutter_opentelemetry/middleware_flutter_opentelemetry.dart';

final tracer = FlutterOTel.tracer;

final span = tracer.startSpan(
  'checkout',
  attributes: OTel.attributesFromMap({
    'operation': 'payment',
    'screen': 'checkout',
  }),
);

try {
  await processPayment();

  span.setStatus(SpanStatusCode.Ok);
} catch (error, stackTrace) {
  span.recordException(error, stackTrace: stackTrace);
  span.setStatus(SpanStatusCode.Error, error.toString());
  rethrow;
} finally {
  span.end();
}
```

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:

```bash
flutter run \
  --dart-define=OTEL_SERVICE_NAME=my-flutter-app \
  --dart-define=OTEL_SERVICE_VERSION=1.0.0 \
  --dart-define=OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector:4317 \
  --dart-define=OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
  --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

Common parameters accepted by `FlutterOTel.initialize()`:

| Parameter | Description |
| --- | --- |
| `serviceName` | Application service name |
| `serviceVersion` | Application version |
| `tracerName` | OpenTelemetry tracer name |
| `middlewareAccountKey` | Middleware account key |
| `endpoint` | Middleware ingestion endpoint |
| `resourceAttributes` | Custom resource attributes |
| `autoCaptureErrors` | Registers Flutter and platform error handlers. On by default |
| `enableSessionRecording` | Enables or disables Session Replay. On by default |
| `enableAutomaticNetworkInstrumentation` | Records HTTP requests on Android and iOS. On by default |

## 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

- Confirm that `autoCaptureErrors` is not set to `false`.
- If you set `FlutterError.onError` or `PlatformDispatcher.instance.onError` after `initialize()`, it replaces the SDK handler. Set your handlers before `initialize()`, or call `FlutterOTel.reportError()` from them.
- Report errors you catch yourself through `FlutterOTel.reportError()`.

### HTTP requests are missing

- Confirm that `enableAutomaticNetworkInstrumentation` is not set to `false`.
- Create HTTP clients after `FlutterOTel.initialize()`. Clients created earlier aren't traced.
- Check whether your networking library uses its own HTTP stack instead of `dart:io`, such as a native platform client.
- 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 `enableSessionRecording` is not set to `false`.
- Check that your code doesn't call `stopSessionRecording()` before the session ends.
- If you wrap part of the UI with `FlutterOTel.repaintBoundaryKey`, only that part is recorded.

#### Android build errors

- Verify that `compileSdk` is 35 or later.
- Confirm that Kotlin Gradle Plugin 2.0+ is configured.
- Enable core library desugaring.
- 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`.
- If CocoaPods can't find or upgrade `MiddlewareRum`, check both sources are in your Podfile and run `pod update MiddlewareRum`.
- Check CocoaPods static framework linking.
- Rebuild the iOS project after installing the SDK.

If the issue persists, contact Middleware Support at support@middleware.io.

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