JavaScript SDK
Integrate the Mythic Analytics JavaScript SDK to track events, page views, and user identity from the browser with automatic batching, session management, and privacy controls.
Overview
The Mythic Analytics JavaScript SDK captures events, page views, and user identity data from the browser. It manages batching, sessions, attribution, and remote configuration automatically.
Key capabilities:
- Initialize with a publishable key (
pk_prefix, safe for client-side use) - Track custom events with
captureand page views withpageview - Identify users with
identifyand create aliases withalias - Manage super properties that attach to every event
- Control consent, opt-in/opt-out, and HIPAA compliance
- Auto-capture page views, page leaves, UTM parameters, and click IDs
- Remote configuration for tags, snippets, and transformers
The SDK uses a publishable key starting with pk_. This key is safe to expose in client-side code. Never use admin or secret keys in the browser.
Install or load the SDK
Paste the loader snippet
Drop this into <head>, as high as possible. It starts the remote-config request immediately, preloads the SDK core so it downloads in parallel with the loader rather than one round trip behind it, installs the error listeners, stubs window.mythic, and calls init — one tag, nothing else to add.
<script>!function(){var u="https://api.adberserk.com/decide?key=pk_your_publishable_key&v=2",r=fetch(u,{cache:"default"});r.catch(function(){});window.__mythicCfgPrefetch={url:u,response:r};var l=document.createElement("link");l.rel="modulepreload";l.href="https://api.adberserk.com/cdn/core/mythic.mjs";(document.head||document.body).appendChild(l);var b=window.__mythicErr=window.__mythicErr||{q:[],sink:null};if(!b.on){b.on=1;var p=function(x){b.sink?b.sink(x):b.q.length<50&&b.q.push(x)};window.addEventListener("error",function(v){p({k:0,m:v.message,f:v.filename,l:v.lineno,c:v.colno,e:v.error})},!0);window.addEventListener("unhandledrejection",function(v){p({k:1,r:v.reason})},!0)}var e=[];window.mythic={init:function(t,n){return e.push(["init",t,n]),window.mythic},q:e};["capture","pageview","identify","alias","reset","opt_in","opt_out","flush","debug","getDistinctId","getSessionId","getDeviceId","isBot","getConfig","set","set_once","unset","get_property","get_super_properties","clear_super_properties","getPageContext","getExperimentAssignments","refreshConfig","grantConsent","revokeConsent"].forEach(function(t){window.mythic[t]=function(){return e.push([t].concat(Array.prototype.slice.call(arguments))),window.mythic}});var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://api.adberserk.com/cdn/m.js";(document.head||document.body).appendChild(t)}();
mythic.init("pk_your_publishable_key", {api_host: "https://api.adberserk.com"});</script>
GET /api/v1/clients/{id}/loader returns this exact snippet with the client's key, custom domain, and global name already filled in. Copy it from there rather than editing by hand.
Place the snippet high in <head>, before any tag manager. It installs
its uncaught-error / unhandled-rejection listeners synchronously the moment
it runs, so errors thrown before it executes can't be captured. If you
inject it through Google Tag Manager (or load it after GTM), GTM's own
initialization errors fire before the listeners exist and won't appear in
error tracking.
Track events
<script>
// Methods can be called on window.mythic right away — calls made
// before the core finishes loading are queued and replayed.
window.mythic.capture("Signup started", { plan: "pro" });
</script>
With the CDN loader, the global is window.mythic (lowercase). It exposes pre-init stubs for every public method, so you can call window.mythic.capture(...), window.mythic.identify(...), etc. before initialization completes — those calls are queued and replayed once the core loads.
A bare <script src="https://api.adberserk.com/cdn/m.js"></script> followed by window.mythic.init(...) also works, but it can't capture errors thrown before the core finishes loading. Use the snippet above unless you have a reason not to.
Initialize the SDK
init(key, config?)
Initialize Mythic. The CDN global exposes window.mythic.init(...), which loads the SDK core, applies your config, and wires up the queued method stubs so calls made before init completes are replayed.
Publishable project key starting with pk_.
Optional configuration overrides. See the configuration reference for all options.
<script>!function(){/* ...loader snippet... */}();
mythic.init("pk_your_publishable_key", {
api_host: "https://analytics.yourdomain.com",
debug: true,
batch_size: 20,
autocapture: true,
capture_pageview: true,
hipaa: false
});</script>
When the SDK is loaded from a custom first-party domain (Cloudflare for SaaS), it auto-detects that hostname and uses it as api_host — you do not need to set api_host manually in that case.
White-label the global object
By default the SDK attaches to window.mythic. You can rename that global — for example to your agency's or client's brand — so tracking calls read as window.acme.capture(...). The chosen name must be a valid JavaScript identifier.
There are two ways to set it:
Set the client's global_name when you create or update it (see Onboard a client). The loader snippet returned by GET /api/v1/clients/{id}/loader then bakes the override in automatically — you install the snippet as-is and the global is renamed for you.
curl -X PATCH "https://mythic-analytics.gulp.workers.dev/api/v1/clients/acme-retail" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "global_name": "acme" }'
Set window.__mythic_global_name before the loader runs — the first statement in the snippet. The loader reads it and attaches to that name (falling back to mythic if it isn't a valid identifier).
<script>window.__mythic_global_name="acme";!function(){/* ...loader snippet... */}();
acme.init("pk_your_publishable_key");</script>
<script>
window.acme.capture("Signup started", { plan: "pro" });
</script>
The loader snippet from GET /api/v1/clients/{id}/loader puts that
assignment inside the snippet itself when the client has a global_name,
and stubs window.acme rather than window.mythic.
window.mythic stays available as an alias even when a custom name is set, so shared snippets keep working. Storage keys also pick up the custom name by default ({globalName}_{key}_) — see persistence_name.