DocsProducts / Install the tracker

Install the tracker

One line of JavaScript, pasted before the closing body tag, on every page. It is the same line on every website — there is no site key and nothing to fill in. This page is the reference version: the platforms, the byte figures, the failure modes, and what the snippet does and does not touch on the page it sits on.

The line

Paste immediately before </body>, on every page

<script async src="https://tracker.frontlatch.com/t.js"></script>

Select the text above and copy it — the button needs JavaScript, this does not.

Copied from INSTALL_LINE in apps/web/components/install/content.ts, which matches installTag() in packages/tracker/src/snippet.ts. This is the line /install serves and there is no second version of it.
  • It is byte-for-byte identical on every site. There is no site ID, no account key and nothing to fill in — a site is recognised by its own domain name. If anybody ever hands you a version of this line with a code or a number in it, it did not come from us.
  • Where it must not go: not in the <head>, not inside a form, and not into a page-builder text widget, which will escape the code and print it on the page as visible words instead of running it.
  • There is no account to create and nothing to buy. Removing it is deleting the line.

Seven platforms

WordPress leads because it is the most likely answer: of the fifteen Sydney service-business sites scanned on 25 August 2026, nine run WordPress — seven say so outright and two give themselves away with WordPress-only plugins. One runs Wix. The other five do not announce what they are. Source: packages/scanner/benchmark/reports/.

Where the line goes
PlatformRoute
WordPressPlugins → Add New → a "headers and footers" plugin (WPCode, Insert Headers and Footers) → its Footer or Body (end) box. Use a plugin rather than editing theme files: a theme update wipes a direct edit and the tracker silently stops with nobody noticing. If your theme already has a Footer scripts or Custom code box, use that and skip the plugin.
WordPress with ElementorElementor → Site Settings → Custom Code → Add. Location: Body – End. Publish.
SquarespaceSettings → Advanced → Code Injection → the Footer box, not the Header box. Save.
WixSettings → Custom Code → Add Custom Code. All pages. Load code once per page — not "once per visit", because every pageview should be counted. Place code in: Body – end.
ShopifyOnline Store → Themes → ⋯ beside the live theme → Edit code → theme.liquid in Layout. Paste on the line just above </body>.
Google Tag ManagerNew Tag → Custom HTML → paste → Triggering: All Pages → Save → **Submit**. A container does not go live until you Submit, and that is the step everybody forgets. If the site already uses GTM this is the fastest route of the lot.
Plain HTMLJust above </body> on every page. If there is a shared footer include — footer.php, footer.html, _footer.inc — put it there once and every page picks it up.

Source: apps/web/components/install/content.ts · platforms

Confirming it works

  1. The quick check. Load any page, view source, search for t.js. If the line is there, it is installed.
  2. The real check. Open developer tools, click Network, reload. t.js loads with status 200. Now navigate away or close the tab: a request to /b fires and returns 204. That 204 is the collector saying "received" — it always answers 204 whatever it decides about a beacon, because the response is seen by a stranger’s browser on somebody else’s site.
  3. The lazy check, and honestly the best one. Tell us the domain and load a couple of pages. The site appears at our end within a minute and we confirm back.
If the line is there and nothing arrives
CauseWhat to do
Global Privacy Control or Do Not Track in your own browserThe big one, above. Your own visit is invisible by design.
An ad blocker in your own browserTry a private window, or a different browser.
A caching plugin still serving the old copy of the pageClear the cache. WordPress caching plugins are the usual culprit.
A Tag Manager container saved but never submittedSaving a tag is not publishing it. Open the container and press Submit.
The line went into the <head>, or into a text widgetIn the head it can still work. A page-builder text widget will print the code on the page as visible words. If you can see the line on your site, that is what happened.

Source: apps/web/components/install/content.ts · troubleshooting

What it costs the page

Page cost
ItemValue
File size5,686 bytes minified · 2,308 gzipped · 2,014 brotli — 2.3 KB on the wire
Loadingasync — the browser never waits for it, so it cannot delay the page appearing
RequestsOne per pageview, sent as the visitor leaves the page or after 20 seconds, whichever comes first. Never during loading.
Typical request sizeAbout 200 bytes; about 600 bytes on a pageview with a filled six-field form
ListenersAll registered passive — the browser’s own guarantee that a script cannot make scrolling stutter
Changes to your pageNone. No markup added, no styles changed, no redirects, nothing done to your forms.
Measured on 26 August 2026 against the live endpoint, not estimated. The collector URL is baked into the build, so its length moves these figures by roughly a byte per character. One ordinary photograph on a homepage is forty to a hundred times bigger than this file.

Source: apps/web/components/install/content.ts · weight

The package asserts a budget rather than a measurement, because the measurement moves with the endpoint. The budget is 5,800 bytes and the suite fails if a build breaches it; at the 35-character endpoint the tests use, the built file is 5,689 bytes. Source: packages/tracker/src/snippet.ts and the test run.

The standing rule when the budget binds is written down in the package: cut collection the classifier does not use before touching the budget, and if the only candidates left are signals the classifier does use, raise the budget and record why. That rule has been exercised twice and both moves are on the record — once to restore a detection probe that a byte ceiling had forced out, and once to buy three privacy fixes at +573 bytes with no signal dropped.

The whole snippet is wrapped so that if it ever hit a bug it stops quietly and the page carries on as though it were not there. That is not a promise on trust: the suite runs the actual built file against a stub page and fails the build if it throws.

Removing it

Delete the line. That is the entire removal. There is nothing else to undo: no cookie to clear, no account to close, no plugin left behind, no file on any visitor’s computer. Do it at 2am without telling anybody and nothing breaks at either end.

If you want the visit counts already collected deleted as well, say so and they are deleted — though there is nothing in them that names anybody. Everything is deleted automatically after 60 days regardless, and nothing survives that, not even an aggregate.

Building the snippet yourself

The tag is produced by one function, and the file it points at is built from the classifier and the collection code with the endpoint compiled in.

installTag()

export function installTag(scriptUrl: string): string {
  return '<script async src="' + scriptUrl + '"></script>';
}
Verbatim from packages/tracker/src/snippet.ts.

Building it

npm run snippet -- --endpoint https://<your-collector-host>/b --out dist/t.js
Verbatim from the usage line packages/tracker/src/cli.ts prints.

Written from

  • The tag builder and the byte budgetpackages/tracker/src/snippet.ts
  • The build commandpackages/tracker/src/cli.ts
  • The package explainerpackages/tracker/README.md
  • The owner-facing install pageapps/web/components/install/content.ts