Install the tracker
The script tag, every option it takes, and what changes for single-page apps.
All pages
The tracker is one script. It has no dependencies, no build step, and no companion SDK.
<script defer
src="https://api.trysonex.com/sonex.js"
data-website-id="YOUR_WEBSITE_ID"></script>
Put it in <head> and use defer so it never blocks rendering. data-website-id is the only required attribute; copy your real id from the Install button in the app.
Where it goes in a framework
The tag belongs in the document head, wherever your framework builds that:
- Plain HTML. Inside
<head>on every page. - Next.js. In the root layout’s
<head>(App Router), orpages/_document.tsx(Pages Router). - Astro. In your base layout’s
<head>. - Any other SPA. In
index.html, the one real document your app boots from.
Client-side routing needs nothing extra. The tracker hooks pushState, replaceState and the back/forward button, so route changes record pageviews on their own. Rapid successive navigations are debounced into a single pageview for the final URL, so a redirect on boot does not double count.
Script options
Every option below is optional and goes on the same <script> tag.
| Attribute | What it does |
|---|---|
data-website-id | Your website id. Required; without it nothing is sent. |
data-host-url | Send events somewhere other than the script’s own origin. |
data-auto-track="false" | Stop automatic pageview tracking. You then call window.sonex.track() yourself. |
data-do-not-track="true" | Skip visitors whose browser sends a Do Not Track signal. |
data-exclude-search="true" | Strip query strings from recorded URLs. |
data-exclude-hash="true" | Strip hash fragments from recorded URLs. |
data-domains="a.com,b.com" | Only collect when the page hostname is in this list. |
data-tag="staging" | Label every event from this tag with a tag you can filter on later. |
data-web-vitals="true" | Also report Core Web Vitals, which feed the Performance report. Loads a second small file, sonex-vitals.js (see below). |
data-before-send="fnName" | Name of a global function that can inspect, rewrite or drop each event. |
data-fetch-credentials="include" | Change the fetch credentials mode. Defaults to omit. |
Core Web Vitals are a separate file
Vitals measurement lives in its own bundle, sonex-vitals.js, served from the
same origin as the tracker. The tracker requests it only when your script tag
carries data-web-vitals="true", so a site that does not opt in never downloads
it and pays nothing for the feature.
If you restrict outbound requests with a Content Security Policy, allow both files from the API origin:
script-src https://api.trysonex.com;
connect-src https://api.trysonex.com;
Filtering by domain
data-domains is the cleanest way to stop staging or local traffic polluting production numbers:
<script defer
src="https://api.trysonex.com/sonex.js"
data-website-id="YOUR_WEBSITE_ID"
data-domains="example.com,www.example.com"></script>
Anything served from another hostname, including localhost, is then ignored.
Rewriting events before they leave
data-before-send names a function on window. It receives the event type and payload, and returns a payload to send, or a falsy value to drop the event:
<script>
window.scrubUrl = (type, payload) => {
// Never record a URL that carries a reset token.
if (payload.url.includes("/reset/")) return false;
return payload;
};
</script>
<script defer
src="https://api.trysonex.com/sonex.js"
data-website-id="YOUR_WEBSITE_ID"
data-before-send="scrubUrl"></script>
Define the function before the tracker loads. If it throws, the event is dropped rather than sent.
Excluding yourself
Your own visits are traffic too, and on a quiet site they distort everything. To stop tracking your own browser, run this once in the console on your site:
localStorage.setItem("sonex.disabled", "1");
That browser stops sending events until you remove the key. It is per browser and per site, and nothing about it reaches sonex.
Next: Verify your install.