Docs / JavaScript SDK

JavaScript SDK

Hosted tracking snippet for any website. ~4 KB gzipped, no third-party dependencies.

Installation

Add this single tag to the <head> of your site. It loads asynchronously and does not block rendering.

HTML
<script async defer
  src="https://www.openanalyticsapi.com/sdk/oa.js"
  data-site="YOUR_SITE_ID"></script>

data-site is your public site_id — safe to expose in HTML. It is not an API token.

What gets tracked automatically

  • Pageviews on initial load and on SPA navigation (pushState / popstate)
  • Session start / end / bounce with 30-minute inactivity timeout
  • Anonymous user ID stored in localStorage; session ID stored in sessionStorage
  • Browser, OS, device type, screen and viewport size
  • Country, region, city, timezone — derived server-side from the anonymized IP
  • Referrer and UTM parameters (utm_source, utm_medium, utm_campaign, utm_term, utm_content)
  • Language preference from navigator.language

No cookies are set on the visitor's device in default mode. The snippet automatically respects the browser's Do Not Track signal when data-respect-dnt="true" is set on the script tag, and never sends events for headless browsers / known crawlers.

Manual API

Once the snippet has loaded, window.oa(...) is available. Calls made before load are queued and replayed after init, so it's safe to invoke oa() from inline scripts that may run earlier.

Custom event

window.oa('event', 'signup', { plan: 'pro', source: 'pricing_page' });

Identify call

Associate the current anonymous user with a stable identifier. Hash or pseudonymize before sending — do not pass raw emails.

window.oa('identify', 'user_123', { plan: 'pro' });

Conversion

window.oa('conversion', 'purchase', {
  revenue:  49.99,
  currency: 'USD',
  plan:     'pro'
});

Manual pageview

Useful for SPAs that don't use the History API, or when you want to record a virtual pageview after a state change.

window.oa('pageview', { url: '/virtual/checkout-step-2' });

Opt-out / opt-in

window.oa('optOut') immediately halts tracking on this browser. The tracker stops sending events, clears the locally-stored anonymous ID and session ID, and notifies the replay/heatmap addons to drop their buffers. The opt-out is persisted in localStorage and survives reloads.

window.oa('optIn') removes the opt-out flag. A page reload is recommended so the tracker can fully re-initialize for the current page view:

window.oa('optOut');

// Later, after the user re-consents:
window.oa('optIn');
window.location.reload();

A fresh anonymous ID is generated on the next page load — pre-opt-out and post-opt-in activity are not linked. See GDPR & privacy for the consent-banner pattern.

Configuration attributes

Attribute Default Description
data-site required Public site_id for the project.
data-api https://api.openanalyticsapi.com/collect Override the ingest endpoint (for self-hosted setups).
data-oa-off off Collect nothing on this page and write nothing to the device. Also settable as window.oaOff = true before the snippet. Use on auth screens.
data-oa-no-url off Count the visit but reduce URL and referrer to the bare origin (path and query dropped). Also window.oaNoUrl = true.
data-oa-full-url off Opt back in to sending the query string, which is dropped by default since v2.0.0. Also window.oaFullUrl = true.
data-respect-dnt false If "true", the snippet becomes a no-op when the browser sends Do Not Track.
data-replay-sample 0.1 Replay addon only. Probability that any given session is recorded. 0.1 means approximately 10% of eligible sessions. Set on the oa-replay.js script tag.

Addons (beta)

Two optional addons can be loaded after the core snippet. Each is hosted on the same domain, loads lazily, and respects the same oa('optOut') kill switch as the core tracker.

  • https://www.openanalyticsapi.com/sdk/oa-replay.js — session replay capture (DOM mutations, mouse, scroll, input events). PII masking on all <input>, <textarea>, and [data-oa-mask] by default. Pro+ plan required.
  • https://www.openanalyticsapi.com/sdk/oa-heatmap.js — click + scroll + attention heatmap collection. Pro+ plan required.

Collection is available in beta; beta viewers are available in the console under Replay and Heatmaps. Replay records with rrweb and the console plays back the reconstructed page. The heatmap viewer shows aggregated click hotspots + scroll-depth distribution; a screenshot-based page overlay is planned. Anything captured today is retained per your plan's retention setting.

Authentication and other sensitive pages

Do not measure authentication screens. Login, password reset, magic-link sign-in, two-factor setup, backup codes, data export and payment steps should either not load the tracker at all, or load it with URL collection turned off. One-time tokens frequently live in the URL itself, and analytics is not the place for them.

The snippet is usually included from a shared layout, so it ends up on every page — including the ones above. Three controls exist for that, and the first two need no change to the snippet itself:

Control Effect
window.oaOff = true Set it in <head> before the snippet. Nothing is sent and nothing is written to the device — no localStorage, no sessionStorage. Best fit for a shared layout: one condition covers every sensitive route.
window.oaNoUrl = true The visit is still counted, but the URL and referrer are reduced to the bare origin — path and query are both dropped. Use it when you want traffic volume from a page whose address is itself sensitive.
data-oa-off / data-oa-no-url The same two behaviours as attributes on the script tag, for when you control the snippet per page rather than the layout.
<!-- in your shared layout, before the snippet -->
<script>
  // one condition instead of removing the snippet on ten templates
  window.oaOff = {{ isAuthPage ? 'true' : 'false' }};
</script>

The replay and heatmap add-ons follow the same switches (since v2.0.1): with oaOff, a stored opt-out or DNT (when data-respect-dnt="true") they do not start at all, and oaNoUrl disables them too — a recording or a click map without the page is meaningless. Calling oa('optOut') mid-session stops all three scripts, drops anything buffered and forgets the stored id. On the server side, chunks for a project whose replay or heatmap is switched off in the console are discarded.

What is sent from a normal page

Query strings are not collected. Since v2.0.0 the tracker sends the URL and referrer without the query string, because that is where one-time tokens, OAuth code/state and return_to parameters normally live. Campaign tracking is unaffected — UTM parameters are read out separately into the event properties before the query is dropped, and the pages report has always grouped by path.

This does not protect a token in the path. A URL such as /password/reset/<token> carries the secret in the path itself, and the tracker cannot know which path segment is a secret. For those routes use oaOff or oaNoUrl — there is no automatic protection.

If you genuinely need the query string (and accept the consequences for whatever appears in it), opt back in with data-oa-full-url or window.oaFullUrl = true.

There is no autocapture: the tracker registers no click, submit, input or change listeners, and never reads element text, form fields or input values.

Server-side tracking for sensitive flows

The most robust option for an authentication or payment flow is to run no script in the browser at all and report the outcome from your backend once it has happened. You control exactly what leaves your server, and there is nothing on the page to review. See Server-side tracking.

Pinning a version (SRI)

/oa.js updates itself, which is why no integrity attribute can be attached to it — the hash would break on the next release. If you would rather verify exactly what runs on your pages, pin an immutable versioned build instead. Published versions are never overwritten.

<script async defer
  src="https://cdn.openanalyticsapi.com/v/2.0.1/oa.js"
  integrity="sha384-gfq0sTsKgfoay4KolBCEWxX6ZP5Eof16siLbkNk64EcrUP3S6OWG9V2hBz9BRxQF"
  crossorigin="anonymous"
  data-site="YOUR_SITE_ID"></script>

Current hashes for every file in a release are published at /v/<version>/integrity.json, and /v/latest.json names the newest release. The trade-off is yours: the self-updating loader gets fixes automatically, a pinned build never changes underneath you but has to be bumped by hand.

Replay sampling

The replay addon records a configurable percentage of eligible sessions. The sampling decision is made once per session and persisted in sessionStorage so the choice is stable for that session.

HTML
<script async defer
  src="https://www.openanalyticsapi.com/sdk/oa-replay.js"
  data-site="YOUR_SITE_ID"
  data-replay-sample="0.1"></script>

data-replay-sample="0.1" means approximately 10% of eligible sessions. Use "1" to record every session (useful for staging or low-traffic sites); the default if you omit the attribute is also 0.1.

Self-hosting the snippet

You can download oa.js and serve it from your own domain (improves Core Web Vitals and bypasses some ad-blockers). The hosted version is exactly what we serve; no obfuscated keys or per-customer builds.

Source

The snippet is around 4 KB gzipped, has no third-party dependencies, and is safe to embed across customer sites. It does not call out to Google, Meta, or any cloud provider — only to api.openanalyticsapi.com/collect (or your configured endpoint).

Part of the Open API ecosystem