Sift Docs
Tracking behavior

SPA routes

How Sift follows client-side navigation, and what it ignores.

Single-page apps change the URL without a page load. Sift watches the History API and sends a pageview when the URL actually changes.

What is watched

The script patches three things:

  • history.pushState
  • history.replaceState
  • the popstate event, which fires on back and forward

The original functions are called first, then Sift compares the current URL with the last one it saw. A pageview is sent only when they differ.

Because the patch is installed once and guarded by a flag, loading the script twice does not produce double pageviews.

The referrer on an SPA

When the URL changes without a reload, the browser's document.referrer still points at wherever the user came from. Sift sends the previous URL as the referrer instead, so internal navigation is attributed to the page the visitor just left rather than the original external source.

Session-level attribution still comes from the first pageview of the session. See How visitors are counted.

Hash changes

example.com/docs#install and example.com/docs#usage are the same page: the reported pathname is the path, not the hash.

Sift compares the full URL, hash included, so whether a hash change counts depends on how it happens:

  • A plain anchor link (<a href="#install">) does not touch the History API, so nothing is sent.
  • A router that calls pushState or replaceState with a new hash does trigger a pageview, and it lands on the same pathname as the previous one.

If your router pushes hash-only changes and you see inflated pageviews, that is why.

Duplicate URLs

Sift compares the URL with the last one it sent. Repeated calls that set the same URL produce one pageview.

Different URLs each produce a pageview. A router that writes /posts/123 and then /posts/hello-world for the same screen sends two, and both are stored.

Sift does not retroactively edit stored pageviews, so a URL that is rewritten after the pageview was sent stays as it was.

What is not tracked

  • Renders that do not change the URL.
  • State changes inside a route, such as opening a modal.
  • Scroll position or time on page.

Sift records pageviews, not interactions.

On this page