After completing the Flutter Monitoring Setup, use this guide to configure additional agent capabilities. Each section is independent and can be enabled as needed.

Control the Sampling Rate

To manage the volume of data sent to Atatus, set a session sampling rate. The value is a percentage between 0.0 and 100.0, and defaults to 100.0 (every session is kept). Values outside that range are clamped. For example, the following configuration retains 80% of sessions:

copy
icon/buttons/copy
final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
  rumConfiguration: AtatusRumConfiguration(
    sessionSamplingRate: 80.0,
  ),
);

SDK Configuration Options

AtatusConfiguration holds the settings that apply to the whole SDK. licenseKey, env, and appName are required. Everything else has a default:

Option Default Description
licenseKey Required Authenticates the SDK with Atatus.
env Required Environment name reported with every event, such as production or staging.
appName Required Application name reported with every event.
service Not set Service name reported with every event.
version Application version Defaults to the version in your pubspec.yaml, without any build or pre-release part. A + is replaced with -.
nativeCrashReportEnabled false Reports native Android crashes.
customEndpoint Not set Sends all data to a self-hosted collector instead of the default endpoint.
firstPartyHosts [] Hosts that receive tracing headers. See Flutter Distributed Tracing.
firstPartyHostsWithTracingHeaders {} Per-host control over which tracing header formats are sent.
batchSize BatchSize.medium Preferred size of an upload batch: small, medium, or large.
uploadFrequency UploadFrequency.average How often batches are uploaded: frequent, average, or rare.
batchProcessingLevel BatchProcessingLevel.medium How many batches are processed per cycle: low, medium, or high. Higher sends more per cycle and uses more CPU and memory.
rumConfiguration Not set Enables RUM. See RUM Configuration Options.
loggingConfiguration Not set Enables log collection. See Flutter Log Collection.
additionalConfig {} Extra key-value configuration passed through to the underlying native SDK.
Note:

version matters for symbolication. If you upload Flutter symbols or an Android mapping file, the version here must match the version used in the upload, or stack traces are not deobfuscated.

Note:

AtatusConfiguration also accepts sessionPersistence, trackSessionsAcrossSubdomains, useSecureSessionCookie, and usePartitionedCrossSiteSessionCookie. These apply to Flutter Web only and have no effect on Android.

RUM Configuration Options

AtatusRumConfiguration accepts the following options. All of them are optional:

Option Default Description
sessionSamplingRate 100.0 Percentage of sessions kept, from 0.0 to 100.0.
traceSampleRate 100.0 Percentage of tracked resources that carry APM tracing headers.
traceContextInjection TraceContextInjection.sampled Whether tracing headers are injected on all requests or only sampled ones.
detectLongTasks true Reports long-running work on the main Dart isolate.
longTaskThreshold 0.1 Seconds of blocking before work counts as a long task. Minimum 0.02. Ignored on Flutter Web, which always uses 0.05.
trackFrustrations true Detects frustration signals such as error taps.
trackAnonymousUser true Keeps a stable anonymous identifier across sessions.
trackBackgroundEvents false Records events that happen when no view is active, including while the application is in the background, by attaching them to an automatically created background view. This can create additional sessions and affect billing.
vitalUpdateFrequency VitalsFrequency.average How often mobile vitals are sampled: frequent (100ms), average (500ms), or rare (1000ms). Set it to null to disable mobile vitals collection.
reportFlutterPerformance false Reports Flutter build and raster times.
initialResourceThreshold 0.1 Seconds after a view starts during which resources are counted towards Time to Network-Settled.
trackNonFatalAnrs Platform default Android only. Reports application-not-responding events that do not crash the app. Enabled by default on Android API 29 and below, disabled on API 30 and above, where it would create too much noise over fatal ANRs.
appHangThreshold Not set iOS only. Seconds of unresponsiveness before an app hang is reported.
serverUrl Not set Sends RUM data to a self-hosted collector instead of the default endpoint.
additionalConfig {} Extra key-value configuration passed through to the underlying native SDK.
Note:

sessionSamplingRate, traceSampleRate, and longTaskThreshold are clamped to their valid ranges, so a value outside the range is corrected rather than rejected.

Manual Initialization and Error Tracking

By default, the SDK is initialized using the AtatusSdk.runApp wrapper which wraps the Flutter runApp execution. Alternatively, you can initialize the SDK manually. This is useful if you need to run custom asynchronous initialization logic before starting the SDK, or if you want to set up custom error boundaries.

To initialize Atatus manually:

  1. Call WidgetsFlutterBinding.ensureInitialized() first.
  2. Initialize the SDK using AtatusSdk.instance.initialize(...).
  3. Capture unhandled Flutter framework errors using FlutterError.onError.
  4. Capture asynchronous platform errors using PlatformDispatcher.instance.onError.
copy
icon/buttons/copy
import 'dart:ui';
import 'package:atatus_flutter_plugin/atatus_flutter_plugin.dart';
import 'package:flutter/material.dart';

void main() async {
  // 1. Ensure Flutter bindings are initialized
  WidgetsFlutterBinding.ensureInitialized();

  final configuration = AtatusConfiguration(
    licenseKey: '<LICENSE_KEY>',
    env: '<ENV_NAME>',
    appName: '<APP_NAME>',
    nativeCrashReportEnabled: true,
    rumConfiguration: AtatusRumConfiguration(),
  );

  // 2. Initialize the Atatus SDK manually
  await AtatusSdk.instance.initialize(configuration, TrackingConsent.granted);

  // 3. Capture Flutter framework errors
  FlutterError.onError = (FlutterErrorDetails details) {
    FlutterError.presentError(details);
    AtatusSdk.instance.rum?.handleFlutterError(details);
  };

  // 4. Capture asynchronous platform-level errors
  PlatformDispatcher.instance.onError = (Object error, StackTrace stackTrace) {
    AtatusSdk.instance.rum?.addErrorInfo(
      error.toString(),
      RumErrorSource.source,
      stackTrace: stackTrace,
    );
    return false; // Return false to allow the default platform handler to run
  };

  runApp(const MyApp());
}

Customizing Route and View Names

To customize screen names as they appear in the RUM dashboard, or to assign custom attributes to specific routes, use a custom ViewInfoExtractor callback. This is especially helpful if routes use obfuscated class names or dynamic parameters that you wish to standardize.

Using ViewInfoExtractor

Define a route extractor function that inspects the dynamic route and returns a customized RumViewInfo object. You can fall back to the default behavior using defaultViewInfoExtractor(route) for other routes:

copy
icon/buttons/copy
import 'package:atatus_flutter_plugin/atatus_flutter_plugin.dart';
import 'package:flutter/material.dart';

RumViewInfo? customViewInfoExtractor(Route<dynamic> route) {
  final name = route.settings.name;

  if (name == '/product_detail') {
    return RumViewInfo(
      name: 'Product Details Screen',
      attributes: {
        'page_type': 'e-commerce',
      },
    );
  }

  // Fall back to default name extraction for other routes
  return defaultViewInfoExtractor(route);
}

// Pass the extractor to AtatusNavigationObserver
final observer = AtatusNavigationObserver(
  atatusSdk: AtatusSdk.instance,
  viewInfoExtractor: customViewInfoExtractor,
);

Overriding View Info with RouteAware Mixins

For widgets that implement the standard Flutter RouteAware observer lifecycle, you can mix in the AtatusRouteAwareMixin on the widget's State to override the reported name directly inside the view code:

copy
icon/buttons/copy
import 'package:atatus_flutter_plugin/atatus_flutter_plugin.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with RouteAware, AtatusRouteAwareMixin {
  // Override rumViewInfo to specify a custom name and extra attributes
  @override
  RumViewInfo get rumViewInfo => RumViewInfo(
        name: 'Home Dashboard Screen',
        attributes: {'source': 'main_nav'},
      );

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: Text('Home')),
    );
  }
}

Custom Action Labels

For custom widgets where the RumUserActionDetector cannot infer a meaningful label, annotate the widget with a description using RumUserActionAnnotation. This ensures the action appears with a human-readable name in the Atatus dashboard:

copy
icon/buttons/copy
RumUserActionAnnotation(
  description: 'Favorite button',
  child: InkWell(
    onTap: onTap,
    child: const Icon(Icons.favorite),
  ),
);

Track User Sessions

Adding user information to your RUM sessions enables you to follow the journey of a specific user, identify which users are most affected by errors, and monitor performance for your most important users.

Use setUserInfo to associate an identity with all RUM events in the current session:

copy
icon/buttons/copy
AtatusSdk.instance.setUserInfo(
  '1234',
  name: 'John Doe',
  email: 'john@doe.com',
);

The following attributes are available on all RUM events after this call:

Attribute Description
usr.id Unique user identifier
usr.name User display name
usr.email User email address

To clear user information (for example, on sign-out), call clearUserInfo:

copy
icon/buttons/copy
AtatusSdk.instance.clearUserInfo();
Note: setUserInfo requires a non-null id, so it cannot be used to clear the user. Use clearUserInfo instead. Clearing also empties the user attribute on the active session and view. To keep the user on events already collected, stop the session with AtatusSdk.instance.rum?.stopSession() or the view with stopView before clearing.

Add Custom User Attributes

You can attach additional custom attributes to the user session. These attributes are automatically applied to all subsequent RUM events, logs, and traces:

copy
icon/buttons/copy
AtatusSdk.instance.addUserExtraInfo({
  'plan': 'premium',
  'company_id': 'acme-corp',
});

To remove an existing attribute, set its value to null:

copy
icon/buttons/copy
AtatusSdk.instance.addUserExtraInfo({
  'company_id': null,
});

You can also pass these attributes when you set the user, using the extraInfo parameter of setUserInfo.

Track Accounts

For business-to-business applications, you can record the account a user belongs to, alongside the user identity:

copy
icon/buttons/copy
AtatusSdk.instance.setAccountInfo(
  id: 'acme-corp',
  name: 'Acme Corporation',
  extraInfo: {'plan': 'enterprise'},
);

// Add more attributes later
AtatusSdk.instance.addAccountExtraInfo({'seats': 250});

// Clear on sign-out
AtatusSdk.instance.clearAccountInfo();

Set Custom Global Attributes

To attach contextual metadata to every RUM event emitted by the SDK, use global attributes. These are useful for filtering and grouping data in the Atatus dashboard, for example by feature flag, A/B test variant, or store identifier.

copy
icon/buttons/copy
// Add a global attribute
AtatusSdk.instance.rum?.addAttribute('store_id', 'store-42');
AtatusSdk.instance.rum?.addAttribute('ab_test_group', 'variant_b');

// Remove an attribute when no longer needed
AtatusSdk.instance.rum?.removeAttribute('ab_test_group');

To scope attributes to the current view instead of the whole session, use addViewAttribute, addViewAttributes, removeViewAttribute, and removeViewAttributes:

copy
icon/buttons/copy
AtatusSdk.instance.rum?.addViewAttribute('checkout_step', 'payment');
AtatusSdk.instance.rum?.removeViewAttribute('checkout_step');

Manually Track User Actions

The RumUserActionDetector widget captures common tap interactions automatically. For interactions it cannot detect, such as programmatic triggers, long presses, or scroll events, use manual action tracking.

Instantaneous Actions

For discrete actions (taps, clicks), use addAction:

copy
icon/buttons/copy
void _onDownloadTapped(String resourceName) {
  AtatusSdk.instance.rum?.addAction(
    RumActionType.tap,
    resourceName,
  );
}

Continuous Actions

For time-bound actions (scrolls, swipes), use startAction and stopAction:

copy
icon/buttons/copy
void _onScrollStart() {
  AtatusSdk.instance.rum?.startAction(
    RumActionType.scroll,
    'Product List Scroll',
  );
}

void _onScrollEnd() {
  AtatusSdk.instance.rum?.stopAction(
    RumActionType.scroll,
    'Product List Scroll',
  );
}
Note: When using startAction and stopAction, the type parameter must be the same in both calls for the SDK to match the start and end of the action.

Manually Track Custom Resources

In addition to the automatic resource tracking provided by the Dio interceptor and the Atatus Tracking HTTP Client, you can manually track network requests or third-party API calls that are not covered by automatic instrumentation.

copy
icon/buttons/copy
// Start tracking a resource
AtatusSdk.instance.rum?.startResource(
  'resource-key',
  RumHttpMethod.get,
  'https://api.example.com/data',
);

// On successful completion
AtatusSdk.instance.rum?.stopResource(
  'resource-key',
  200,
  RumResourceType.fetch,
);

If the resource request fails, report the error using stopResourceWithErrorInfo, which takes a message and an error type:

copy
icon/buttons/copy
AtatusSdk.instance.rum?.stopResourceWithErrorInfo(
  'resource-key',
  'Connection timed out',
  'network',
);

If you are holding the caught Exception, pass it to stopResourceWithError instead:

copy
icon/buttons/copy
try {
  // ...
} on Exception catch (e) {
  AtatusSdk.instance.rum?.stopResourceWithError('resource-key', e);
}
Note: The key string must be unique for each resource and must be the same in the startResource and corresponding stopResource, stopResourceWithErrorInfo, or stopResourceWithError calls.
Note: The resourceKey string must be unique for each resource and must be the same in the startResource and corresponding stopResource or stopResourceWithError calls.

Custom Performance Timings

Measure custom performance milestones within a view using addTiming. The timing is recorded relative to the start of the current RUM view, making it ideal for tracking content render times, hero image loads, or any application-specific milestone.

copy
icon/buttons/copy
void _onHeroImageLoaded() {
  AtatusSdk.instance.rum?.addTiming('hero_image');
}

void _onContentRendered() {
  AtatusSdk.instance.rum?.addTiming('content_rendered');
}

After the timing is set, it is accessible as @view.custom_timings.<timing_name> (for example, @view.custom_timings.hero_image). Use these values to create custom measures and visualizations in the Atatus dashboard.

Track Feature Flags

Record which variant of a feature flag a user saw, so you can compare errors and performance between variants:

copy
icon/buttons/copy
AtatusSdk.instance.rum?.addFeatureFlagEvaluation('new_checkout', true);
AtatusSdk.instance.rum?.addFeatureFlagEvaluation('pricing_page', 'variant_b');

The evaluation is attached to the current view and to the events collected in it.

Track Feature Operations

Feature operations measure a business workflow that can succeed or fail, such as a checkout or an onboarding flow:

copy
icon/buttons/copy
AtatusSdk.instance.rum?.startFeatureOperation('checkout');

// On success
AtatusSdk.instance.rum?.succeedFeatureOperation('checkout');

// On failure
AtatusSdk.instance.rum?.failFeatureOperation(
  'checkout',
  RumFeatureOperationFailureReason.error,
);

The failure reason is one of RumFeatureOperationFailureReason.error (an error during execution), .abandoned (the user or process gave up), or .other.

Pass operationKey when several instances of the same operation can run at once, and attributes to attach context to the operation.

Manual View Tracking

The AtatusNavigationObserver cannot see every kind of navigation, such as a custom navigator or a widget that swaps content in place. In those cases, start and stop views yourself:

copy
icon/buttons/copy
AtatusSdk.instance.rum?.startView('checkout-screen', 'Checkout');

// When the user leaves
AtatusSdk.instance.rum?.stopView('checkout-screen');

The key must be the same in both calls. If you omit the name, the key is used as the view name.

Stop the Current Session

Use stopSession to end the active RUM session. The next user interaction starts a new one. This is useful at sign-out, when you want the next session to be attributed to a different user:

copy
icon/buttons/copy
AtatusSdk.instance.rum?.stopSession();

Modify or Drop RUM Events

To modify the attributes of a RUM event before it is sent to Atatus, or to drop an event entirely, use Event Mappers during SDK configuration. Each mapper is a function with the signature (T) → T? where T is a concrete RUM event type. Returning null from a mapper drops the event.

copy
icon/buttons/copy
final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
  rumConfiguration: AtatusRumConfiguration(
    viewEventMapper: (event) => event,
    actionEventMapper: (event) => event,
    resourceEventMapper: (event) {
      // Redact sensitive URL segments before sending
      event.resource.url = redactUrl(event.resource.url);
      return event;
    },
    errorEventMapper: (event) => event,
    longTaskEventMapper: (event) => event,
    vitalOperationStepEventMapper: (event) => event,
  ),
);
Important: The view event mapper must not return null. Returning null from the error, resource, or action mappers drops the event entirely, so it is not sent to Atatus.

The following event properties can be modified:

Event Type Modifiable Properties
View view.url, view.referrer
Action action.target.name, view.referrer, view.url
Error error.message, error.stack, error.resource.url, view.referrer, view.url
Resource resource.url, view.referrer, view.url

Retrieve the RUM Session ID

Retrieving the current RUM session ID is helpful for troubleshooting. You can attach it to support tickets, bug reports, or internal logs to correlate user-reported issues with the corresponding session in the Atatus dashboard.

copy
icon/buttons/copy
final sessionId = await AtatusSdk.instance.rum?.getCurrentSessionId();

Clear All Data

Use clearAllData to wipe all locally queued data that has not yet been transmitted to Atatus. This is useful for implementing user data deletion requests or clearing state after a user logs out.

copy
icon/buttons/copy
AtatusSdk.instance.clearAllData();

Track Work in a Background Isolate

The SDK is initialized in your root isolate. Work running in a background isolate does not see it, so requests and errors from there are not reported until you attach:

copy
icon/buttons/copy
await AtatusSdk.instance.attachToBackgroundIsolate();

Call this inside the background isolate, after the SDK has been initialized in your root isolate.

Warning:

If Atatus has not finished initializing in the root isolate when you call this, the call fails silently. Nothing is reported from the isolate and no error is logged, so initialize first and attach second.

Attach to an Existing Native SDK

If your Flutter code runs inside an existing Android application that already initializes the native Atatus SDK, do not initialize the SDK again from Dart. Attach to the running instance instead:

copy
icon/buttons/copy
await AtatusSdk.instance.attachToExisting(
  AtatusAttachConfiguration(
    detectLongTasks: true,
    longTaskThreshold: 0.1,
    traceSampleRate: 100.0,
    reportFlutterPerformance: false,
    firstPartyHosts: ['api.example.com'],
  ),
);

AtatusAttachConfiguration covers only the Dart side of the SDK. Settings that belong to the native SDK, such as the license key, the environment, and the sample rate, keep the values the host application set.

Logs and RUM are enabled on the Dart side only if the native SDK already has them enabled.

Extend the SDK with Plugins

Plugins let a package hook into the SDK lifecycle. The network integrations use this mechanism, which is why enableHttpTracking() is a call on the configuration rather than on the SDK.

Add a plugin when you build your configuration:

copy
icon/buttons/copy
final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
)..addPlugin(MyPluginConfiguration());

Retrieve a plugin later by its type:

copy
icon/buttons/copy
final plugin = AtatusSdk.instance.getPlugin<MyPlugin>();

To write one, implement AtatusPluginConfiguration with a create method that returns your AtatusPlugin. The plugin's initialize method runs once the SDK is ready, and shutdown runs when it stops.

Note:

Only one plugin of each runtime type is allowed. Adding a second of the same type is ignored, and an error is logged.

Flutter-Specific Performance Metrics

To enable the collection of Flutter-specific rendering metrics, meaning widget build times and raster (frame render) times, set reportFlutterPerformance to true on AtatusRumConfiguration. These metrics are displayed in the Mobile Vitals section of the Atatus dashboard.

copy
icon/buttons/copy
final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
  rumConfiguration: AtatusRumConfiguration(
    reportFlutterPerformance: true,
  ),
);

Session Replay

Session Replay records what the user saw and did, and links the recording to its RUM session. It ships as a separate package, atatus_session_replay, and is enabled with enableSessionReplay on your AtatusConfiguration:

copy
icon/buttons/copy
final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
  rumConfiguration: AtatusRumConfiguration(),
)..enableSessionReplay(
    AtatusSessionReplayConfiguration(replaySampleRate: 30.0),
  );

Replay also needs a SessionReplayCapture widget at the root of your widget tree. For the full setup, the privacy levels, and per-widget masking, see Flutter Session Replay.

Log Correlation

The Atatus SDK supports sending structured log messages from your Flutter application and correlating them with RUM sessions. When log correlation is enabled, each log entry is automatically linked to the active RUM view and session, providing full context during incident investigation.

For detailed setup instructions, see Flutter Log Collection.

To comply with GDPR and similar data protection regulations, the SDK requires a tracking consent value at initialization. Three values are available:

  • TrackingConsent.pending: the SDK collects and batches data locally but does not transmit it until consent is updated.
  • TrackingConsent.granted: the SDK collects data and transmits it to Atatus.
  • TrackingConsent.notGranted: the SDK does not collect any data.

Update the consent value at any time after initialization:

copy
icon/buttons/copy
AtatusSdk.instance.setTrackingConsent(TrackingConsent.granted);

Sending Data When the Device Is Offline

RUM data is batched and stored locally on the device when no network connection is available. The SDK uploads all stored data automatically once connectivity is restored. No additional configuration is required. This ensures complete data capture regardless of network conditions.