Skip to content

JavaScript API

Once s.js is on the page, the SDK exposes one global: window.statable.t(). Use it to fire custom events from anywhere, click handlers, framework lifecycle hooks, fire-and-forget instrumentation deep in your code.

This page covers manual events. For HTML attributes see Tracking script reference. For payload shape see Event payload reference.

The legacy global window.__usdTrackEvent still exists internally but is not part of the public API. Always use window.statable.t().


Signature

window.statable.t(name: string, props?: Record<string, any>): void
ParameterTypeRequiredDescription
namestringyesHuman-readable event name. Title Case recommended.
propsobjectnoCustom properties merged into the event payload as p.*

Returns undefined. Fire-and-forget. No callback, no promise.


Basic usage

Event without props

window.statable.t('Sign Up');

Event with custom props

window.statable.t('Purchase', {
  plan: 'pro',
  amount: 49,
  currency: 'USD'
});

Property values can be strings, numbers, or booleans. Nested objects are accepted but flat types index better in the dashboard.


Framework examples

React

import { useEffect } from 'react';

function PricingPage() {
  useEffect(() => {
    window.statable.t('Pricing Viewed');
  }, []);

  const handleUpgrade = (plan) => {
    window.statable.t('Upgrade Clicked', { plan });
  };

  return <button onClick={() => handleUpgrade('pro')}>Upgrade</button>;
}

Vue

<script>
export default {
  mounted() {
    window.statable.t('Modal Opened', { modal: 'newsletter' });
  },
  methods: {
    submit() {
      window.statable.t('Newsletter Subscribed');
    }
  }
}
</script>

Plain DOM

<button id="cta">Start trial</button>
<script>
  document.getElementById('cta').addEventListener('click', () => {
    window.statable.t('Trial Started', { source: 'hero' });
  });
</script>

Safe-call pattern (script not yet loaded)

If your code might run before s.js finishes loading (inline scripts in <head>, or a deferred bundle that hasn't parsed yet), guard against the global being undefined. The simplest pattern is an existence check on the call site:

window.statable?.t?.('Early Event', { source: 'hero' });

The optional chaining drops the call when the SDK isn't ready yet, so you don't crash with a reference error. The SDK does not currently auto-replay a queue, so if you depend on the early event being recorded, fire it after DOMContentLoaded.


Auto-tracked events

Some events fire automatically. They appear in your dashboard alongside custom events.

TriggerEvent name (filterable)
Page load + SPA navigationpageview
Tab unload / hidden / 30-min timeoutengagement (system)
Click on <a> to a different hostOutbound Link Click
Click on <a> with download extension or download attrFile Download
Submit on <form data-statable-event="...">Your event name

engagement is a system event that powers session duration and scroll-depth metrics. Not meant to be filtered in the UI like a custom event. Treat it as infrastructure.

File Download matches: pdf, zip, rar, gz, tar, 7z, doc(x), xls(x), ppt(x), csv, exe, dmg, iso, mp3, mp4, avi, mov. Links with a download attribute also count regardless of extension.


Naming conventions

  • Use Title Case: Sign Up, Pricing Viewed, Plan Changed.
  • Keep names short and human-readable. They appear in dashboards and reports.
  • Use property names, not event names, for variable data: 'Plan Changed', { from: 'free', to: 'pro' } instead of 'Plan Changed Free To Pro'.
  • Stay consistent across your codebase. Mismatched casing creates duplicate rows.

Reserved names

The SDK internally wraps custom event names in square brackets ([Event Name]) to distinguish them from system events on the backend. Do not pass names that already contain brackets. The names pageview and engagement are reserved and bypass the bracket wrapping.


Opt-out

Set a flag in localStorage to exclude a visitor from tracking:

localStorage.setItem('analytics_ignore', 'true');

The SDK checks this on every send and silently drops events when set. To re-enable:

localStorage.removeItem('analytics_ignore');

Scope: per-browser, per-domain (standard localStorage rules). Useful for excluding your own team, contractors, or honoring user-level Do-Not-Track preferences.


Bot detection

Two client-side checks skip tracking entirely:

  • navigator.webdriver === true. Set by Selenium, Cypress, Playwright, Puppeteer (when not stealth-patched).
  • window.Cypress. Additional Cypress-specific guard.

Server-side filtering (multiple UA parsers, IP heuristics) runs on top. See Event payload reference.


Status code for error pages

For 404, 410, or other non-200 pages, hint the status to the SDK with a meta tag in <head>:

<meta name="status:code" content="404">

Read on every pageview and added to the payload as sc. The dashboard uses it to separate broken-page traffic from healthy traffic and power the Error pages report.


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.