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 iOS-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 iOS, the two parts of the name are resolved as follows:
Screen name: The fully qualified class name where the touch occurred, for example, ViewController for UIKit or ContentView for SwiftUI. 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, UIButton.
touch on UIButton on ViewController
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.
UIKit: The logic is executed in the UIApplication's sendEvent method.
SwiftUI: The logic is executed via a button's action or via the onTapGesture modifier.
For a detailed explanation of action handlers, refer to User interactions.
Use Dynatrace.setAutomaticUserActionDetectionEnabled(Bool) 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.setAutomaticUserActionDetectionEnabled(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 views.
Use Dynatrace.createUserAction(configuration: DTXUserActionConfiguration) to start a user action triggered by the API. Pass a DTXUserActionConfiguration with a custom name that describes the workflow you track. Call complete() when the workflow finishes.
createUserAction always returns a user action, and invalid arguments are handled silently.
let userAction = Dynatrace.createUserAction(configuration:DTXUserActionConfiguration(customName: "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, activate withCompleteAutomatically(true).
let userAction = Dynatrace.createUserAction(configuration:DTXUserActionConfiguration(customName: "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(enabled: 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.
let userAction = Dynatrace.createUserAction(configuration:DTXUserActionConfiguration(customName: "Checkout Process"))userAction.addEventProperty("event_properties.payment_method", value: "credit_card")userAction.addEventProperty("event_properties.cart_value", value: 149.99)userAction.addEventProperty("event_properties.item_count", value: 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 CheckoutViewController while the payment is processed, and closed—with outcome properties attached—in both the success and error paths.
final class CheckoutViewController: UIViewController {// MARK: - Propertiesprivate let cart: Cartprivate let paymentService: PaymentServiceprivate var checkoutAction: DTXUserAction?// MARK: - Private@objc private func checkoutButtonTapped(_ sender: UIButton) {let configuration = DTXUserActionConfiguration(customName: "Checkout Process")checkoutAction = Dynatrace.createUserAction(configuration: configuration)checkoutAction?.addEventProperty("event_properties.cart_id", value: cart.id)checkoutAction?.addEventProperty("event_properties.item_count", value: cart.items.count)checkoutAction?.addEventProperty("event_properties.cart_total", value: cart.total)checkoutAction?.addEventProperty("event_properties.currency", value: cart.currency)paymentService.processPayment(for: cart) { [weak self] result inswitch result {case .success(let order):self?.completeCheckout(orderId: order.id)case .failure(let error):self?.cancelCheckout(reason: error.localizedDescription)}}}private func completeCheckout(orderId: String) {checkoutAction?.addEventProperty("event_properties.order_id", value: orderId)checkoutAction?.addEventProperty("event_properties.checkout_successful", value: true)checkoutAction?.complete()checkoutAction = nil}private func cancelCheckout(reason: String) {checkoutAction?.addEventProperty("event_properties.checkout_successful", value: false)checkoutAction?.addEventProperty("event_properties.cancellation_reason", value: reason)checkoutAction?.complete()checkoutAction = nil}}