The SDK instruments your application automatically once RUM is enabled, but automatic instrumentation can only infer what it observes through lifecycle callbacks and the OkHttp interceptor chain. This page covers the APIs that let you emit events the instrumentation cannot derive, attach domain context to the events it already produces, and govern what leaves the device.
If you have not set up the SDK yet, start with Android Monitoring Setup.
Enrich user sessions
Views, interactions, resources, and errors are captured automatically through lifecycle hooks and interceptors, which covers the common case without any code of your own. Reach for the GlobalRumMonitor API when your architecture hides activity from that instrumentation, or when an event needs to carry domain context the SDK has no way to infer.
Custom views
A view represents a screen in the session timeline and acts as the parent for every action, resource, and error recorded while it is active. Start and stop it from the lifecycle callbacks that match its visibility, normally onResume() and onPause().
override fun onResume() {
super.onResume()
GlobalRumMonitor.get().startView(viewKey, viewName, viewAttributes)
}
override fun onPause() {
GlobalRumMonitor.get().stopView(viewKey, viewAttributes)
super.onPause()
}
Pass the same viewKey to both calls. Atatus pairs the start and stop events by that key to derive the view's duration, and an unmatched key leaves the view open until the session ends.
Custom actions
An action records a discrete user interaction and is attributed to the view that is active when it fires. Use addAction for instantaneous interactions such as taps and clicks, and startAction with stopAction for continuous ones such as scrolls, where the elapsed duration is part of the signal.
GlobalRumMonitor.get().addAction(RumActionType.TAP, "checkout_button", actionAttributes)
Valid action types are CUSTOM, CLICK, TAP, SCROLL, SWIPE, and BACK. The type drives how the action is aggregated in your dashboard, so prefer the specific type over CUSTOM where one applies.
Custom resources
A resource records a network request or any other asynchronous load, carrying its method, URL, status code, and transfer size. Track one manually when the request bypasses the OkHttp interceptor, as with a third-party SDK that ships its own HTTP client.
GlobalRumMonitor.get().startResource(resourceKey, method, url, resourceAttributes)
// When the request completes
GlobalRumMonitor.get().stopResource(
key = resourceKey,
kind = RumResourceKind.NATIVE,
statusCode = 200,
size = null,
attributes = emptyMap()
)
Call stopResourceWithError in place of stopResource when the load fails. The resource is then correlated with an error event rather than recorded as a completed request, which keeps your failure rate accurate.
Custom errors
addError reports a handled exception as a RUM error event attributed to the active view and session. Supply the Throwable whenever one is available, because Atatus derives both the stack trace and the issue grouping from it.
GlobalRumMonitor.get().addError(
message = "Payment failed",
source = RumErrorSource.SOURCE,
throwable = throwable,
attributes = mapOf("order.id" to orderId)
)
Add context to sessions
Every event carries a set of default attributes describing the device, OS, app version, and network state. Layering your own identifiers and business dimensions on top is what makes a session queryable by the terms your team actually investigates, such as plan tier, merchant, or feature flag.
Identify users
User information is attached to the session and propagates to every event it contains, which lets you trace one person's journey and quantify who a regression affects. Set it as soon as identity is known, typically after authentication resolves.
Atatus.setUserInfo("1234", "John Doe", "john@doe.com")
| Attribute | Required | Description |
|---|---|---|
usr.id |
Yes | Stable unique identifier for the user. |
usr.name |
No | Display name, surfaced in the Atatus UI. |
usr.email |
No | Email, surfaced when no name is set. |
Extend the user record at any point without resetting the identifiers already in place:
Atatus.addUserProperties(mapOf("plan" to "enterprise"))
Track attributes
Global attributes are merged into every RUM event emitted after they are set, making them the right place for context that applies across a whole flow rather than a single call. Remove an attribute once it falls out of scope so later events are not tagged with stale state.
GlobalRumMonitor.get().addAttribute("cart.value", 99.90)
GlobalRumMonitor.get().removeAttribute("cart.value")
Track views automatically
The view tracking strategy determines which component boundary the SDK treats as a screen transition. Choose the one that matches your navigation architecture, since a mismatch produces either duplicate views or screens that never close.
| Strategy | Use it when |
|---|---|
ActivityViewTrackingStrategy |
Each activity is a screen. This is the default. |
FragmentViewTrackingStrategy |
Each fragment is a screen. |
MixedViewTrackingStrategy |
Activities and fragments are both screens. |
NavigationViewTrackingStrategy |
You use Jetpack Navigation. Each destination is a screen. |
val rumConfiguration = RumConfiguration.Builder()
.useViewTrackingStrategy(FragmentViewTrackingStrategy(trackExtras = true))
.build()
Supply a ComponentPredicate to exclude components from tracking or to override the name a view is reported under:
val rumConfiguration = RumConfiguration.Builder()
.useViewTrackingStrategy(
ActivityViewTrackingStrategy(
trackExtras = true,
componentPredicate = object : ComponentPredicate<Activity> {
override fun accept(component: Activity) = component !is SplashActivity
override fun getViewName(component: Activity): String? = null
}
)
)
.build()
Returning null from getViewName falls back to the component's canonical class name. If you configure no strategy at all, automatic view detection is disabled and every view must be emitted through startView and stopView.
Track network requests
AtatusInterceptor sits in the OkHttp interceptor chain and reports each matching request as a RUM resource, correlated with the view that issued it. The options below extend what that interceptor records beyond the default method, URL, status code, and duration.
Capture request timings
An EventListener factory exposes OkHttp's connection-level instrumentation, adding DNS resolution, TCP and TLS handshake, and time to first byte to each resource. These phases are what separate a slow server from a slow network when you investigate a latency regression.
val tracedHosts = listOf("api.example.com")
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AtatusInterceptor.Builder(tracedHosts).build())
.eventListenerFactory(AtatusEventListener.Factory())
.build()
Capture request headers
Header capture records request and response headers on the resource event, which is often the fastest way to confirm a caching or content negotiation problem in production. Headers are recorded under resource.request.headers and resource.response.headers.
val interceptor = AtatusInterceptor.Builder(tracedHosts)
.trackResourceHeaders()
.build()
Called with no arguments, the interceptor captures a conservative default set chosen to avoid credentials:
| Direction | Headers |
|---|---|
| Request | cache-control, content-type |
| Response | age, cache-control, content-encoding, content-length, content-type, etag, expires, server-timing, vary, x-cache |
Do not extend this list with headers that carry credentials, such as authorization or cookie. Captured headers are persisted with the event and readable by anyone with access to your dashboard.
Add attributes to requests
A RumResourceAttributesProvider is invoked for every tracked request and returns attributes merged into that resource event. It receives the request, the response when one arrived, and the throwable when the call failed, so you can tag resources with routing, tenancy, or retry context drawn from the call itself.
val interceptor = AtatusInterceptor.Builder(tracedHosts)
.setRumResourceAttributesProvider(
object : RumResourceAttributesProvider {
override fun onProvideAttributes(
request: HttpRequestInfo,
response: HttpResponseInfo?,
throwable: Throwable?
): Map<String, Any?> = mapOf("request.kind" to request.method)
}
)
.build()
Track long tasks
A long task is a unit of work that occupies the main thread beyond a configured threshold, blocking frame rendering and input dispatch for its duration. Each one is reported with its duration and the view that was active, which points you at the screens where jank originates.
val rumConfiguration = RumConfiguration.Builder()
.trackLongTasks(durationThreshold = 250L)
.build()
The threshold defaults to 100 ms. Raise it if your baseline produces more events than you can act on, and lower it when you are hunting dropped frames specifically.
Modify or drop events
Event mappers run on each event after it is built and before it is serialized into an upload batch, giving you a final interception point on the device. Use them to redact identifiers from URLs and messages, or to return null and discard an event entirely.
val rumConfiguration = RumConfiguration.Builder()
.setViewEventMapper(viewEventMapper)
.setActionEventMapper(actionEventMapper)
.setResourceEventMapper(resourceEventMapper)
.setErrorEventMapper(errorEventMapper)
.setLongTaskEventMapper(longTaskEventMapper)
.build()
Each event type exposes a fixed set of writable fields. Mutations outside this set are discarded, because the remaining fields anchor the event to its session and view:
| Event type | Editable fields |
|---|---|
ViewEvent |
view.name, view.url, view.referrer |
ActionEvent |
action.target.name, plus the view fields |
ErrorEvent |
error.message, error.stack, error.resource.url, plus the view fields |
ResourceEvent |
resource.url, plus the view fields |
LongTaskEvent |
The view fields |
Returning null drops the event. View events and crash error events are exempt, since discarding them would break session continuity and hide fatal failures.
Manage stored data
Events are written to batch files on disk and retained until they upload successfully or expire, which is what keeps data intact across offline periods and process death. These two calls give you direct control over that buffer.
Purge every batch that has not yet been uploaded, for example when a user signs out and their pending data should not be transmitted:
Atatus.clearAllData()
Halt collection and uploading for the current SDK instance:
Atatus.stopInstance()
Get the current session ID
The session ID is the join key between a user's report and the session recorded in Atatus. Resolving it at runtime lets you embed it in support tickets, in-app bug reports, or your own logs so an investigation starts from the exact session.
GlobalRumMonitor.get().getCurrentSessionId { sessionId ->
currentSessionId = sessionId
}
The value is delivered through a callback because the session may still be initializing when you ask. It changes whenever a new session begins, so read it at the moment you need it rather than caching it.
Initialization reference
The two builders below define the SDK's behavior at startup and cannot be changed afterwards. Options relevant to a specific task are covered in the sections above.
Configuration.Builder
Governs transport, storage, and crash handling for the SDK instance as a whole. These settings apply to every feature you enable, including RUM, logs, and traces.
| Method | Description |
|---|---|
setBatchSize(SMALL | MEDIUM | LARGE) |
Target size of each upload batch. Smaller batches upload more frequently. |
setUploadFrequency(FREQUENT | AVERAGE | RARE) |
Interval at which pending batches are uploaded. |
setCrashReportsEnabled(Boolean) |
Reports uncaught JVM exceptions. Enabled by default. |
setBackpressureStrategy(BackPressureStrategy) |
Behavior when the SDK's internal task queues reach capacity. |
setProxy(...) |
Routes uploads through an HTTP proxy. |
setEncryption(Encryption) |
Applies an encryption layer to batches stored on disk. |
RumConfiguration.Builder
Governs what the RUM feature collects and at what rate. Each option maps to a category of event in your dashboard.
| Method | Description |
|---|---|
trackUserInteractions() |
Instruments taps, scrolls, and swipes. |
useViewTrackingStrategy(strategy) |
Sets the component boundary treated as a screen. |
trackLongTasks(durationThreshold) |
Reports main-thread work exceeding the threshold. |
trackBackgroundEvents(Boolean) |
Collects events recorded while no view is active. Disabled by default. |
trackFrustrations(Boolean) |
Detects frustration signals such as rage taps. |
trackNonFatalAnrs(Boolean) |
Reports ANRs the application recovers from. |
setSessionSampleRate(Float) |
Percentage of sessions retained, from 0f to 100f. |
setViewEventMapper(...) and the other mappers |
Rewrites or discards events before serialization. |
Next steps
- Report crashes and deobfuscate release stack traces with Error Tracking.
- Measure what the SDK costs your application in SDK Performance Impact.
+1-415-800-4104