# Configure the tracking script

Every script attribute, automatic events, excluding your own visits, engagement, Web Vitals and cross-domain tracking.

The default tag needs nothing but `data-site`. Everything on this page is optional — add attributes to the same `<script>` tag you already installed.

index.html:
```
<script
  defer
  data-site="YOUR_SITE_ID"
  data-domain="example.com"
  data-cross-domain="shop.example.net,docs.example.org"
  src="https://visitrack.app/tracker.js"
></script>
```

## Script attributes

| Attribute | What it does |
| --- | --- |
| `data-site` | Required. Your site id (`YOUR_SITE_ID`). Don't change it — it's how events reach this site. |
| `data-domain` | Root domain for the visitor cookie, e.g. `example.com`. Detected automatically; set it only if detection is wrong (e.g. unusual country-code domains). All subdomains of it share one visitor id. |
| `data-cross-domain` | Comma-separated list of other domains you own, e.g. `a.com,b.com`. Links to them carry the visitor id so one person stays one visitor across domains. See below. |
| `data-cookieless` | Store nothing in the browser. The visitor id becomes a server-side hash that rotates every 24 hours. Same as turning on [cookieless mode](https://visitrack.app/docs/cookieless) in Settings. |
| `data-auto="false"` | Turn off the automatic events listed below. Pageviews, outbound clicks, engagement and Web Vitals are still recorded. |
| `data-exclude="/app/*,/settings"` | Paths that are never tracked, comma-separated, `*` as a wildcard. Checked on every event, so client-side navigation into an excluded area stops tracking too. A page can also opt out on its own with `<meta name="visitrack-ignore">`. |
| `data-allow-local` | Track on localhost, 127.0.0.1, *.local and file:// pages, which are ignored by default. Useful for testing an install. |
| `data-debug` | Log every event the script sends (and why it skipped one) to the browser console. |

> **Where the visitor id lives** — In standard mode the anonymous visitor id is stored in a first-party cookie `_vt_vid` on your root domain (so `www.` and `app.` share visitors), mirrored to localStorage `_ana_vid`. With `data-cookieless` or cookieless mode, neither is written.

## Calling the script before it loads

The script loads with `defer`, so code that runs earlier can't call `window.visitrack` yet. Add this one-line queue stub above the tag: calls made before the script arrives are buffered and sent once it loads.

```
<script>window.visitrack=window.visitrack||function(){(window.visitrack.q=window.visitrack.q||[]).push(arguments)}</script>
<script defer data-site="YOUR_SITE_ID" src="https://visitrack.app/tracker.js"></script>
```

After that, `visitrack("signup", { plan: "pro" })` and `visitrack("identify", "user_123", { plan: "pro" })` work anywhere. See [Custom events](https://visitrack.app/docs/custom-events).

## Exclude your own visits

Open any page of your site with `?vt_ignore=1` added to the URL, e.g. `https://example.com/?vt_ignore=1`. That browser stops sending data until you visit a page with `?vt_ignore=0`. The flag is per browser and per domain, so repeat it on each device and domain you use. To exclude an office or a whole IP range instead, use **Settings → Exclusions**.

## Automatic events

These are recorded without any code and show up next to your custom events. Turn them all off with `data-auto="false"`.

| Event | When | Props |
| --- | --- | --- |
| `file_download` | A link to a file is clicked (pdf, zip, dmg, exe, csv, xlsx, docx, pptx, mp3, mp4 and similar). | `url`, `ext` |
| `contact_click` | A `mailto:` or `tel:` link is clicked. | `type` (`mailto` or `tel`) |
| `form_submit` | Any form is submitted. Field values are never read. | `form` (the form's id, name or action path) |
| `rage_click` | The same element is clicked 3 times in quick succession — usually something that looks clickable but isn't. | `label`, `element` |
| `js_error` | An uncaught JavaScript error (max 5 per page). | `message`, `source` (file name), `line` |
| `page_not_found` | The page title contains "404" or "not found", or the page has `<meta name="visitrack:404">`. | `url` |

Outbound link clicks (`outbound_click`) are always tracked and feed the Outbound tab.

## Engagement and scroll depth

For every pageview the script measures active time on the page (only while the tab is visible) and the furthest point scrolled, as a percentage of the page height. Both are sent when the visitor leaves the page or switches tabs, and power time-on-page and scroll depth in the Pages tab.

## Web Vitals

Real-user Core Web Vitals are collected from your actual visitors' browsers, once per page load: **LCP** (largest contentful paint), **INP** (interaction to next paint), **CLS** (cumulative layout shift), **FCP** (first contentful paint) and **TTFB** (time to first byte). Browsers that don't support a metric simply don't report it.

## Cross-domain tracking

Subdomains of the same root domain already share visitors through the root-domain cookie. For separate domains (say, a marketing site on `example.com` and checkout on `example-shop.com`), install the script on both with the same `data-site`, and list the other domain in `data-cross-domain` on each side:

```
<!-- on example.com -->
<script defer data-site="YOUR_SITE_ID" data-cross-domain="example-shop.com" src="https://visitrack.app/tracker.js"></script>

<!-- on example-shop.com -->
<script defer data-site="YOUR_SITE_ID" data-cross-domain="example.com" src="https://visitrack.app/tracker.js"></script>
```

When a visitor clicks a link to a listed domain, the script appends their visitor id as a `_vt_vid` query parameter; the script on the other side picks it up, removes it from the address bar, and keeps the same id. Cross-domain linking is off in cookieless mode, since there is no stored id to carry.

> **What's never tracked** — Localhost and file:// pages (unless `data-allow-local`), pages loaded inside an iframe, and automated browsers (Selenium, Playwright, Puppeteer and similar headless tools).
