Skip to main content

The script

Single-page apps

Route changes are tracked automatically.

Route changes are tracked automatically. In most cases there is nothing to do.

What works out of the box

The script watches history.pushState, history.replaceState and popstate, and records a page view whenever the path changes. That covers React Router, Next.js, Vue Router, SvelteKit, Astro's view transitions, Remix, and anything else that uses the History API — which is nearly everything.

You do not need to call window.truestat() on navigation, and you should not: that would double-count.

Debouncing

Navigations are debounced at 100 ms.

Routers routinely call replaceState immediately after pushState — to normalise a trailing slash, to write a scroll position, to add a query parameter. Without the debounce, every single navigation would produce two page views. If you have ever seen a page view count exactly double the truth in another analytics tool, this is usually why.

The practical consequence: two genuine navigations less than 100 ms apart are recorded as one. That is a redirect, not a person reading two pages.

Hash routing

If your app routes on the fragment — /#/dashboard, /#/settings — the path never changes, so nothing is recorded after the first load. Turn on hash tracking:

<script
  defer
  data-website-id="ts_a1b2c3d4e5f6"
  data-domain="example.com"
  data-ts-track-hash="true"
  src="https://truestat.io/js/t.js"
></script>

The script then also listens for hashchange.

Only turn this on if you actually route on the hash. On a normal site the fragment is an anchor link, and every jump to a #section heading would be recorded as a page view.

What the path looks like

The recorded path is location.pathname — no origin, no query string, no fragment (unless hash tracking is on, in which case the fragment is included).

It is truncated at 500 characters. Long faceted-search URLs and deep documentation trees can exceed that; the tail is dropped and the view is still recorded.

Framework-specific advice

Do not add the script from inside a component's effect hook. Two things go wrong. A cleanup function that removes the script tears the tracker down on navigation. And a component that remounts adds a second copy of the script, which double-counts every view from then on.

Put the tag in your root HTML document or root layout — the file that renders once for the whole app. Every install page in Installing TrueStat names that file for its platform.

Verifying it

The clearest check is a count, not a state:

  1. Load your app.

  2. Navigate to three different routes.

  3. Open your dashboard and look at Top pages.

You should see four paths, once each. If you see each one twice, you have two tags on the page — see Duplicate events. If you only see the first, your tag is in a page component rather than the root layout.

Was this page helpful?

Last updated August 28, 2026