Engaged time
The engaged-time subpath measures how long the user was actively engaged
with the page, combining visibility with interaction inside an idle timeout.
Bundle target: under 1 kB gzip.
Install
Section titled “Install”import { installEngagedTime } from '@syntarie/tracking/engaged-time';import { send } from '@syntarie/tracking';
const teardown = installEngagedTime(send, { idleTimeoutMs: 30_000 });| Option | Type | Default |
|---|---|---|
idleTimeoutMs | number | 30_000 |
The accumulator runs while:
document.visibilityState === 'visible'(the tab is focused), AND- The user has produced any user-input event (mousemove, key, touch,
scroll, click) within the last
idleTimeoutMs.
It pauses when the tab goes to the background and resumes on
visibilitychange back to 'visible'.
Wire shape
Section titled “Wire shape”{ "type": "engaged_time", "url": "https://example.com/blog/post", "ts": 1714665600000, "props": { "seconds": 47 }}props.seconds is rounded. Zero-second pageviews are dropped before emit
(no event for “user opened the tab and switched away immediately”).
SPA navigation
Section titled “SPA navigation”For per-route engaged-time on a single-page app:
import { endEngagedTimeForPageview } from '@syntarie/tracking/engaged-time';
router.beforeEach(() => { endEngagedTimeForPageview();});This emits the current accumulator (if non-zero) and resets it for the next route.
What this is NOT
Section titled “What this is NOT”This is not “time on page”. That would be pageHideTs - pageLoadTs, a
metric inflated by users who open a tab and walk away. Engaged time is the
actual attention budget the user spent on this content.
It is also not a heatmap, scroll velocity, or rage-click detector. This module ships the raw engaged seconds; richer interaction analysis lives in the dashboard.