Get started
Installation
Add Totallytics to your application layout, single-page app, or modern frontend framework.
Script placement
Load latest.js once in your root document. Do not mount duplicate script tags across child views.
Plain HTML
Place the script in your shared template header or footer:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My App</title>
<script
async
src="https://analytics.bitgate.dev/latest.js"
data-hostname="example.com"
></script>
</head>
<body>
<main></main>
</body>
</html>React and Vite
Add the script directly inside index.html at the project root:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<script
async
src="https://analytics.bitgate.dev/latest.js"
data-hostname="example.com"
></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>Next.js (App Router)
Place a raw <script> tag inside app/layout.tsx within the <body> element. Totallytics does not require an external npm package:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<script
async
src="https://analytics.bitgate.dev/latest.js"
data-hostname="example.com"
/>
</body>
</html>
);
}The tag is included in the rendered document; tracking runs in the visitor’s browser. For strict CSP, follow your framework’s nonce or hash setup for any inline code.
Single-page navigation
latest.js automatically hooks the browser window.history.pushState API and listens to popstate events. These navigation events trigger pageviews when the tracked path changes. Consecutive identical paths are suppressed; replaceState alone does not trigger a pageview.
Do not add a second manual pageview for a route already covered by automatic tracking.
If your frontend uses hash-based routing (such as example.com/#/dashboard), add the data-mode="hash" attribute to track hash fragment transitions:
<script
async
src="https://analytics.bitgate.dev/latest.js"
data-hostname="example.com"
data-mode="hash"
></script>Manual pageview tracking
If you prefer manual control over pageviews, disable automatic collection with data-auto-collect="false". When disabled, trigger pageviews using window.sa_pageview(path, metadata).
Calls recording an identical consecutive path are automatically suppressed. Verify that the script has loaded before calling window.sa_pageview:
<script>
function trackInitialPage() {
if (typeof window.sa_pageview !== "function") {
console.warn(
"Pageview tracking is unavailable; check DNT and script loading.",
);
return;
}
window.sa_pageview(window.location.pathname);
}
</script>
<script
async
src="https://analytics.bitgate.dev/latest.js"
data-hostname="example.com"
data-auto-collect="false"
onload="trackInitialPage()"
></script>Script configuration options
Configure behavior by setting data attributes on the <script> tag:
data-hostname: The registered site hostname (e.g.,example.com).data-ignore-pages: Comma-separated path patterns with wildcards to ignore (e.g.,/admin/*,/checkout/receipt).data-allow-params: Extra comma-separated query keys to keep, beyond the campaign parameters the script already recognizes (e.g.,plan). Keep values non-sensitive.data-mode: Set to"hash"for hash-based client routers.data-auto-collect: Set to"false"to disable automated pageviews on load and history navigation.data-strict-utm: Set to"true"to keep automatic campaign-parameter collection toutm_keys rather than short aliases such assourceandcampaign.
You can also assign settings via window.sa_settings before the script loads:
<script>
window.sa_settings = {
hostname: "example.com",
autoCollect: false,
};
</script>
<script async src="https://analytics.bitgate.dev/latest.js"></script>For most settings, window.sa_settings overrides the equivalent attribute; data-auto-collect="false" still disables automatic pageviews. Avoid conflicting configurations and set them before latest.js executes. Totallytics does not host the optional automatic-events companion scripts.
Privacy and Do Not Track
By default, navigator.doNotTrack === "1" stops normal collection after the script loads. Keep this default to respect the visitor’s setting.
Content Security Policy (CSP)
Totallytics uses new Image() for pageview beacons and navigator.sendBeacon for /append duration tracking.
If your site serves a Content Security Policy header, merge https://analytics.bitgate.dev into your existing directives. Do not overwrite your wider security rules:
script-src 'self' https://analytics.bitgate.dev;
img-src 'self' https://analytics.bitgate.dev;
connect-src 'self' https://analytics.bitgate.dev;If your policy defines script-src-elem, include https://analytics.bitgate.dev there as well. Inline settings, event queues, and onload examples also need your existing inline-code policy; prefer external app code or your framework’s nonce/hash mechanism rather than adding unsafe-inline.
Testing on localhost
By default, latest.js extracts location.host when data-hostname is omitted. On local development environments, this results in values like localhost:3000.
The script can still send on localhost; it is not a reliable development-mode exclusion. An unregistered local hostname is normally ignored by the collector, while an explicit production data-hostname can record local test traffic against your live site. To verify integrations, test on an explicit staging or production domain that matches a registered hostname. Do not direct localhost test traffic to your production hostname.
Next, explore Custom Events or review the Troubleshooting Guide.