All posts

Writing a Tracking Script That Does Not Slow Down the Site

August 10, 20267 min read

The obligation

A tracking script is the one piece of your product that runs on someone else's site, on every page, for every visitor. If it is slow, their Core Web Vitals suffer — and Core Web Vitals affect their search ranking.

That makes performance a correctness requirement, not a nice-to-have.

Never block rendering

<script defer src="https://analytics.example.com/script.js"></script>

defer is the right default: the parser continues, and the script runs after the document is parsed. async would also work, but defer preserves execution order if a site loads more than one.

The failure mode to avoid is a bare <script src> in <head>. The parser stops, waits for a network round trip to your server, and the customer's LCP now includes your latency.

Budget the size

Under 5 KB gzipped is achievable for full pageview, event and Web Vitals collection. Getting there means writing plain DOM code — no framework, no polyfills for browsers you do not support, no date library for one toISOString() call.

For comparison: a heavy tag manager can exceed 100 KB, and the difference is measurable in field data.

sendBeacon for the exit path

The hard case is sending an event as the page unloads. fetch gets cancelled; the browser is tearing the page down.

function send(payload) {
  const body = JSON.stringify(payload);
  if (navigator.sendBeacon) {
    navigator.sendBeacon(endpoint, new Blob([body], { type: 'application/json' }));
  } else {
    fetch(endpoint, { method: 'POST', body, keepalive: true }).catch(() => {});
  }
}

sendBeacon is queued by the browser and delivered regardless of what happens to the page. It is the only reliable way to capture session-end events.

Fail silently, always

If the collector is down, the customer's site must not notice:

try { send(payload); } catch { /* analytics must never break a page */ }

Every network call ends in .catch(() => {}). An analytics outage that throws console errors on customer sites is a worse incident than the outage itself.

Collect Web Vitals from the field

Lab tools measure one run on one machine. Field data measures what your visitors actually experienced.

The web-vitals library is small and handles the subtleties — LCP can change until the page is interactive, CLS accumulates over the session lifetime. Report on visibilitychange rather than unload, which is unreliable on mobile.

Respect Do Not Track and opt-out

Check navigator.doNotTrack and a local opt-out flag before sending anything. It costs two lines and it is the difference between a privacy-first claim being true and being marketing.

Try InsightsTrack free

Open-source, self-hosted, privacy-first analytics — explore the live demo, no install required.

Open live dashboard