@traffical/js-client is the framework-agnostic browser SDK. It fetches the config bundle, resolves parameters in the browser, tracks exposure events, and manages anonymous-user identity automatically.
If you’re using React or Svelte, prefer the React SDK or Svelte SDK — they wrap this client with framework-native APIs.
Installation
Setup
Use an publishable SDK key (
traffical_pk_...) in client code. It fetches the config bundle and sends events, and cannot modify configuration — safe to ship in a client bundle.Resolving parameters
getParams(context, defaults) and decide(context, defaults) take context first, defaults second, and both are synchronous. In the browser you can usually omit the unit key — the SDK fills it from the auto-generated stable ID (see below).
The legacy object-bag form —
getParams({ context, defaults }) / decide({ context, defaults }) — still works but is deprecated. Prefer the positional form.Anonymous users and identify
Browser-side experimentation often needs to resolve parameters before a user is logged in. To make that work without you having to think about it, the browser SDK auto-generates a stable UUID on first visit, stores it in localStorage (with a cookie fallback), and fills the project’s unit-key slot with that value whenever the caller doesn’t pass one.
So if the project’s unit key is userId, the SDK effectively passes context.userId = "<auto-generated-uuid>" on every pre-login resolution. Bucketing works, exposure events fire, the user gets a stable assignment for as long as their localStorage persists.
When the user logs in, call identify(realUserId):
userId. Every subsequent resolution uses the new value.
You can read the current stable ID with traffical.getStableId(). After identify(), this returns the value you passed in.
Tracking events
track(event, properties?, options?) — the event name first, an optional properties payload second, and an options bag (unitKey, decisionId, value, values, eventTimestamp) third. In the browser unitKey defaults to the current stable ID, so you rarely pass it:
Lifecycle
createTrafficalClient (async) awaits the first bundle fetch. When you can’t await at construction, use createTrafficalClientSync and await readiness before the first resolution:
close(). It stops the background refresh and awaits a final event flush before returning (on page unload it falls back to sendBeacon so the last batch still ships):
destroy() still exists but is deprecated — prefer close(), which awaits the final flush.Options
Deprecated option aliases. Earlier releases used
eventBatchSize, eventFlushIntervalMs, and a single requestTimeoutMs. These still work and forward to the canonical names above (batchSize, flushIntervalMs, and the three-way timeout split). requestTimeoutMs is honored as the legacy fallback for any of configTimeoutMs / eventsTimeoutMs / resolveTimeoutMs that you don’t set explicitly. Prefer the canonical names — the aliases will be removed in a future major.Bundle caching
The browser SDK caches the bundle in memory. The first page load fetches it; subsequent loads benefit from HTTP caching at the CDN edge (Cache-Control: public, max-age=60, must-revalidate with ETag). On warm loads, resolution is available immediately.
Plugins
The browser SDK has a small plugin system that powers some of Traffical’s other tools:Auto attributes
The auto-attributes plugin derives browser, page, UTM, and locale keys and adds them to every decision context. It is opt-in — nothing changes in the context you send until you register it. All keys live in the reserved$ namespace, so they never collide with your own, and they are registered as system attributes in every project, ready to target from the condition editor.
Traffical.autoAttributesPlugin() (Traffical.createAutoAttributesPlugin is an alias).
Rules:
- Caller wins. Context you pass to
decide()/getParams()overrides any derived key of the same name. - Nothing empty. A key that cannot be derived is omitted, never sent as
"". - Re-derived on every decision, so single-page-app navigation is covered without patching
history. - SSR-safe. Without a
windowthe context passes through untouched.
AUTO_ATTRIBUTE_KEYS (the full key list) and the AutoAttributeKey type are exported for building include / exclude lists. The mobile SDKs emit the same $ keys from their device-info providers — see iOS and React Native.
Framework SDKs
If you’re using React or Svelte, use the framework-specific SDKs instead:@traffical/react— provider anduseTrafficalhook@traffical/svelte— stores and context API
@traffical/js-client and expose the same plugin system.