LiteStats iconLitestats

Tracking Script

A deep dive into how the LiteStats tracking script works under the hood.

How it works

The tracking script (track.js) is a lightweight JavaScript file (about 5 KB gzipped) that runs on your visitors' browsers. It collects basic pageview data and sends it to the LiteStats servers without cookies or fingerprinting. It filters common patterns of personal data before sending.

Installation

<script
  async
  src="https://getlitestats.com/track.js"
  data-site="YOUR_SITE_ID"
  crossorigin="anonymous" referrerpolicy="no-referrer"
></script>
AttributeRequiredDescription
data-siteYesYour unique site ID (shown in the Add Site modal after creating a site, and always available in Account Preferences → Sites)
asyncRecommendedLoads the script without blocking page rendering
crossoriginRecommendedEnables proper CORS handling
referrerpolicyRecommendedSet to no-referrer to hide the page URL during the script download

What data is collected

Each pageview sends the following data:

  • Page URL — the path being visited (e.g. /blog/my-post)
  • Referrer — where the visitor came from (e.g. google.com), or "direct"
  • UTM parameters — campaign tracking tags from the URL (utm_source, utm_medium, utm_campaign, utm_term, utm_content)
  • Session ID — a random UUID stored in sessionStorage (not a cookie, resets when the tab closes)
  • Timestamp — when the pageview happened
  • User agent — used server-side to derive browser, OS, and device type (not stored raw)

Event tracking

Track button clicks, link clicks, and form submissions by adding an event name:

<button data-ls-event="Signup clicked">
  Start free
</button>

Links and forms work the same way:

<a href="/pricing" data-ls-event="Pricing clicked">View pricing</a>

<form data-ls-event="Contact form submitted">
  ...
</form>

For custom JavaScript events, call:

litestats.track("Signup clicked", {
  plan: "Pro",
  location: "Hero"
});

Optional event properties can also be added with data-ls-prop-* attributes:

<button
  data-ls-event="Signup clicked"
  data-ls-prop-plan="Pro"
  data-ls-prop-location="Hero"
>
  Start free
</button>

Personal data is not accepted in custom event properties. Only predefined categories are allowed. Never send names, email addresses, phone numbers, addresses, user IDs, or other information about a person.

  • plan: Free, Trial, Starter, Basic, Pro, Business, Enterprise.
  • location: Hero, Header, Footer, Sidebar, Navigation, Pricing, Modal, Checkout.

Values are case-insensitive. Here, location means placement on the page, not a visitor's physical location. Events without properties still work. If any property or value is not approved, the entire event is rejected: the script displays a generic console warning, and direct API requests receive HTTP 400. Free text, numeric values, booleans, nested objects, arrays, and null values are not accepted.

Custom properties use the strict categories above. Other tracking fields use the automatic filtering described below.

Automatic personal data filtering

The browser filters page paths, event names, campaign values, and referrers before sending them. The collection API independently applies the same rules, including to older scripts and direct API requests.

  • Path queries and fragments are removed. Segments containing email addresses, phone-like numbers, IP addresses, UUIDs, or long token-like strings become :redacted.
  • Values after common account, user, profile, order, authentication, and password-reset route names are hidden too. For example, /users/brian becomes /users/:redacted.
  • Events with suspicious names are dropped; direct API submissions receive HTTP 400. Use a fixed label such as Signup clicked, never a visitor's details.
  • Suspicious campaign values are omitted without dropping the pageview or event. Cached campaign values are checked again and removed if rejected.
  • Referrers are reduced to hostnames before transmission, preserving source-name reporting. Collection requests suppress the HTTP Referer header too.

Event names are limited to 80 characters and campaign values to 200. Encoded values are checked too. Collection errors use generic messages without echoing submitted values. Redacted paths are grouped together in reports, so funnels should use the recorded path.

Automatic filtering is a safeguard, not a guarantee of anonymity. It can miss names, addresses, and unusual identifiers, and can hide harmless values that resemble sensitive data. Keep personal data out of tracking fields. These rules apply to new requests; they do not clean historical records or infrastructure logs.

Add referrerpolicy="no-referrer" to existing script tags as shown above to suppress the page URL when the browser initially downloads the script. Browser filtering takes effect after a visitor loads the updated tracker.

What is NOT collected

  • No IP addresses are stored
  • No cookies are set
  • No browser fingerprinting
  • No form contents are read; obvious personal data in tracking fields is filtered as described above
  • No cross-site or cross-device tracking

Browser privacy signals

Do Not Track (DNT) and Global Privacy Control (GPC) are respected by default. In Account preferences → Privacy & Data, the Respect browser privacy signals switch applies to all your current and future sites. Turning it off allows normal tracking for visitors who send these signals. No installation snippet change is needed.

When a signal is present, the script checks the account preference before creating a session or accessing session/campaign storage. With the switch on, it sends no pageviews, custom events, or pings. If the preference check fails, tracking stays off. The API also honours the setting for DNT and GPC request headers.

GPC is treated as a complete analytics opt-out here, although the signal specifically concerns selling or sharing personal information. Browser support varies, and an absent signal is not consent. Settings are picked up on the next page load; visitors must have loaded the updated tracker.

The script download and site-ID-only preference request can still appear in infrastructure logs. This setting does not erase previously stored analytics or existing browser storage.

Session tracking

LiteStats uses sessionStorage to generate a random UUID for each browsing session. This ID groups pageviews into sessions but cannot be used to identify a person. It's automatically cleared when the browser tab is closed — there is no persistent tracking.

Exclude your own visits

To keep your analytics accurate, you can exclude your own pageviews from being recorded. This works regardless of your IP address — no static IP required.

Open your browser's DevTools console on your tracked website and run:

localStorage.setItem("litestats_ignore", "true")

That's it. The tracking script will silently skip all pageviews from that browser. The flag persists across sessions and tab closes — you only need to set it once per browser.

To re-enable tracking (e.g. for testing), run:

localStorage.removeItem("litestats_ignore")

Bot filtering

All incoming requests are checked against a comprehensive list of known bots, crawlers, and headless browsers. Bot traffic is silently discarded and never recorded, so your analytics only reflect real human visitors.

Performance impact

  • The script is about 5 KB gzipped
  • Loads asynchronously — does not block rendering
  • Makes a single lightweight API call per pageview
  • No impact on Core Web Vitals or Lighthouse scores

Content Security Policy (CSP)

If your site uses a Content Security Policy, add the following directives:

script-src 'self' https://getlitestats.com;
connect-src 'self' https://getlitestats.com;

Single Page Applications (SPAs)

The tracking script automatically detects client-side navigation using the History API. It will track route changes in frameworks like Next.js, React Router, Vue Router, and similar without any extra configuration.

Tip: You can verify the script is working by opening your browser's DevTools → Network tab and looking for requests to getlitestats.com/api/collect.