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.
Four timings, three different jobs
| Setting | Default | Configurable? | What it does |
|---|---|---|---|
| Engagement activity window | 5 seconds | Yes, requested; default proposed | Recent activity keeps the attention clock running. When the window closes, engaged time pauses; blur or a hidden tab pauses it immediately. |
| Snapshot heartbeat | 15 seconds | Yes, proposed SDK option | Updates the same pending Page Viewed with cumulative engaged time. Reach wants this cadence; they have not specifically requested a cadence control. |
| Client inactivity finalization | 3 minutes | Yes, confirmed by Reach | Measured from the last qualifying engagement. A running SDK finalizes the page; heartbeat requests never reset this deadline. |
| Service fallback timeout | 3 minutes | Internal setting, aligned with client | Measured from the last accepted snapshot when the SDK cannot finalize. It is a separate timer, not a second customer-facing option. |
The 5-second window pauses counting; the 3-minute inactivity timer ends the logical page view. The service timeout protects the latest stored snapshot if the browser stops running. This POC simulates all three behaviors in-browser. Timing decision ↗ · Reach confirmation ↗
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.
Send a snapshot now. Normally the 15-second cadence replaces the pending Page Viewed with its latest cumulative engaged time.
Choose navigation, the running client's 3-minute inactivity timer, or the service fallback after browser suspension.
Navigation starts Article B immediately. After inactivity, simulate returning to Article A after the 3-minute boundary.
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 three-minute client inactivity 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 three minutes without qualifying engagement, the running client sends a final snapshot and finalizes the Page Viewed. Heartbeat traffic does not reset this clock. Returning after that boundary creates a new logical Page View, even at the same URL.
The SDK stops before it can finalize
If browser timers are suspended, the service timeout becomes due three minutes after the last accepted snapshot and forwards that stored value. This may lose the unreported tail. Actual DynamoDB TTL deletion and ingestion can take longer; three minutes is not a delivery guarantee.
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, client inactivity, or the separate service timeout 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.