Skip to content
Reference

beat.js

beat.js is the client tracker. It is 1,515 bytes gzipped, minified as served, and it sets no cookies. It writes two localStorage keys on your own domain: the first-touch attribution key, and the owner opt-out flag.

Script attributes

Set on the <script> tag, read via document.currentScript.

FieldTypeRequiredDescription

Because beat.js reads document.currentScript, it must be a parser-inserted tag. Do not load it through a bundler-injected loader like next/script, which leaves currentScript null.

window.kymo

After load, window.kymo is a function for custom goals.

FieldTypeRequiredDescription
window.kymo('signup');
window.kymo('purchase', { revenue: 49 });

If the owner opt-out is active, window.kymo is still defined but is a no-op, so your calls never error.

window.kymo.attribution()

Returns a copy of this browser's stored first touch, or null when attribution is off, when the browser has no stored value, or when storage is unavailable. It is always safe to call.

window.kymo.attribution();
// { s: 'newsletter', m: 'email', c: 'launch', l: '/pricing', t: '2026-05-02T09:14:00.000Z' }

See First-touch attribution for every field and for passing the value to Stripe.

The beacon payload

Each event is a text/plain POST to /api/beat via navigator.sendBeacon (falling back to fetch with keepalive). The body is JSON:

FieldTypeRequiredDescription

The payload carries no cookie and no identifier you set. See /api/beat for what the server does with it.

Automatic behavior

  • Pageviews fire on load and on every history.pushState and popstate, de-duplicated on identical path plus query.
  • Outbound clicks — a click on a link to a different hostname sends an outbound event.
  • Auto-goalstel:, mailto:, WhatsApp links, and form submits fire goals with no configuration.

Size

beat.js is 1,515 bytes gzipped. That is the minified file kymo.in serves, measured from the built artifact when these docs are built, so the figure here cannot drift from the file your visitors download.

The script loads on every page view, before the rest of your page finishes rendering. A smaller file is a smaller file. We have not measured what it does to your page speed scores, and we make no claim about that.

Storage

beat.js writes two localStorage keys, both on your own domain, and no cookie:

FieldTypeRequiredDescription

An opted-out browser writes neither key. Storage that is blocked or full is caught, and the beacon still sends.

Opt-out and local development

  • ?kymo=ignore sets a per-browser localStorage flag that stops sending; ?kymo=track clears it.
  • On localhost, 127.*, and 192.168.*, beat.js does nothing.