Skip to content

Privacy

Akayashuu edited this page Sep 27, 2026 · 6 revisions

Privacy

Privacy protection is built into the core of Takt, not bolted on afterwards. No cookie, no persistent identifier, no personal data leaves the browser. Visitors have nothing to accept.

When an event is not sent

Before any send, Takt checks four conditions in this order. If any is true, the event is silently dropped:

  • 1. Visitor opt-out — The visitor declined measurement: localStorage contains takt_ignore = '1'.
  • 2. Do Not Track — The browser sends the DNT header and respectDnt is on (default; turn it off with data-respect-dnt="false" or respectDnt: false).
  • 3. Localhost / private IP — The host is local or on a private network (localhost, ::1, 0.0.0.0, *.local, 127.*, 10.*, 192.168.*, 172.16–31.*) and excludeLocalhost is on (default).
  • 4. Sampling — sampleRate (or data-sample-rate) is below 1 and this event falls outside the kept fraction.

The opt-out, DNT and localhost guardrails are on by default. In local development, nothing is reported: that's intentional, not a bug.

With the npm SDK and framework wrappers, exclude adds another lever: any page or named event whose path starts with an excluded prefix (e.g. ['/app','/account'], segment-bounded so /app matches /app and /app/… but not /application) is never tracked. It's checked at send time, so it holds across SPA navigation. The minimal CDN snippet omits this option.

Giving control to the visitor

You can expose a "Don't track me" button that drives the opt-out. The choice is written to localStorage (key takt_ignore), so it persists across visits on this browser.

In an npm integration, use the dedicated functions:

import { optOut, optIn, isOptedOut } from '@vskstudio/takt-core'

optOut()     // sets takt_ignore='1', no event is sent anymore
optIn()      // removes the flag, resumes tracking
isOptedOut() // true while the flag is set

These functions need no instance: a consent banner can call them before init() has run, and every instance created later honours the choice. The framework wrappers re-export them, and their useTakt() (or TaktService) consent methods work before the provider has mounted.

On the snippet (CDN) side, the global window.takt only exposes track. So drive the opt-out directly via localStorage — the snippet reads this key before each send:

function toggleTracking() {
  if (localStorage.getItem('takt_ignore') === '1') {
    localStorage.removeItem('takt_ignore') // opt-in
  } else {
    localStorage.setItem('takt_ignore', '1') // opt-out
  }
}

URL scrubbing

By default, Takt strips the query string and hash from every URL before sending: the page URL, the referrer and outbound link destinations keep only origin + path. A token, email or identifier slipped into ?... or #... therefore never reaches analytics.

You can tune this: trackQuery keeps the whole query, queryParams keeps only an allowlist, and scrubUrl replaces the logic with your own function (npm). Since 0.9.0, scrubUrl also receives the url prop of Outbound Link: Click and File Download events, so an identifier in the path of a link or a file (/invoice/42.pdf) can be masked before it is sent. On the snippet, use data-track-query or data-query-params for the same effect.

Route redaction

Stripping the query and hash leaves the path untouched. A route that carries a secret in the path, such as /verify/abc123, /reset/9f2c… or /invite/abc, therefore sends that value in clear by default. Since 0.10.0, the npm SDK and the framework wrappers offer two opt-in modes that replace the real path with the route pattern.

redactRoutes: only the sensitive routes

init({
  domain: 'example.com',
  redactRoutes: ['/verify/[token]', '/reset/:code', '/invoices/[id].pdf']
})

A path matching one of the patterns is sent as the pattern: /verify/abc123 becomes /verify/[token]. Every other path keeps its real value, so your per-page stats stay readable. The rule applies to:

  • the page URL of pageviews and custom events;
  • the referrer, when it comes from your own site (internal navigation);
  • the url of Outbound Link: Click and File Download events pointing to your own origin;
  • the path reported by 404 tracking.

Patterns accept both route syntaxes:

Syntax Examples Matches
SvelteKit, Astro, Next.js [token], [[lang]], [...rest], (group) one segment, an optional segment, any tail, ignored group
Vue Router, React Router, Angular, Solid :token, :lang?, *, **, :path* one segment, an optional segment, any tail

A parameter can share a segment with fixed text (/invoices/[id].pdf). Patterns are matched against the raw and the decoded path, and the value sent is the normalized pattern (:code(\d+) is sent as :code, a (group) segment is dropped).

routeTemplates: every page as a template

init({
  domain: 'example.com',
  routeTemplates: true,
  routeTemplate: () => currentRoute.id
})

With routeTemplates: true, every page is sent as its route template: /blog/hello becomes /blog/[slug], /users/42 becomes /users/:id. The core cannot know your router, so it needs a routeTemplate resolver; the framework wrappers provide one. When the resolver returns nothing (no matched route), redactRoutes still applies and the real path is sent otherwise. Same-origin referrers are reduced to the site origin in this mode, since their template is unknown.

The trade-off. routeTemplates suits a fully private app (a dashboard, an account area) where no path is worth reading as is. On a public site, it merges every article, product or profile into a single row: /blog/[slug] gets all the traffic and you can no longer tell which post performs. There, prefer redactRoutes on the few sensitive routes.

exclude is still evaluated on the real path. The ≤ 1 kB CDN snippet does not support redactRoutes nor routeTemplates: use the npm SDK or a framework wrapper when a route carries a secret in its path. On the server, the Node client takes redactRoutes and a per-call route, see Server-side (Node).

What Takt does not collect

  • No cookie and no session-identifier storage.
  • No IP address kept on the client, no browser fingerprinting.
  • No query string or hash in URLs (stripped by default), and no secret path segment when redactRoutes covers the route.
  • No personal data: keep your props anonymous and low-cardinality.

Because no personal data is processed, Takt integrates without a consent banner in most jurisdictions. Always check your own legal context.


Source: github.com/taktlytics/takt-core · npm @vskstudio/takt-core

Takt — @vskstudio/takt-core


React · Vue · Svelte wrappers: see the docs site.

Clone this wiki locally