Engaged time
The engaged-time subpath measures how long the user was actively engaged
with the page — visibility plus interaction within 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 → '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. Those are candidates for a v1.1+ analysis layer; the v1.0 SDK ships the raw engaged seconds.