> ## Documentation Index
> Fetch the complete documentation index at: https://docs.insito.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Screen tracking

> Auto-discover the screens your app uses, target surveys per-screen, and audit the screen-map view.

Screen tracking surfaces which routes your users actually visit. The
data feeds two systems:

1. **Per-screen triggers** — `screen_viewed:/checkout` automatically fires when
   the user lands on `/checkout`, so you can wire a survey to any route without
   adding `trigger()` calls everywhere.
2. **Screen map** in the dashboard — shows which paths exist, ordered by visit
   count.

## Navigator observer

Drop `InsitoNavigatorObserver` into your app's `navigatorObservers`. Zero config.

```dart theme={null}
import 'package:insito_flutter/insito_flutter.dart';

MaterialApp(
  navigatorObservers: [InsitoNavigatorObserver()],
  // ...
);
```

What happens:

* The observer reads each route's name from `route.settings.name`.
* Consecutive visits to the same route are de-duplicated.
* Each new route is recorded via `MicroSurvey.recordScreenVisit(name)`.
* If the user has been identified, the SDK also fires a trigger named
  `screen_viewed:<name>` — fire-and-forget, swallowing errors. This means the
  dashboard can target a survey to a specific screen without your app shipping
  any new code.

<Note>
  Screen names come from `RouteSettings.name`, so give your routes names to get
  useful data. Named routes (`Navigator.pushNamed(context, '/checkout')`) and
  the `routes:` / `onGenerateRoute` maps set this automatically. For
  `MaterialPageRoute` built inline, pass
  `settings: const RouteSettings(name: '/checkout')`.
</Note>

## Nested navigators & tabs

Add an `InsitoNavigatorObserver()` to each `Navigator` you want tracked — for
example the root navigator plus a nested one inside a tab shell. Each observer
de-duplicates independently.

## Manual screen recording

If a screen isn't driven by a `Navigator` push (a tab switch, an `IndexedStack`,
a custom router), record it directly:

```dart theme={null}
import 'package:insito_flutter/insito_flutter.dart';

MicroSurvey.recordScreenVisit('home');
```

This records the visit and — once the user is identified — fires the same
`screen_viewed:home` trigger as the observer.

## Data flow

```mermaid theme={null}
sequenceDiagram
  participant App
  participant SDK
  participant API

  App->>SDK: route pushed → "/checkout"
  SDK->>SDK: ScreenMap.record("/checkout")
  Note over SDK: Aggregates locally for 60s
  SDK->>API: POST /v1/sdk/screen-map { screens: {...} }
  SDK-->>App: screenMapFlushed { screens }
```

Local aggregation reduces network chatter. The SDK debounces visits into a
60-second window, then flushes the accumulated counts in one batch. It also
flushes when the app is backgrounded; if it can't, the next launch flushes on
the next visit.

## Viewing screens in the dashboard

[admin.insito.app](https://admin.insito.app) → your project → **Screens** tab.
Lists every path Insito has seen, sorted by visit count, with a search box.

Use this to:

* Audit your information architecture (which screens are users actually using?).
* Target a survey to a specific path — paste the path into a survey's trigger
  field with the `screen_viewed:` prefix, e.g. `screen_viewed:/checkout/success`.
* Spot dark corners — screens with low visit counts that marketing assumed were
  primary flows.

## Limits and gotchas

* Route names are stored verbatim. Keep them stable and free of per-instance IDs
  (`/products/123`) — use a templated name (`/products/:id`) so visits aggregate
  instead of exploding into unique paths.
* Each flush sends at most 200 paths (`POST /v1/sdk/screen-map`), so keep the
  set of screen names bounded (see the templated-name tip above).
* Unnamed routes (`route.settings.name == null`) are skipped, so give routes
  names to track them.
