Skip to content
TraceItX Docs
Documentation

Screen tracking

Activity transitions are automatic. Modern single-Activity apps see one screen unless you mark the rest.

Updated

Once TraceItX.start() has run, the SDK records each onResume, using the Activity’s simple class name.

That is the whole automatic story — and on a single-Activity app it means one screen for the entire session, which is most modern apps. The rest is one line per screen.

Compose

Works with NavHost, state-based routing, Voyager and Decompose:

import com.traceitx.TXScreen

@Composable
fun CheckoutScreen(…) {
    TXScreen(name = "Checkout")

}

In pagers and other keep-alive containers, off-screen pages stay composed — pass active so the marker fires on selection rather than composition:

TXScreen(name = "Checkout", active = pagerState.currentPage == page)

Without it, a three-tab pager records all three screens once at startup and nothing thereafter.

Jetpack Navigation

One listener covers the whole app:

navController.addOnDestinationChangedListener { _, dest, _ ->
    TraceItX.recordScreen(dest.route ?: dest.displayName)
}

Fragments and plain Views

override fun onResume() {
    super.onResume()
    TraceItX.recordScreen("Checkout")
}

How the chain behaves

  • One global chain, chronological. Not per-back-stack — a tab switch correctly reads TabA → TabB.
  • The first screen emits nothing. There is no screen to come from yet. It still becomes the from of the next transition.
  • A → A is suppressed. Configuration changes, recomposition, and returning from the background never produce a duplicate crumb — which matters on Android, where a rotation recreates the Activity.
  • Blank names are dropped, and recordScreen is a no-op before start().
  • Failures stay silent. Marker calls never throw into your navigation.

Naming screens

Route identifiers, never user content. OrderDetail, not Order #4471 — jane@example.com. Names travel in the report and are shown in triage. Screen names do pass through the breadcrumb buffer’s redaction, so an obvious email or card number is caught — but redaction recognises shapes, not meaning, and an order id or an internal username sails through. Do not rely on it. Ids belong in the optional data map:

TraceItX.recordScreen("OrderDetail", mapOf("orderId" to orderId))

A NavDestination.route often contains argument placeholders rather than values, which is why the listener above is safe by default — but check yours if you build routes by string interpolation.

What lands in the envelope

{
  "t": 1755500000000,
  "seq": 42,
  "kind": "navigation",
  "message": "Cart → Checkout",
  "data": {
    "from": "Cart",
    "to": "Checkout"
  }
}

Troubleshooting

SymptomLikely cause
Only one screen ever appearsSingle-Activity app. Add TXScreen(), a destination listener, or recordScreen in onResume.
Every tab recorded once at startup, never againPages stay composed — pass active rather than relying on composition.
Screens repeat after a rotationThey should not — A → A is suppressed. If you see it, two destinations share a name.
Crumbs stop when the reporter opensExpected. The trail is frozen so the reporter’s own UI never pollutes the evidence.