Knowing What Operators Do
At 2 AM during a fire, nobody files a bug report. If a dispatcher fumbles with a control, clicks the wrong thing three times, or hits an error and just… works around it, the only witness is telemetry. That's what this chapter is about: the app streams every click, session, and error to Azure Application Insights, where we can replay what operators actually did — not what we hoped they'd do.
This lesson covers what gets tracked and how the pipeline works. Anatomy of a Click goes deep on the click tracker, and Asking Questions of the Data is the query cookbook.
What gets tracked
Five streams, from broadest to most specific:
Every click. A global listener captures each click with rich context — what was clicked,
what it said, where it sits in the component hierarchy, and every data-* attribute it carried.
This is Dynatrace-style ambient capture: nobody has to remember to instrument a button for it to
show up in the data.
Sessions. Start (browser, platform, screen size, timezone) and end (duration, page views, last action) — the envelope around everything else.
Identity. After sign-in, the user's id, organization, and role are attached to all subsequent telemetry, so "what did agency X's operators struggle with" is an answerable question.
Errors. Console errors, unhandled promise rejections, and React component crashes — with one deliberate filter: ArcGIS abort errors are excluded, because the map fires them constantly during normal pan/zoom and they'd drown everything else.
Domain events. Explicit calls for the things clicks can't express: camera interactions (view, PTZ, snapshot), map interactions (pan, zoom, layer toggles), alert interactions (create, acknowledge).
How a click becomes a queryable row
Three things in that picture matter in practice. Events are batched, so don't expect one-network-request-per-click in the DevTools network tab. There's a 2–5 minute lag before events are queryable — patience before declaring your instrumentation broken. And retention is 90 days by default, so long-term analyses need their conclusions exported, not re-run.
Where the code lives
The whole system is two files plus a wiring point:
lib/applicationInsights.ts— the SDK setup and everytrack*function:initializeAppInsights,setUserContext/clearUserContext,trackClick,trackSessionStart/End, and the domain trackers (trackCameraInteraction,trackMapInteraction,trackAlertInteraction).hooks/useAppInsightsTracking.ts— the React hooks:useClickTracking(the global listener),useSessionTracking(beforeunload),useUserTracking(auto-links auth state).pages/_app.tsx— where the hooks are mounted, once, for the whole app.
Initialization is guarded by typeof window !== 'undefined' — the SDK never runs during SSR —
and requires one env var, NEXT_PUBLIC_APPLICATIONINSIGHTS_CONNECTION_STRING. No connection
string, no telemetry, no error: it fails quiet.
Wrapping up
Every click, session, identity, error, and domain event flows through two files into Azure, batched and queryable within minutes. The system is ambient — you get click data for free — but the quality of that data depends on how components are written, which is exactly where the next lesson picks up: Anatomy of a Click.