Measuring attention in an app with no page loads
02-07-2026
The visitors resource counts how long someone actually looked at a page, which is harder than it sounds once the app is a single page.
Classic analytics counts page loads. An SPA has one. Every navigation after that is a DOM swap, so the only honest signal left is a heartbeat, and the question becomes what it should count. Not wall-clock time, because a tab left open overnight is not attention. The heartbeat is gated on document.visibility and pauses when the tab is hidden, deliberately not on focus: a visitor reading with the window slightly behind another is still reading.
Two details that took a revision each. A beat fires on every navigation as well as on its own interval, and the closing seconds of the previous page ride along with the beat that opens the next one, so time is attributed to the page it belonged to. And the last beat goes out on pagehide with keepalive set, because a normal request at that moment is one the browser is free to cancel.
The identity moved too. It used to key on a persistent cookie, which measured a person across days; it now keys per browser window, which measures a session in the sense a reader would recognise. Writes are a single atomic upsert, so concurrent beats cannot race into two rows.
None of it leaves the machine, and untracked visitors are excluded from the breakdowns rather than bucketed as unknown.
Engine 1.0.1. See visitors in the manual.