A user action represents a significant operation within your app—it groups the requests, navigations, and errors that result from a single user interaction into one event. For a full conceptual overview of how user actions start, end, and what data they capture, see User actions. The sections below cover only Flutter-specific instrumentation details.
Automatic user actions are caused by User interactions with an action handler.
The general naming pattern is described in User actions. On Flutter, the two parts of the name are resolved as follows:
Screen name: The route name registered in the app's route table, for example Home. For unnamed routes, the page widget's class name is used as a fallback. If you set a custom view name via the API, that name is used instead.
Element name: The text content of the tapped element, for example, Checkout. For non-text elements, a Semantics label or Tooltip message is used; otherwise, the widget's class name is used.
touch on Checkout on Home
An action handler is the app code bound to a User interaction that implements the behavior triggered by that interaction. Only user interactions that have an action handler attached can produce a user action.
Flutter: The logic is executed in an onPressed callback.
For a detailed explanation of action handlers, see User interactions.
Use Dynatrace().setAutomaticUserActionDetection(bool) to enable or disable automatic user action detection at runtime. Automatic detection is enabled by default.
When you disable automatic detection, user interactions no longer trigger automatic user action creation. Manual user actions created with createUserAction are not affected.
Dynatrace().setAutomaticUserActionDetection(false);
User actions triggered by the API let you track custom workflows that the agent cannot instrument automatically, such as multi-step business processes, background tasks, or interactions that span multiple screens.
Use Dynatrace().createUserAction(UserActionConfiguration) to start a user action triggered by the API. Pass a UserActionConfiguration with a custom name that describes the workflow you are tracking. Call complete() when the workflow finishes.
createUserAction always returns a user action, and invalid usage (for example, providing an empty custom name) is handled silently.
import 'package:dynatrace_flutter_plugin/dynatrace_flutter_plugin.dart';final userAction = Dynatrace().createUserAction(UserActionConfiguration('Checkout Process'),);// ... perform the workflow ...userAction.complete();
By default, you must call complete() explicitly. If your workflow triggers web requests and you want the user action to close automatically once all in-flight requests finish, pass completeAutomatically: true to UserActionConfiguration.
import 'package:dynatrace_flutter_plugin/dynatrace_flutter_plugin.dart';final userAction = Dynatrace().createUserAction(UserActionConfiguration('Checkout Process', completeAutomatically: true),);// The user action closes on its own once pending requests finish.// You can still call complete() to close it earlier.
You can also change this behavior at any point during the user action's lifetime with setCompleteAutomatically(bool).
Use addEventProperty to attach custom data to the user action. Property keys must be prefixed with event_properties.. Properties added after complete() is called are silently ignored.
For property naming rules and limits, see Event and session properties.
import 'package:dynatrace_flutter_plugin/dynatrace_flutter_plugin.dart';final userAction = Dynatrace().createUserAction(UserActionConfiguration('Checkout Process'),);userAction.addEventProperty('event_properties.payment_method', 'credit_card');userAction.addEventProperty('event_properties.cart_value', 149.99);userAction.addEventProperty('event_properties.item_count', 3);// ... perform the workflow ...userAction.complete();
The following example tracks a checkout workflow as a single user action that spans multiple methods. The action is started in the button handler so that its start time matches the user's selection, kept as a field on the state object while the payment is processed, and closed—with outcome properties attached—in both the success and error paths.
import 'package:dynatrace_flutter_plugin/dynatrace_flutter_plugin.dart';class CheckoutScreen extends StatefulWidget {const CheckoutScreen({required this.cart, super.key});final Cart cart;@overrideState<CheckoutScreen> createState() => _CheckoutScreenState();}class _CheckoutScreenState extends State<CheckoutScreen> {UserAction? _checkoutAction;/// Called when the user taps the "Checkout" button./// createUserAction() is invoked here so that the action start time/// accurately reflects the button tap.Future<void> _onCheckoutButtonTapped() async {final userAction = Dynatrace().createUserAction(UserActionConfiguration('Checkout Process'),);_checkoutAction = userAction;userAction.addEventProperty('event_properties.cart_id', widget.cart.id);userAction.addEventProperty('event_properties.item_count', widget.cart.items.length);userAction.addEventProperty('event_properties.cart_total', widget.cart.total);userAction.addEventProperty('event_properties.currency', widget.cart.currency);await _processPayment();}Future<void> _processPayment() async {try {final result = await PaymentRepository().processPayment(widget.cart);_completeCheckout(orderId: result.orderId);} catch (e) {_cancelCheckout(reason: e.toString());}}void _completeCheckout({required String orderId}) {_checkoutAction?.addEventProperty('event_properties.order_id', orderId);_checkoutAction?.addEventProperty('event_properties.checkout_successful', true);_checkoutAction?.complete();_checkoutAction = null;}void _cancelCheckout({required String reason}) {_checkoutAction?.addEventProperty('event_properties.checkout_successful', false);_checkoutAction?.addEventProperty('event_properties.cancellation_reason', reason);_checkoutAction?.complete();_checkoutAction = null;}@overrideWidget build(BuildContext context) {return Scaffold(body: Center(child: ElevatedButton(onPressed: _onCheckoutButtonTapped,child: const Text('Checkout'),),),);}}