Skip to content
TraceItX Docs
Documentation

Screen tracking

UIKit navigation is automatic. SwiftUI is one line per screen, because there is nothing to observe.

Updated

UIKit — automatic

TraceItX observes UIViewController.viewDidAppear and emits a crumb when the appearing controller is either pushed onto a UINavigationController or presented modally. The screen name is the view controller’s class name:

// Automatic — no code required.
navigationController?.pushViewController(CheckoutViewController(), animated: true)
// → breadcrumb: "CartViewController → CheckoutViewController"

Container churn and tab re-selections are deliberately excluded, so the trail stays readable rather than logging every internal re-appearance. That also means tab switches emit nothing — mark them explicitly if they matter.

SwiftUI — not automatic

A NavigationStack / NavigationLink push is not backed by discrete view controllers, so there is nothing to observe. Mark screens from .onAppear:

struct CheckoutView: View {
    var body: some View {
        Form {  }
            .onAppear { TraceItX.shared.recordScreen("Checkout") }
    }
}

Markers and UIKit auto-capture share one chain, so a mixed app reads as a single trail: RootViewController → Checkout → ConfirmationViewController.

How the chain behaves

  • One global chain, chronological. Not per-stack. Note that tab switches are excluded from auto-capture entirely (see above), so TabA → TabB only appears if you record it yourself.
  • 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. Re-appearances from backgrounding or a dismissed modal never produce a duplicate crumb.
  • 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.shared.recordScreen("OrderDetail", data: ["orderId": orderId])

Class names are stable and safe by default, which is part of why UIKit auto-capture uses them.

What lands in the envelope

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

t is the shared epoch-millisecond clock that also stamps the session replay.

Troubleshooting

SymptomLikely cause
Only one screen ever appearsSwiftUI-only navigation, or navigation that is neither a push nor a modal presentation. Mark screens from .onAppear.
Tab switches missingExpected — tab re-appearances are excluded from auto-capture. Mark them explicitly.
Crumbs stop when the reporter opensExpected. The trail is frozen so the reporter’s own UI never pollutes the evidence.