Opt-in engaged time tracking for accurate visit duration - #4554
anandghegde wants to merge 4 commits into
Conversation
Add a data-engagement="true" tracker option that measures time the page is visible and focused, and sends it on route change, visibilitychange and pagehide as a new "engagement" collection type. Engaged time is stored per page in a new website_engagement table (Postgres and ClickHouse). Visit duration uses the visit's engaged time when it exists and falls back to the first-to-last event span otherwise, so sites that do not enable the option are unchanged. Refs umami-software#3518
|
@anandghegde is attempting to deploy a commit to the Umami Software Team on Vercel. A member of the Team first needs to authorize it. |
|
Intervals shorter than a second were reset on every flush, so quick route changes or tab switches lost that time from the visit total. Keep the remainder and send it with the next report instead.
Engagement is written when the page is left, which can be after the range that contains the visit's events. Allow up to a day past endDate (the largest single report) when joining engagement to visits.
Refs #3518
What
Adds an opt-in tracker option,
data-engagement="true", that measures engaged time. That is the time the page is visible and focused. Visit duration uses it in place of last-event-minus-first-event.Right now a single-page visit always has a duration of 0. The last page of any visit also adds nothing to the duration. This PR fixes both for sites that turn the option on. Sites that don't turn it on are unchanged.
How
Tracker (
src/tracker/index.ts, +407 B min / +123 B gzip)focus,blurandvisibilitychange.{ type: 'engagement', payload: { ...payload, engagement: ms } }on SPA route change (for the page being left), onvisibilitychangeand onpagehide. Anything under 1 s is not sent. It uses the existingsend(), sobefore-send, the cache token and DNT behave as they do for other events.Collection (
/api/send)engagementtype.engagementmust be an integer from 1 to 86,400,000 ms.website_engagementtable with its session, visit and URL path.Storage
27_add_website_engagement. ClickHouse migration15_add_website_engagementplusschema.sql. The healthcheck indocker-compose.test.ymlnow waits on the new last table.event_typeonwebsite_event. That keeps pageview counts,website_event_stats_hourlyand the existingNOT IN (2, 5)filters as they are.heatmap_event.Queries
getEngagementQuery()inlib/prismaandlib/clickhousejoins the engaged seconds for each visit.coalesce(engaged, max - min). This is used ingetWebsiteStats,getSessionExpandedMetrics,getChannelExpandedMetricsandgetWebsiteSession.getBreakdownandgetEventExpandedMetricsare unchanged. They group below visit level, so a per-visit total would be counted more than once.Testing
pnpm buildpasses and the migration applies. Biome and vitest show no new failures.Notes / open questions
url_pathis stored so time on page could be added later.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.