Digital experiences have outgrown the page-view model. Single-page apps re-render on every interaction, AI assistants stream tokens over long-lived sockets, and entire user journeys play out without a single full page load. For an analytics SDK living inside someone else's runtime, this is unforgiving territory: you must collect rich, accurate signals across constantly changing UI surfaces, never destabilize the host application, and remain controllable in production when something inevitably goes wrong.
This post walks through the engineering arc behind the Conviva JavaScript Sensor SDK, used across our Digital Pattern Insights solutions. The underlying philosophy is consistent throughout: design for correctness under uncertainty, empower rapid response through remote control, and expand the kinds of interactions we can observe reliably.
Auto-collected click events have always been a foundational signal for web analytics, but the definition of "clickable" has drifted significantly. Modern interfaces compose interaction out of divs with ARIA roles, custom React/Vue/Angular components, virtualized lists, and shadow DOM boundaries. A click handler attached only to and ends up blind to the majority of meaningful user intent.
We rebuilt the click resolution pipeline to capture semantically meaningful interactions across the full spectrum of HTML and framework-rendered surfaces — not just the standard set of clickable elements, but also the patterns frameworks invent on top of them. The pipeline now also captures xpath attributes on clicks and supports extracting specific DOM elements via remote configuration, which gives downstream analytics a stable, queryable handle on UI elements that don't always have semantic identifiers.

Equally important, the new pipeline exposes its decisions to remote configuration, so teams can:
This reflects a guiding engineering principle: interaction data should adapt to real usage, not constrain it. Remote control built into the sensor gives teams confidence that analytics stay reliable even as interfaces change underneath them.
The most significant shift in modern web UX is that interactions are no longer point-in-time events — they are streams. Chat applications, collaborative editors, and AI assistants emit messages over WebSocket and Server-Sent Event (SSE) channels that may live for the entire session. Classical page-view and click instrumentation simply does not model this.
The SDK now intercepts these transport layers and reconstructs structured conversation context from them. Specifically, it captures the full message lifecycle — open, message, send, error, close — giving downstream pipelines a faithful model of how a conversation actually unfolded, not just whether one occurred. Plain-text chunked message streams (the streaming format most LLM responses arrive in) are tracked with configurable endpoint filtering, so teams can scope capture to the specific routes that carry user-facing conversation.

Two additional pieces make this practically useful in production:
For teams instrumenting agentic experiences, this moves their analytics beyond token counts and into conversation shape and flow, giving them visibility into the user engagements that actually matter for these products.
Aggregated metrics tell you what changed; they rarely tell you why. Cohort Replay closes that gap by reconstructing a user's sequence of interactions — clicks, navigations, scrolls, inputs — into a video-like playback that product, design, and engineering teams can review together.
The hard engineering problem here is not the capture itself; it is operating safely inside someone else's production application while doing it. That means strict bounds on CPU and memory cost, no interference with the host app's rendering pipeline, and zero tolerance for leaking sensitive data.

The design treats replay as a first-class remotely controlled feature:
The net effect is actionable user-journey visibility without compromising operational safety, privacy compliance, or production flexibility.
Single-page application frameworks deliberately bypass the browser's traditional navigation events: React, Vue, and Angular all transition between "pages" through client-side routing, history-API manipulation, and selective DOM updates. None of these emit a load event. For an analytics SDK, this means the most natural session boundary — page navigation — simply isn't there to listen for.

We invested in detecting these soft navigations directly, by observing the signals SPAs actually produce: history API mutations, route changes, and structural DOM updates that correspond to a logical page transition. The improvements deliver:
The net effect is that session and page-level analytics finally reflect how users actually move through a modern SPA, rather than reporting one giant "page" that began at app boot and never ended.
Most of the engineering work behind an analytics SDK is not glamorous feature development — it is hardening behavior against the long tail of real-world conditions: flaky networks, polyfilled APIs, legacy codebases, and unexpected interactions with whatever else the host page is doing.
Each of these reduces a class of edge-case failures, improves attribution accuracy, and increases the SDK's resilience across the diverse environments it runs in.
A consistent thread runs through every feature above: remote configuration is not a side concern; it is the control plane.
Collection limits (request/response body size caps), element extraction rules, feature flags for streaming or click inference, sampling rates for replay — all of it is exposed through remote config. The implication is operational, not just architectural: a team can respond to a production issue without rebuilding the host application or shipping a new SDK version.
A key recent investment was moving the remote config delivery surface to a lower-latency, instant-update endpoint. The old model could leave changes pending until a session refresh — fine for normal tuning, not fine when you need to disable a misbehaving collector right now. With instant updates, the gap between "we pushed a config change" and "every active session sees it" closes dramatically.
A subtle but important implementation detail is how the SDK consumes this configuration. Because remote config is fetched asynchronously, any feature that checks configuration at initialization time will always see the default values — typically enabled: false — and silently disable itself for the entire session. Every feature is therefore designed to register its listeners unconditionally and consult configuration live, inside the event handler, so that by the time a real signal arrives, the most recent config is in effect. This pattern is now a first-class convention in the codebase.
The end result is a sensor SDK that behaves less like a static collector and more like an operationally safe platform — one where analytics teams can be proactive instead of reactive, and emergency releases become genuinely rare.
Five themes hold the work together:
A sensor SDK earns its place by being trustworthy. The improvements described here move the platform in that direction: more comprehensive in what it can observe, more honest about what it observed, easier to deploy, and more responsive when something needs to change in production.