Try it free

User action instrumentation

  • Latest Dynatrace
  • How-to guide
  • Published Jun 29, 2026

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 Android-specific instrumentation details.

Automatic instrumentation

Automatic user actions are caused by User interactions with an action handler.

User action names

The general naming pattern is described in User actions. On Android, the two parts of the name are resolved as follows:

Screen name: The fully qualified class name of the Activity where the touch occurred, for example, com.example.MainActivity. If you set a custom view name via the API, that name is used instead.

Element name: The agent uses the component type name of the element that handled the selection, for example, Button or MaterialCardView.

touch on Button on com.example.MainActivity

Action handler examples

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.

Android View: The logic is executed in an OnClickListener.

Jetpack Compose: The logic is executed via the clickable modifier.

For a detailed explanation of action handlers, see User interactions.

Configure automatic instrumentation

Use Dynatrace.setAutomaticUserActionDetection(boolean) to activate or deactivate automatic user action detection at runtime. Automatic detection is active by default.

When you deactivate automatic detection, user interactions no longer trigger automatic user action creation. Manual user actions created with createUserAction are not affected.

Dynatrace.setAutomaticUserActionDetection(false)
Dynatrace.setAutomaticUserActionDetection(false);

Manual instrumentation

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.

Create a user action

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.

val userAction = Dynatrace.createUserAction(
UserActionConfiguration("Checkout Process")
)
// ... perform the workflow ...
userAction.complete()
UserAction userAction = Dynatrace.createUserAction(
new UserActionConfiguration("Checkout Process")
);
// ... perform the workflow ...
userAction.complete();

Automatic completion

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, activate withCompleteAutomatically(true).

val userAction = Dynatrace.createUserAction(
UserActionConfiguration("Checkout Process")
.withCompleteAutomatically(true)
)
// The user action closes on its own once pending requests finish.
// You can still call complete() to close it earlier.
UserAction userAction = Dynatrace.createUserAction(
new UserActionConfiguration("Checkout Process")
.withCompleteAutomatically(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(boolean).

Add event properties

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.

val 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()
UserAction userAction = Dynatrace.createUserAction(
new 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();

Example: E-commerce checkout flow

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 ViewModel while the payment is processed, and closed—with outcome properties attached—in both the success and error paths.

class CheckoutViewModel(
private val paymentRepository: PaymentRepository
) : ViewModel() {
private var checkoutAction: UserAction? = null
// Called from the UI layer when the user taps the "Checkout" button.
fun onCheckoutButtonClicked(cart: Cart) {
checkoutAction = Dynatrace.createUserAction(
UserActionConfiguration("Checkout Process")
).apply {
addEventProperty("event_properties.cart_id", cart.id)
addEventProperty("event_properties.item_count", cart.items.size)
addEventProperty("event_properties.cart_total", cart.total)
addEventProperty("event_properties.currency", cart.currency)
}
processPayment(cart)
}
private fun processPayment(cart: Cart) {
viewModelScope.launch {
try {
val result = paymentRepository.processPayment(cart)
completeCheckout(orderId = result.orderId)
} catch (e: Exception) {
cancelCheckout(reason = e.message ?: "unknown_error")
}
}
}
private fun completeCheckout(orderId: String) {
checkoutAction?.let {
it.addEventProperty("event_properties.order_id", orderId)
it.addEventProperty("event_properties.checkout_successful", true)
it.complete()
}
checkoutAction = null
}
private fun cancelCheckout(reason: String) {
checkoutAction?.let {
it.addEventProperty("event_properties.checkout_successful", false)
it.addEventProperty("event_properties.cancellation_reason", reason)
it.complete()
}
checkoutAction = null
}
}
public class CheckoutViewModel extends ViewModel {
private final PaymentRepository paymentRepository;
private UserAction checkoutAction = null;
public CheckoutViewModel(PaymentRepository paymentRepository) {
this.paymentRepository = paymentRepository;
}
// Called from the UI layer when the user taps the "Checkout" button.
public void onCheckoutButtonClicked(Cart cart) {
checkoutAction = Dynatrace.createUserAction(
new UserActionConfiguration("Checkout Process")
);
checkoutAction.addEventProperty("event_properties.cart_id", cart.getId());
checkoutAction.addEventProperty("event_properties.item_count", cart.getItems().size());
checkoutAction.addEventProperty("event_properties.cart_total", cart.getTotal());
checkoutAction.addEventProperty("event_properties.currency", cart.getCurrency());
processPayment(cart);
}
private void processPayment(Cart cart) {
paymentRepository.processPayment(cart, new PaymentCallback() {
@Override
public void onSuccess(PaymentResult result) {
completeCheckout(result.getOrderId());
}
@Override
public void onError(String errorMessage) {
cancelCheckout(errorMessage != null ? errorMessage : "unknown_error");
}
});
}
private void completeCheckout(String orderId) {
if (checkoutAction != null) {
checkoutAction.addEventProperty("event_properties.order_id", orderId);
checkoutAction.addEventProperty("event_properties.checkout_successful", true);
checkoutAction.complete();
checkoutAction = null;
}
}
private void cancelCheckout(String reason) {
if (checkoutAction != null) {
checkoutAction.addEventProperty("event_properties.checkout_successful", false);
checkoutAction.addEventProperty("event_properties.cancellation_reason", reason);
checkoutAction.complete();
checkoutAction = null;
}
}
}
Related tags
Digital Experience