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.
1. Broader and Smarter Click Tracking
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 <button> and <a> 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:
- Fine-tune which elements are tracked without redeploying the host app.
- Roll back a problematic selector or rule the moment it misfires in production.
- Adapt collection logic dynamically as UI patterns evolve.
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.
2. Real-Time Conversation Capture via WebSockets and SSE
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:
- Remote-configurable “rich content” inference. Instead of hard-coding which payload shapes count as user-visible content, classification rules are pushed via remote config, so new conversational formats can be supported without an SDK release.
- Conversation identifier propagation via baggage headers. Client and conversation IDs travel with outbound requests, so backend systems can stitch together streams that originated on the client even when they fan out across services.
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.
3. Cohort Replay: Reconstructing Real User Behavior
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:
- Remote enable/disable of replay capture with no host-app redeploy.
- Dynamic, fine-grained sampling controls that balance insight, performance, and cost — you can dial replay up for a cohort under investigation and back down the moment the data is gathered.
- Configurable data masking applied in real time, so privacy rules are enforced at capture time rather than relying on downstream redaction.
The net effect is actionable user-journey visibility without compromising operational safety, privacy compliance, or production flexibility.
4. Soft Navigation in Single Page Applications
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:
- More accurate identification of page transitions triggered by framework-driven routing.
- Improved session flow visibility without depending on traditional browser reload boundaries.
- Better attribution of engagement and performance metrics across dynamic UI state changes.
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.
5. Stability, Correctness, and Performance Under Real-World Conditions
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.
A few representative improvements:
- More reliable network request tracking. Request headers and contextual metadata are preserved exactly as sent, so downstream systems can attribute metrics and errors to the correct origin without ambiguity. A specific class of bugs where headers were being forwarded as normalized header objects rather than retaining their original shape in fetch requests was eliminated.
- Enhanced XMLHttpRequest interception. The SDK observes legacy and polyfilled XHR traffic accurately without modifying native request behavior. This matters disproportionately for older or heavily customized codebases where naive monkey-patching would silently break the host app’s own retry, auth, or telemetry logic.
- Pre-initialization command queuing. Tracker calls issued before convivaAppTracker() has finished initializing — trackCustomEvent, trackRevenueEvent, setUserId, and others — are buffered and automatically replayed once the tracker is up. This removes an entire class of “I called it too early” bugs that previously caused silent data loss in fast-rendering apps.
- Event durability on unload. A subtle but high-impact bug where events could be lost when a user closed a tab or clicked an outbound link (especially in multi-page applications) was fixed, using transport choices designed to survive page-unload.
- Bundle-size reduction. Replacing the internal compression library cut a meaningful slice of the main SDK bundle without changing any external API. For sensors, every kilobyte is paid for by every customer’s users; this kind of optimization is foundational.
- Supplementary Web Vitals — LCP, INP, CLS, FCP and TTFB. First Contentful Paint and Time to First Byte are now available alongside the Core Web Vitals, gated by a remote config flag and supported in Chrome, Firefox, and Safari. Performance teams can opt in only where they need the deeper view.
- Integration ergonomics. A Google Tag Manager template for zero-code deployment, a typed revenue API for first-class business metrics, default client-ID persistence for cross-subdomain stitching, and AGENTS.md for AI-assisted integrations.
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.
6. Remote Configuration as a First-Class Control Plane
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.
In practice, remote configuration is now used to:
- Quickly mitigate spikes in event volume by lowering caps or sampling.
- Disable a collector during an incident while keeping the rest of the SDK active.
- Adapt to new frameworks or UI libraries in production by pushing updated extraction rules.
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.
Stepping Back
Five themes hold the work together:
- Accuracy first — smarter event capture (clicks, forms, scroll, soft navigations, streamed conversations) that respects how modern apps actually behave.
- Control always — remote configuration as both a safety valve and a tuning dial, with an instant-update delivery path so the control plane is fast enough to actually mitigate incidents.
- Rich interaction capture — conversational streams, replay, and form lifecycles treated as first-class signals, not approximated from coarser events.
- Operational excellence — pre-init queuing, event durability on unload, bundle-size discipline, and continuous correctness work under real usage conditions.
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.