Summary
Track how long users spend on pages. Requires client-side JS and backends that support updateEvent.
How other tools track duration
| Tool |
Metric |
Scope |
Idle time included? |
| GA4 |
Session duration |
Session |
Yes (includes idle) |
| GA4 |
Engagement time |
Per-page |
No (pauses on tab switch) |
| Plausible |
Engagement time |
Per-page |
No (pauses on tab switch) |
Session duration = time between first and last event. Simple but misleading - if user opens tab,
walks away for 10 min, comes back, that idle time counts.
Engagement time = actual active time on page. Pauses when tab loses focus or window is blurred.
More accurate measure of user attention.
Our approach: per-page engagement time
We'll track engagement time per page (like GA4's engagement time, not session duration):
- Start timer when page becomes visible
- Pause on
visibilitychange (tab switch) and blur (window focus lost)
- Resume on visibility restore /
focus
- Send duration when user leaves page
This gives accurate "time spent reading this page" metric.
Design
Client-side (NextlyticsClient component)
// Pseudocode
let startTime = 0
let accumulated = 0
function onVisible() {
startTime = Date.now()
}
function onHidden() {
accumulated += Date.now() - startTime
}
function sendDuration() {
const duration = accumulated + (document.hidden ? 0 : Date.now() - startTime)
fetch('/api/event', {
method: 'POST',
body: JSON.stringify({
type: 'updateEvent',
eventId: currentPageViewId,
patch: { properties: { duration } }
})
})
}
Events to listen
visibilitychange - pause/resume timer
pagehide - send final duration (more reliable than beforeunload)
- Optional: periodic heartbeat every 30s for long sessions
Page navigation (SPA)
On client-side navigation:
- Send duration for current page
- Reset timer
- Start tracking new page
Backend requirements
Only backends with supportsUpdates: true can use this feature:
- ClickHouse: yes
- Postgres/Neon: yes
- Segment: no
- PostHog: no
- GA: no (but GA tracks in anyway)
Config
Nextlytics({
trackDuration: true, // default: false
durationHeartbeatMs: 30000, // optional, 0 to disable
})
Changes needed
- Add
trackDuration and durationHeartbeatMs to NextlyticsConfig
NextlyticsClient component:
- Set up visibility/pagehide listeners
- Track accumulated time
- Send updateEvent on page leave
- Add
type: 'updateEvent' handling to /api/event route
- Document which backends support this
Summary
Track how long users spend on pages. Requires client-side JS and backends that support
updateEvent.How other tools track duration
Session duration = time between first and last event. Simple but misleading - if user opens tab,
walks away for 10 min, comes back, that idle time counts.
Engagement time = actual active time on page. Pauses when tab loses focus or window is blurred.
More accurate measure of user attention.
Our approach: per-page engagement time
We'll track engagement time per page (like GA4's engagement time, not session duration):
visibilitychange(tab switch) andblur(window focus lost)focusThis gives accurate "time spent reading this page" metric.
Design
Client-side (NextlyticsClient component)
Events to listen
visibilitychange- pause/resume timerpagehide- send final duration (more reliable thanbeforeunload)Page navigation (SPA)
On client-side navigation:
Backend requirements
Only backends with
supportsUpdates: truecan use this feature:Config
Changes needed
trackDurationanddurationHeartbeatMstoNextlyticsConfigNextlyticsClientcomponent:type: 'updateEvent'handling to/api/eventroute