All docs

Tracker Script Reference

Every option the Attribi tracking script accepts — restricting tracking to acquisition pages on a single-page app, stopping your login form creating leads, capturing OAuth sign-ups, and checking the tracker from the console.

Every option the Attribi tracking script accepts, what it does, and when you need it.

The script tag Attribi generates for you already contains everything required. The attributes below are for the cases the default cannot know about — a single-page app, a login form, a staging environment.


The script tag

<script src="https://track.yourdomain.com/tracker.js"
  data-site-id="YOUR_SITE_ID"
  data-api-key="YOUR_API_KEY"
  defer></script>

Place it before </head> on every page, not just your landing page — a visitor's journey usually spans several pages, and that journey is the thing being measured.

Using Next.js App Router? There is no </head> to paste into; it is generated from the metadata export. Render the script from your root layout with next/script and strategy="afterInteractive" instead. Top of <body> is equivalent for a defer script.

Required

AttributeWhat it is
data-site-idIdentifies your site.
data-api-keyPublic by design — it ships in a <script> tag on your website, so it is visible to anyone. It is not a secret. Requests carrying it are only accepted from origins registered to your site, so it cannot be used from anywhere else.

data-only-paths — restrict which pages are tracked

You need this if your site is a single-page app (React, Next.js, Vue, Svelte).

data-only-paths="/,/pricing,/blog"

Only those paths record pageviews. Absent or empty means every path is tracked.

Why a single-page app needs it

The tracker follows client-side navigation, which it must do to see a journey that never reloads the page. The mechanism it uses is global and outlives the component that loaded the script — so if you render the tag once in a root layout, it keeps recording pageviews for every route the visitor reaches afterwards, including your signed-in application.

Three consequences, and the second is the one that quietly damages your data:

  1. Privacy. You would be recording your customers' in-product activity as marketing data.
  2. Attribution is corrupted. Application routes carry no campaign parameters, so a visitor who arrives from a campaign and then moves into your app lands an unattributed touchpoint there — which becomes their last touch, in place of the campaign that actually brought them.
  3. Cost. In-app navigation is the highest-volume, lowest-value traffic on your site, and it counts against your plan's monthly event allowance.

Choosing the paths — the rule that matters

List your acquisition pages, not merely your public pages.

The two are not the same, and the difference is where people go wrong.

Do not include /login, /logout, or OAuth callback pages, even though they are public. They are not acquisition — they are where existing users re-enter. A Google sign-in that returns to a tracked page books a touchpoint sourced from accounts.google.com, which looks like Google referral traffic in your reports. Left in place, you accumulate a fictional acquisition channel that grows with retention rather than marketing, and it will read as one of your best-performing sources.

Matching rules

  • / matches the homepage exactly. It is not a prefix, or the list would mean nothing.
  • /blog matches /blog and /blog/any-post, but not /blogroll.
  • Whitespace around entries is ignored.

Pageviews only. Conversions are never suppressed by this list — losing a real lead because it happened on an unlisted page would be far worse than an extra pageview. To scope conversions, use data-convert-exclude-paths below.


data-convert-exclude-paths — stop capturing leads on certain pages

data-convert-exclude-paths="/login,/account/security"

Automatic conversion capture watches every email field on your site. That is what makes ordinary contact and sign-up forms work with no code — and it is also why your login form can create a lead every time an existing customer signs in.

That matters beyond a wrong number: leads are uploaded to your ad platforms as conversions, so it teaches their bidding algorithms to optimise toward people who already have accounts — real budget aimed at your worst-performing audience, while conversion volume goes up and reads as success.

This is a denylist, not an allowlist: anything not listed is still captured. A forgotten entry costs you an extra lead, never a missing one.

You may not need it

Attribi also skips forms that the HTML autocomplete contract marks as sign-in:

FieldMeaningCaptured?
autocomplete="current-password"an existing credential — sign-in❌ no
autocomplete="new-password"a credential being created — sign-up✅ yes
neithernot evidence either way✅ yes

Most auth libraries set these correctly, so your login form is often already excluded.

To check: open your login page with DevTools → Network filtered to your tracking domain, type an email into the field and click away. If no POST /api/convert appears, you are already covered.

A skipped capture logs its reason once to the console:

MTA: conversion capture skipped — form looks like a sign-in (autocomplete="current-password").

data-capture-signin-forms — turn the sign-in heuristic off

data-capture-signin-forms="true"

Only needed if the heuristic above is wrong for you — for example a sign-up form mistakenly marked current-password, whose sign-ups would otherwise never be captured.

Disables the heuristic only. data-convert-exclude-paths still applies, because a denylist can suppress but never un-suppress.


Capturing conversions

A conversion is what creates a lead and attaches the visitor's whole journey to it. Without one you have anonymous traffic and nothing to attribute.

Automatic — no code required

When a visitor types a valid email and the field loses focus, Attribi reads the surrounding form and captures email, phone and name together. Field matching is case-insensitive across type, name, id, placeholder and autocomplete, and names are also assembled from separate first/last fields.

This works on React and on embedded form builders (HubSpot, Marketo, Pardot), because the tracker also watches for forms added to the page after it loads.

Note it fires on blur, not on submit. Someone who types their email and clicks away without submitting is still recorded. That is intentional — it captures form abandoners — but it means your lead count includes people who never pressed the button.

Manual — window.MTA.convert()

Automatic capture needs an email field to observe. Call it yourself when there isn't one:

window.MTA?.convert({
  email: user.email,
  name:  user.name,    // optional
  phone: user.phone,   // optional
})

Required in three cases:

  • Sign-up with Google, Apple or another social login — no email field exists on the page
  • Forms inside a cross-origin iframe (Typeform, Calendly, HubSpot iframe mode)
  • Multi-step flows where the account is only created at the final step

Two rules:

Fire it on account creation only — never on every authenticated page render, or every returning user becomes a new lead and is uploaded to your ad platforms as a conversion.

Never call it on a URL carrying a token or an email — magic-link, password-reset and email-confirmation landing pages. Worth checking where your auth provider's confirmation and recovery emails actually land, since that is easy to overlook.


Checking the tracker from the console

window.MTA.lastStatus
// → { endpoint: "pageview", status: 200, reason: "ok", at: "…" }

reason is the field to read.

reasonMeaning
okRecorded.
rejected: origin not allowedThe page's origin is not registered to this site. Add it under Settings → Site & Tracker → Staging & development origins.
plan_limit_reachedYour monthly event allowance is used up. Requests still return success so your site never errors, but events are not recorded.
rate limitedToo many requests in a short window.
rejected: invalid API keydata-api-key does not match this site.
network failureThe request never reached us — commonly an ad blocker, or an unregistered origin whose rejection the browser will not let us read.

Testing before you go live

By default only your registered production domain may send tracking data, so localhost and preview deployments are refused. Register them under Settings → Site & Tracker → Staging & development origins — full origins including scheme and port, e.g. http://localhost:3000.


Need help? Contact us or sign in to your connections page for account-specific tooltips.