Measure attention, then finish the original event.
Today, Page Viewed is normally sent immediately—before its engaged time is known. This POC proposes briefly holding that event in an Amplitude heartbeat service, updating one property over time, and sending the completed event to ingestion.
The browser creates one Page Viewed event. The service holds it instead of sending it to Amplitude yet.
Recent input counts as engaged time. Heartbeats update the same pending record; they are not analytics events.
Navigation or expiry finalizes the record. Amplitude receives one Page Viewed with the final duration attached.
See the full lifecycle in five steps
Current · Step 1
Stop interacting for five seconds. The activity window reaches zero and engaged time pauses.
Scroll anywhere on the page. The tracker returns to ENGAGED and the five-second window restarts.
Advance 15 seconds. The service replaces the pending Page Viewed with its latest cumulative engaged time.
These paths are alternatives. Navigation attempts immediate finalization; two-hour inactivity is the expiry fallback.
Navigation starts the next page immediately. After expiry, simulate returning at hour three to create a new Page View for the same URL.
Live state of this simulated page visit
These values update in your browser only
1 · What happens in the browser
Article AMouse, scroll, click, touch, keyboard, load, and focus renew a five-second activity window. This simulation snapshots every 15 seconds. The separate two-hour expiration deadline resets only on qualifying activity; heartbeat traffic must not keep an inactive page alive.
2 · Amplitude heartbeat service
1 pending eventbuffered
update
forwarded
This is one event, shown as one record. The ID identifies the Page Viewed; engaged_time_seconds is a field updated on it. Heartbeats do not create additional analytics events.
Heartbeat service update history
1 service update| at | page | operation | trigger | engaged so far | snapshot |
|---|
Ownership transferred to the Amplitude ingestion service. The heartbeat service no longer stores this event.
3 · Amplitude ingestion service
final destinationOne logical Page View exists and is still pending.
| page | event | property |
|---|
The page ends explicitly
On pagehide/beforeunload, the SDK attempts one final cumulative snapshot and asks the service to finalize immediately. Delivery is not guaranteed. Chartbeat reports about 68% success for its combined unload mechanisms. For same-site navigation, Chartbeat stores the previous pinger state on the client for up to an hour and can resend it when another page on the domain loads Chartbeat. Whether the Amplitude SDK should add that client-side handoff remains an open design question. Chartbeat methodology ↗
The page remains open but inactive
After two continuous hours without qualifying engagement, the client finalizes if its timer is running. If the browser suspended the client, the delayed service timeout finalizes the latest successful snapshot. Returning at hour three creates a second logical Page View—even in the same tab and at the same URL—with new page_view_id, insert_id, timestamp, and zeroed counters.
Delay and enrich the original event
Sends Page Viewed once to the heartbeat service, then sends engagement heartbeats carrying the current cumulative duration.
Holds the original event and updates its pending engaged-time property. Navigation, lifecycle end, or the two-hour expiry finalizes it.
Receives that same Page Viewed event with engaged_time_seconds attached. No separate engaged-time event.
What this proposal buys
A single canonical Page Viewed event, final engaged time attached to the correct page, active-attention semantics, and final-page recovery from the latest stored snapshot.
Unresolved product costs
Open Page Viewed events are absent from ordinary queries, funnels, and session construction. Production work still needs ordering, BFCache, suspension, offline, multi-tab, shared-heartbeat, and first-class metric decisions.