Skip to content

Tracking script reference

The Statable tracking script is a small JavaScript bundle you embed once on every page you want to measure. It auto-tracks pageviews, engagement, scroll depth, outbound clicks, file downloads, and exposes window.statable.t() for custom events.

This page is the canonical reference for the bundle, HTML attributes, and install patterns. For the JavaScript API see JavaScript API. For wire format see Event payload reference.


The bundle

s.js, ~2.5 KB gzipped. Auto-tracks pageviews, engagement time, scroll depth, outbound link clicks, file downloads, form submits, and exposes window.statable.t() for custom events.

Embed widgets (geo-pop, top-cities, weather, etc.) ship as separate bundles (gp.js, gw.js, luw.js, mw.js, tcw.js). Documented under Embeds, not here.


Installation

Place the snippet in <head> with defer. defer ensures the script doesn't block HTML parsing and runs after the document is parsed.

<script defer src="https://statable.com/js/YOUR_SITE_ID/s.js"></script>

Replace YOUR_SITE_ID with the numeric Site ID from Site settings → Tracking Code. The SDK reads the ID from the URL path, so no data-id attribute is required on paid plans.


URL structure

PathUsed for
/js/{site_id}/s.jsStandalone tracker (paid plans)
/js/{hash}/{widget}.jsStandalone widget (paid plans) — gw, luw, mw, tcw
/js/{hash}/t/{widget}.jsWidget + tracker bundle (Hobby plan; tracker is bundled inside the widget)

The Hobby plan has no separate tracker — pick a widget and the install snippet is generated from /api/site/script-url.


Attributes reference

AttributeRequiredDefaultDescription
srcyes(none)URL of the bundle. Site ID is encoded in the path.
deferrecommended(none)Defer script execution until HTML is parsed
data-idnoderived from srcNumeric Site ID. Only needed for Hobby widget bundles (/t/...) as a fallback.
data-tracking-apino<script-origin>/api/eventOverride the ingest endpoint (proxy / self-hosted)
data-before-sendno(none)Name of a global function that mutates props before send
data-statable-{key}no(none)Sticky custom property attached to every event from this page load

data-tracking-api (optional)

By default the SDK posts events to <script-origin>/api/event. If your script is loaded from https://statable.com/js/YOUR_SITE_ID/s.js, the endpoint is https://statable.com/api/event.

Override this if you proxy traffic through your own domain (recommended for first-party tracking, ad-blocker resilience, or self-hosted ingesters):

<script defer
        src="https://statable.com/js/YOUR_SITE_ID/s.js"
        data-tracking-api="https://example.com/proxy/event"></script>

The endpoint must accept POST with Content-Type: text/plain and a JSON body. Exact shape: Event payload reference.


data-before-send (optional)

Enrich, redact, or sample events before they leave the browser. The value is the name of a global function (not an inline expression). The function receives the current props object and must return the modified object.

<script>
  function statableEnrich(props) {
    // Attach the current user ID, plan, and feature flags
    if (window.currentUser) {
      props.userId = window.currentUser.id;
      props.plan = window.currentUser.plan;
    }
    return props;
  }
</script>

<script defer
        src="https://statable.com/js/YOUR_SITE_ID/s.js"
        data-before-send="statableEnrich"></script>

Fires once per pageview, called with merged custom props (data-statable-* attributes + any per-call props). If the function throws, the SDK swallows the error silently and continues with unmodified props.


data-statable-* (optional)

Any attribute prefixed with data-statable- becomes a sticky custom property attached to every event sent from this page load. Useful for cohort, environment, or experiment tags.

<script defer
        src="https://statable.com/js/YOUR_SITE_ID/s.js"
        data-statable-cohort="beta"
        data-statable-env="production"
        data-statable-app-version="2024.4.28"></script>

Keys are forwarded verbatim (lowercased after the prefix), so the example produces:

{ "cohort": "beta", "env": "production", "app-version": "2024.4.28" }

These props are merged before data-before-send runs, so your hook can override or remove them.


SPA support

The SDK wraps history.pushState, history.replaceState, and listens for popstate / pageshow (back-forward cache). No configuration required. Pageviews fire automatically on client-side navigation in React Router, Vue Router, Next.js, SvelteKit, Astro, and any router that uses the History API.

If your router doesn't use history.pushState (rare), call window.statable.t('pageview') manually after each transition.


Performance impact

  • Bundle: ~2.5 KB gzip (s.js).
  • Loaded with defer: zero render-blocking, runs after DOMContentLoaded.
  • Network calls use fetch with keepalive: true so unload events don't delay navigation.
  • Engagement timer runs in a Web Worker. No main-thread cost.
  • Scroll tracking uses requestAnimationFrame. Fires at most once per frame.

See also


Ready to take control of your web analytics? Try Statable free for 30 days — no credit card required, full feature access, GDPR-compliant by default. Start your free trial or view a live demo.