1. Decide what a page view means before testing
Your pricing page switches from monthly to annual billing without reloading. A signup link changes the route, and the browser Back button returns to pricing. These are three interface actions, but they are not necessarily three additional page views. A useful analytics check starts with a list of expected paths rather than a count of clicks.
The current WhoVisited tracker uses origin plus pathname as its navigation key. It creates an initial page view when collection is allowed, then compares that key on supported client-side navigation. Changes limited to search parameters or fragments do not create another automatic page view. This article tests that behavior; it does not promise that every router or browser lifecycle is covered.
Keep this distinction when interpreting reports. A billing toggle may matter to your product, but a URL parameter change alone is not a new page under this model. If you need to measure an intentional interaction, choose a separate custom event with a stable name and minimal properties.
2. Know which browser transitions are observed
WhoVisited wraps history.pushState and history.replaceState, and listens for popstate. After a wrapped call succeeds, it compares the current origin and pathname with the previous key. It updates that key and attempts to record a page view only when they differ. A replaceState call that changes the pathname therefore counts, even though it replaces the current history entry.
MDN documents that pushState adds a history entry without loading the destination document. Calling pushState or replaceState does not itself fire popstate; history traversal such as Back or Forward can do so. This is why listening only for popstate would miss ordinary router transitions. WhoVisited handles those calls separately.
A hash change is a different signal. WhoVisited does not register a hashchange listener, and its comparison excludes the fragment. An application that routes entirely through URLs such as /#/pricing and /#/signup is outside its automatic path-based navigation coverage. Do not assume those screens appear as separate pages.
Full document navigation starts a new document with its own tracker initialization. Test that separately from a client-side transition. Browser restoration of a cached document also deserves a separate test: the current tracker has no pageshow listener that promises an extra page view on every restoration.
3. Write an expected sequence without sending analytics
Use synthetic routes on a staging site, or paths that contain no personal information. This console helper predicts path changes for a sequence of URLs. It does not navigate, call WhoVisited, inspect cookies or send network requests. The supplied base is deliberately a sample origin.
function planPathViews(urls, base = location.href) {
let previous;
return urls.map((value, step) => {
const url = new URL(value, base);
const pathKey = url.origin + url.pathname;
const expected = pathKey !== previous;
previous = pathKey;
return { step, path: url.pathname, expectedPageView: expected };
});
}
console.table(planPathViews([
"/pricing",
"/pricing?billing=annual",
"/pricing#faq",
"/signup",
"/signup",
"/pricing",
], "https://example.com"));The expected flags are true, false, false, true, false, true. With tracking allowed and a fresh document at /pricing, that means three expected page-view events across this whole sequence. Returning to a previously visited path is another view because the immediately preceding path is different; this is not a unique-page counter.
The helper is a planning tool, not a router simulator. It does not prove that a navigation event fired, that consent was granted, or that the server accepted an event. Use it to agree on expected outcomes before exercising the real application. Keep all test URLs on the same origin for this scenario.
4. Exercise the actual router and inspect accepted events
- Open a fresh page on the test website. Confirm the intended site ID, enabled collection and allowed origin before evaluating navigation.
- Open browser developer tools and preserve the Network log. Filter for the WhoVisited bootstrap and events endpoints.
- Change only the pricing query parameter, then only the fragment. Expect no additional automatic page view for those changes.
- Use the application link to reach /signup. Confirm a page_view event with the signup path after a supported pathname transition.
- Use browser Back to return to pricing. Confirm the path transition is represented when the browser dispatches the observed navigation signal.
- Repeat with an application action that calls replaceState to change the pathname. Check that this transition is included in your expected count.
Inspect event names and URL paths in the request payload, not just the number of HTTP requests. The tracker batches queued events, so one POST can contain multiple page views or custom actions. An initial bootstrap success is only a prerequisite; check the events response and the resulting visitor journey under the correct website.
Use a short test window and note its timezone. Avoid mixing your check with other tabs or real user traffic. A clean run is easier to compare with an explicit sequence than a dashboard total accumulated over a full day.
5. Account for consent and title timing
Navigation detection does not override consent. While collection is disallowed, page views are not queued for later replay. The navigation key can still advance as routes change. When consent changes from disallowed to allowed, the current tracker attempts a page view for the current location, provided it has not stopped and the browser privacy signal permits collection.
Test this with a fresh document configured to require consent: navigate before approval, then approve on the current page. Expect the allowed current page, not a reconstructed history of earlier screens. A privacy signal can keep collection disabled after your application requests consent, so distinguish that state from a broken router.
Page titles have their own timing. The tracker reads document.title when it creates an event, immediately after the observed history operation for a route change. If your framework updates the title later, the recorded title can still belong to the previous screen. Validate the path first, then compare when the title actually changes.
Do not inject a second tracker or send a manual page_view to fix a stale title. The public track API ignores that reserved name. Record the mismatch and address application timing or tracker support deliberately instead of adding an undocumented parallel page-view system.
6. Turn failures into specific integration findings
- Only the first page appears: check whether navigation uses supported History API calls, whether the tracker remains initialized, and whether later collection requests are accepted.
- Only hash routes are missing: recognize the current automatic coverage limit; do not label it a transport failure.
- Paths are correct but titles lag: compare title update timing with the route operation.
- Pre-consent screens are absent: check whether that absence follows the configured collection boundary.
- Unexpected paths appear: inspect redirects and replaceState calls, including intermediate paths that were not meaningful rendered screens.
An origin-and-path change is a technical signal, not proof that a visitor read a page or completed a task. A redirect chain can create intermediate signals; a panel can change without any URL change. Choose business goals from confirmed outcomes rather than treating all navigation as conversion.
Finally, keep paths and titles free of names, email addresses and confidential identifiers. WhoVisited omits query strings and fragments from the event URL, and ingestion persists the pathname, but sensitive content embedded in a pathname or document title still needs attention. Finish your check by saving the expected sequence, consent state, observed paths and any known router limitations for the next release.