fix: deduplicate pageviews on page refresh
This commit is contained in:
@@ -4,6 +4,12 @@ All notable changes to Pulse (frontend and product) are documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and Pulse uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) with a **0.x.y** version scheme while in initial development. The leading `0` indicates that the public API and behaviour may change until we release **1.0.0**.
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and Pulse uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) with a **0.x.y** version scheme while in initial development. The leading `0` indicates that the public API and behaviour may change until we release **1.0.0**.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **More accurate pageview counts.** Refreshing a page no longer inflates your pageview numbers. The tracking script now detects when the same page is loaded again within a few seconds and skips the duplicate, so metrics like total pageviews, pages per session, and visit duration reflect real navigation instead of reload habits.
|
||||||
|
|
||||||
## [0.15.0-alpha] - 2026-03-13
|
## [0.15.0-alpha] - 2026-03-13
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -225,11 +225,42 @@
|
|||||||
return cachedSessionId;
|
return cachedSessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// * Refresh dedup: skip pageview if the same path was tracked within 5 seconds
|
||||||
|
// * Prevents inflated pageview counts from F5/refresh while allowing genuine revisits
|
||||||
|
var REFRESH_DEDUP_WINDOW = 5000;
|
||||||
|
var DEDUP_STORAGE_KEY = 'ciphera_last_pv';
|
||||||
|
|
||||||
|
function isDuplicatePageview(path) {
|
||||||
|
try {
|
||||||
|
var raw = sessionStorage.getItem(DEDUP_STORAGE_KEY);
|
||||||
|
if (raw) {
|
||||||
|
var last = JSON.parse(raw);
|
||||||
|
if (last.p === path && Date.now() - last.t < REFRESH_DEDUP_WINDOW) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordPageview(path) {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(DEDUP_STORAGE_KEY, JSON.stringify({ p: path, t: Date.now() }));
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
// * Track pageview
|
// * Track pageview
|
||||||
function trackPageview() {
|
function trackPageview() {
|
||||||
var routeChangeTime = performance.now();
|
var routeChangeTime = performance.now();
|
||||||
var isSpaNav = !!currentEventId;
|
var isSpaNav = !!currentEventId;
|
||||||
|
|
||||||
|
const path = window.location.pathname + window.location.search;
|
||||||
|
|
||||||
|
// * Skip if same path was just tracked (refresh dedup)
|
||||||
|
if (isDuplicatePageview(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentEventId) {
|
if (currentEventId) {
|
||||||
// * SPA nav: visibilitychange may not fire, so send previous page's metrics now
|
// * SPA nav: visibilitychange may not fire, so send previous page's metrics now
|
||||||
sendMetrics();
|
sendMetrics();
|
||||||
@@ -239,8 +270,6 @@
|
|||||||
lcpObserved = false;
|
lcpObserved = false;
|
||||||
clsObserved = false;
|
clsObserved = false;
|
||||||
currentEventId = null;
|
currentEventId = null;
|
||||||
|
|
||||||
const path = window.location.pathname + window.location.search;
|
|
||||||
const referrer = document.referrer || '';
|
const referrer = document.referrer || '';
|
||||||
const screen = {
|
const screen = {
|
||||||
width: window.innerWidth || screen.width,
|
width: window.innerWidth || screen.width,
|
||||||
@@ -265,6 +294,7 @@
|
|||||||
keepalive: true,
|
keepalive: true,
|
||||||
}).then(res => res.json())
|
}).then(res => res.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
recordPageview(path);
|
||||||
if (data && data.id) {
|
if (data && data.id) {
|
||||||
currentEventId = data.id;
|
currentEventId = data.id;
|
||||||
// * For SPA navigations the browser never emits a new largest-contentful-paint
|
// * For SPA navigations the browser never emits a new largest-contentful-paint
|
||||||
|
|||||||
Reference in New Issue
Block a user