Engaged Dwell POC — Page 1

Exploration only — not shippable. This earlier Solution 2 prototype measures visible dwell rather than interaction-based engaged time. It also emits an immediate Page Viewed plus a separate Page Viewed Completed event. Those semantics are not the proposed Solution 3 design.
How it works

The problem. Engagement (dwell) time for a page view is only known after the user leaves it — but the moment they leave is exactly when the page is being torn down. Firing a final request on unload/pagehide is unreliable across modern browsers, so the last bit of engagement (and the entire last page view of a session) is easily lost.

The approach: a heartbeat to a delayed-events endpoint. While a page is open, the SDK sends a small heartbeat every 1s. Each heartbeat carries two kinds of events:

The delayed service holds, it doesn't ingest. Each heartbeat upserts a row keyed by a per-page-view id. The row stores the latest delayed events and resets a 10s timeout. As long as heartbeats keep arriving, the row keeps getting replaced and the timeout keeps getting pushed out — so nothing is ingested while the user is still on the page.

Ingestion happens on timeout. When the user navigates away or closes the tab, the heartbeats stop. After 10s of silence the row's timeout lapses and the delayed service flushes its last snapshot — the final Page Viewed Completed with the total dwell time — into ingestion. No client request is needed at exit, which is what makes it reliable and what lets us capture the final page view of a session.

What you're seeing in this demo

Hosted demo note: GitHub Pages is static, so the delayed-events backend is simulated in your browser and shared across the two pages via localStorage; a timer plays the role of the server-side timeout reaper. The heartbeat network requests are real, so the 1s cadence is observable in DevTools. Use Reset POC state if a stale row lingers from an earlier visit.
initializing…

Delayed service (held events)

idtimeoutevents

Ingested events pool

#sourceevent

Raw request — click any row above

Click an event in either table to see the raw HTTP request body it arrived in.