Track events
Single-page apps
The tracker fires one page view on initial load. Single-page apps change the URL without reloading, so you fire a page view yourself on each route change.
Why it's manual: the script stays tiny and predictable by not monkey-patching your router or the History API. You call track('pageview') exactly where your app knows a navigation happened — no guessing, no double-counts.
The one line
On every route change, after the URL has updated, call:
window.servoki.track('pageview');It reads the current location.href at call time, so fire it after your router updates the URL.
React Router
import { useLocation } from 'react-router-dom';
import { useEffect } from 'react';
function usePageviews() {
const location = useLocation();
useEffect(() => {
window.servoki?.track('pageview');
}, [location.pathname, location.search]);
}
// call usePageviews() once, high in your app treeNext.js (App Router)
"use client";
import { usePathname, useSearchParams } from 'next/navigation';
import { useEffect } from 'react';
export function ServokiPageviews() {
const pathname = usePathname();
const search = useSearchParams();
useEffect(() => {
window.servoki?.track('pageview');
}, [pathname, search]);
return null;
}
// render <ServokiPageviews /> inside app/layout.tsxSkip the very first render if you like — the script already counted the initial load — but a duplicate on first paint is harmless and most teams leave it in for simplicity.
Vue Router
router.afterEach(() => {
window.servoki?.track('pageview');
});Framework-agnostic (History API)
No router? Hook the History API and the back/forward button:
['pushState', 'replaceState'].forEach((m) => {
const orig = history[m];
history[m] = function () {
const r = orig.apply(this, arguments);
window.servoki?.track('pageview');
return r;
};
});
window.addEventListener('popstate', () => window.servoki?.track('pageview'));Verify it works
Navigate between routes with Realtime open — you should see one page view per navigation, no more, no less.