Snippet SDK API

The A vs B snippet exposes two programming interfaces: the global window.avsb object (available anywhere on the page) and the options toolkit (available inside initVariation, initTrigger, and initProject). Use the global API for page-level concerns; use options for anything scoped to a specific variation or project setup run.

Global API: window.avsb

When the A vs B snippet loads on your page, it attaches a global object called window.avsb. Use it to work with the experiment engine directly. You can track conversions, read which variation a visitor is seeing, force a specific variation for testing, wait for dynamic elements to appear, and hook into the event stream for analytics integrations.

Full interface

Here is the complete TypeScript interface for window.avsb.

The loader tag is async, so when the API becomes fully live depends on the network, not on a DOM event: it can be before or after DOMContentLoaded. Do not guess. The install stub defines avsb.ready, avsb.on, avsb.consent.set and the four avsb.track.* methods from the first byte of the page, so wrap anything else in avsb.ready(...) and it runs at the right moment either way.

These types are on npm

Install them and skip the copy-paste:

Shell
npm install --save-dev @avsbhq/snippet-types
Shell1 line
JSON
{  "compilerOptions": {    "types": ["@avsbhq/snippet-types"]  }}
JSON5 lines
TypeScript
avsb.ready?.(() => {  const visitorId: string | null = avsb.getVisitorId()  avsb.track.event('signup_completed', { revenue: 49.99 })  if (visitorId) console.log(visitorId, 'on snippet', avsb.version)})
TypeScript5 lines

The declarations are global, so nothing needs importing, and they are generated from the snippet's own source: they cannot drift from what is running on your page. Every shape below has a name you can use as well (AvsbPurchaseOrder, AvsbIntegrationRecord, AvsbUtils, and the rest).

Five members are declared optional in those types: ready, on, consent, getExperimentDecisions, and getOriginalReferrer. Two runtime paths do not carry all five. Preview mode builds its own avsb object from scratch, and that object skips all five: it renders one experiment from a preview payload rather than running a live evaluation. An editor or metric-wizard launch skips even more: it never installs the normal runtime at all, so the page is left with only what the install stub defines, ready, on, consent, and the four track.* methods, and nothing else in this interface. getExperimentDecisions and getOriginalReferrer are also missing on any snippet build older than the one that added them. Guard every optional member with avsb.ready?.(...). Every normal page on a current snippet has all five, and in plain JavaScript avsb.ready(...) is equally fine. The typed examples on this page use the optional-call form.

Here is AvsbApi, the type of window.avsb, exactly as the package declares it:

TypeScript
interface AvsbApi {  /** Consent mode only: start the snippet once the visitor has agreed. No effect otherwise. */  init(): void | Promise<void>  /** Stop everything and forget the visitor: tracking off, timers and listeners cleared, variations reverted, visitor cookie expired. */  disable(): void  track: AvsbTrackFunction  /** The visitor's id, or null when there isn't one (before `init()` in consent mode, or for a visitor who denied analytics). */  getVisitorId(): string | null  /** Replace the visitor id to stitch a browser onto a logged-in account. Drops sticky assignments and re-evaluates, so the variation can change. Returns false for an unusable id. */  setVisitorId(visitorId: string): boolean  /** The visitor's Variation ID in that experiment, or null. Takes the numeric Experiment ID the dashboard shows. */  getVariation(experimentId: string | number): string | null  /** Force a variation, for QA, by the numeric dashboard ids. Kept on later page loads unless `{ persist: false }`; `{ track: false }` applies it without recording an exposure. */  forceVariation(experimentId: string | number, variationId: string | number, options?: { track?: boolean; persist?: boolean }): boolean  waitUntil: AvsbWaitUntilFn  utils: AvsbUtils  /** Subscribe to every experiment event. Returns an unsubscribe function. Absent in the preview bypass runtime. */  on?(event: 'event', callback: (record: AvsbIntegrationRecord) => void): () => void  /** Run a callback once experiments have been evaluated. Safe to call before the snippet loads. */  ready?(callback: () => void): void  /** @deprecated Use `ready`. Same machinery. */  onReady(callback: () => void): void  /** Visitor consent: `set` from your banner, `get` for the effective state. Absent in the preview bypass runtime. */  consent?: AvsbConsentApi  /** Experiments this visitor is active in on this page, as numeric dashboard ids in string form. */  getActiveExperiments(): Array<{ experimentId: string; variationId: string }>  /** One row per experiment on the page: what happened to this visit and why (held out, mismatched, pending, running). Rebuilt on every evaluation; empty before evaluation and after `disable()`. Optional: absent on snippet builds that predate it, so read it as `avsb.getExperimentDecisions?.()`. */  getExperimentDecisions?(): AvsbExperimentDecision[]  /** Read a server-side dataset. Never throws: unknown slugs resolve `{ found: false }`. */  dataset(slug: string): AvsbDatasetHandle  /** Headless recommendations. Inside variation code prefer `options.recs`, which attributes automatically. */  recs: AvsbRecsClient  /** Commerce events. Buffered until the commerce chunk loads. */  commerce: AvsbCommerceApi  /** Leave a shared preview link, and undo every persisted `forceVariation`: clears both and reloads. */  exitPreview(): void  /** After a split-URL redirect in this tab: the referrer of the page the visitor was redirected FROM. `''` means that visit was direct; `null` means no redirect happened. Same-origin only. Optional: absent on older snippet builds, so call it as `avsb.getOriginalReferrer?.()`. */  getOriginalReferrer?(): string | null  /** Re-run every experiment against the page as it is now. For app-driven navigation the History API never sees. */  refresh(): void  /** The snippet build running on this page, e.g. `1.1.0`. */  version: string}interface AvsbTrackFunction {  /** Fire a custom event by its metric event key. Numbers are coerced to strings, so a numeric key works when the metric's key is those digits. An unmatched key warns and lists the keys that do work. */  event(eventKey: string | number, properties?: AvsbTrackEventProperties): void  /** Record a visitor attribute you can slice results by. */  segment(segmentKey: string, segmentValue: string): void  /** Send an order immediately. Not batched. */  purchase(order: AvsbPurchaseOrder): void  /** Tell the snippet the current cart total, for commerce audience conditions. `totalMinor` wins when both are set. */  cart(cart: { total?: number; totalMinor?: number }): void}interface AvsbTrackEventProperties {  /** Monetary amount for this event. Feeds revenue metrics. Plain number, no currency symbol. */  revenue?: number  /** Continuous measurement (order value, load time, scroll depth) for percentile and value metrics. */  value?: number}interface Window {  avsb: AvsbApi & { q?: Array<[string, ...unknown[]]> }}declare const avsb: AvsbApi
TypeScript67 lines

The supporting shapes are declared in the same package: AvsbPurchaseOrder and AvsbPurchaseItem (see Tracking Revenue), AvsbIntegrationRecord (see Event bus), AvsbUtils, AvsbWaitUntilFn, AvsbGuardedThenable and AvsbWaitTarget (see Utilities and Wait Until), AvsbConsentApi and AvsbConsentState (see Consent Mode), AvsbDatasetHandle, AvsbRecsClient, and AvsbCommerceApi.

Use avsb.ready() for code that may run before the snippet loads

The install tag stubs avsb.ready before the snippet bundle loads, so you can safely call it at any point in your page. Pass a callback and it will run as soon as the snippet is ready, or immediately if it is already loaded. This replaces the older pattern of guarding with if (window.avsb), which silently dropped calls that ran too early.

JavaScript
// Always use avsb.ready: it works whether the snippet has loaded or not.avsb.ready?.(function () {  avsb.commerce.productView({ sku: 'SKU-123', priceMinor: 8900, currency: 'USD' });});
JavaScript4 lines

The stub is included in the two-tag install snippet from Project Settings → Snippet. onReady is a deprecated alias for ready and still works, but prefer ready in all new code.

Method reference

avsb.init

Plain text
avsb.init() => void | Promise<void>
Plain text1 line

Starts the snippet when Consent Mode is enabled. Triggers cookie creation, experiment evaluation, variation injection, and event tracking. Has no effect when Consent Mode is off (the snippet auto-initializes), when already initialized, or after disable() has been called. Any track calls queued before init() are replayed after initialization completes.

avsb.disable

Plain text
avsb.disable() => void
Plain text1 line

The opt-out. It stops all tracking, tears down every experiment trigger, and reverts the variations applied to the page. It also cancels the timers and listeners the snippet and your variation code created, and it expires the visitor cookie. After calling disable(), init() is a no-op and the visitor must reload the page to opt back in.

This is real on every project, not only the ones using Consent Mode. Use it when a visitor revokes consent or clicks your own "do not track me" control.

disable() forgets, consent.set() decides

avsb.disable() is the hard stop for the current page. avsb.consent.set({ analytics: false }) records a durable choice that also governs the visitor's next page load. A cookie banner should call consent.set; a one-off opt-out button can call either. See Consent Mode.

avsb.track.event

Plain text
avsb.track.event(eventKey: string | number, properties?: AvsbTrackEventProperties) => void
Plain text1 line

Records a conversion for a custom event metric. The eventKey is the event key configured on the metric in the dashboard, exactly as you typed it there. A number is coerced to text, so 12345 fires a metric whose key is 12345; nothing matches a metric by its short ID.

An optional revenue property attaches a monetary amount (unlocking the Revenue Impact calculation); an optional value property attaches a continuous measurement (e.g. order value or load time) used by percentile metrics. For conversion-rate metrics each visitor counts once, and subsequent calls do not change the rate, while count and percentile metrics built on the same event take every call into account.

If no metric uses the key you pass, nothing is recorded and the console says so, listing the keys that do work. See Tracking Events.

avsb.track.segment

Plain text
avsb.track.segment(segmentKey: string, segmentValue: string) => void
Plain text1 line

Assigns a custom attribute to the current visitor, so you can slice results by any visitor property: subscription plan, account tier, locale, and so on.

The call records whatever key you pass, whether or not the segment exists in your settings. What defining it under Settings → Segments adds is the ready-made filter on the results page: the segment's display name and its list of values come from that definition. So you can instrument first and define the segment afterwards. Keys must start with a letter or underscore and contain only letters, digits, underscores, dots, or hyphens; anything else is still recorded but cannot be filtered, and the snippet warns in the console. See Custom Segments.

avsb.track.cart

Plain text
avsb.track.cart(cart: { total?: number; totalMinor?: number }) => void
Plain text1 line

Tells the snippet the visitor's current cart total, which powers the Cart value condition in Commerce Conditions. Call it whenever the cart changes (add, remove, quantity update) and once on page load if your page already knows the total.

Pass exactly one of the two fields:

  • total: the cart total as a plain decimal number in the project currency, the same convention as avsb.track.purchase (49.99 means $49.99). The snippet converts it internally using the project currency's minor-unit rules.
  • totalMinor: the total already in minor units (cents, pence): 4999 means $49.99. Use this when your platform hands you minor units directly (Shopify's cart API does, for example). When both fields are present, totalMinor wins.
JavaScript
// After your cart API responds with the new total:avsb.track.cart({ total: 49.99 });
JavaScript2 lines

Behaviour worth knowing:

  • No network call. The cart total is stored in the browser only and read locally during audience evaluation. Nothing is sent anywhere, except the bucketed cart_band results segment recorded when an experiment uses commerce conditions.
  • Zero is a valid total. { total: 0 } records an empty cart, which "cart value less than X" conditions can match. A page that never calls track.cart leaves the cart unknown, and cart conditions evaluate to false.
  • Invalid values are ignored. Negative or non-numeric totals are dropped (with a console warning in verbose mode); a call with neither field does nothing. The call never throws.
  • Safe to call early. Calls made before the snippet initializes are queued and replayed at init, the same as track.event. In Consent Mode nothing touches browser storage until avsb.init() runs.
  • On Shopify stores with the A vs B app, the theme app embed calls this automatically, so you do not need to.

avsb.getVisitorId

Plain text
avsb.getVisitorId() => string | null
Plain text1 line

Returns the persistent visitor ID assigned to the current browser. This ID is stored in the _avsb_visitor cookie and stays constant across page loads and sessions on the same device. Useful when you need to correlate A vs B data with records in your own database or analytics system.

It returns null when there is no visitor id to give: before avsb.init() on a project using Consent Mode, and for a visitor who denied analytics (no cookie is written on that path at all). Check the result before you use it.

JavaScript
const visitorId = avsb.getVisitorId();if (visitorId) sendToYourBackend(visitorId);
JavaScript2 lines

To measure one metric across both the snippet and the feature-flag SDK (the setup behind cross-project metrics), pass this same id into the SDK so both surfaces share one identity. See Shared Visitor Identity for the wiring.

avsb.setVisitorId

Plain text
avsb.setVisitorId(visitorId: string) => boolean
Plain text1 line

Replaces the visitor id, so an anonymous browser and a logged-in account count as one visitor. Pass your own stable user id.

Because a different id is a different visitor, A vs B drops the sticky variation assignments belonging to the old id and re-evaluates every experiment under the new one. The visitor can therefore end up in a different variation, and the new id records its own exposures, which is what keeps their conversions attributed correctly.

JavaScript
avsb.ready?.(function () {  if (currentUser) avsb.setVisitorId(currentUser.id);});
JavaScript3 lines

Call it as early as you can, ideally before your page has rendered anything. Returns false (and warns in the console) for an id that cannot be stored or sent: allowed characters are letters, digits, . _ : @ | -, up to 128 of them. Passing the id already in use is a no-op that returns true, and it returns false after avsb.disable() rather than re-creating the cookie the opt-out removed.

For the whole cross-subdomain and cross-surface picture, see Shared Visitor Identity.

avsb.getVariation

Plain text
avsb.getVariation(experimentId: string | number) => string | null
Plain text1 line

Returns the Variation ID this visitor is assigned in that experiment, or null if they are not in it (they do not match the targeting rules, they are in a holdout, or they were never bucketed).

Pass the Experiment ID: the number shown in the Experiment details panel in the builder (click the info button). A number or its string form both work, so avsb.getVariation(42) and avsb.getVariation('42') are the same call. The internal UUID is not accepted, and passing one warns in the console and returns null. A visitor who has called avsb.disable() simply has no assignment to report.

The value you get back is the Variation ID from the same panel, as a string. It is the same id the event bus puts on every record, so a value read here lines up with the events forwarded to your analytics tool.

avsb.getActiveExperiments

Plain text
avsb.getActiveExperiments() => Array<{ experimentId: string; variationId: string }>
Plain text1 line

Returns every experiment the current visitor is active in on this page, as { experimentId, variationId } pairs. Both are the numeric dashboard ids in string form, the same vocabulary getVariation and the event bus use, so a value from here can be passed straight back into getVariation or forceVariation.

Useful for debugging multi-experiment pages, or for passing experiment context to an analytics system.

avsb.getExperimentDecisions

Plain text
avsb.getExperimentDecisions() => Array<{  experimentId: string  status: string  variationId?: string  variationName?: string}>
Plain text6 lines

Returns one row per experiment on the page, saying what happened to this visit and why. getActiveExperiments answers "what is running"; this answers "what about everything that is not". Use it when an experiment looks absent and you need to know whether the visitor was held out, missed the audience, or is simply waiting on a trigger.

variationId and variationName are present whenever a variation was assigned, including while a trigger is still pending.

status is one of:

StatusWhat it means
variantThe visitor is in the test and seeing this variation's changes.
controlThe visitor is in the test, in the control group, seeing the unchanged page on purpose.
trigger-pendingA variation is assigned and the experiment is waiting for its trigger to fire.
self-redirectThe visitor is in the test on the variation page; the redirect was skipped because its destination is this page.
not-targetedThe current URL does not match the experiment's targeting rules.
audience-mismatchThe visitor does not meet the experiment's audience conditions.
excludedAn exclusion group kept this visitor out.
traffic-holdoutTraffic allocation kept this visitor out.
cappedThe experiment's visitor cap is full.
scheduled-offThe current time is outside the experiment's schedule.
lateThe page had already been revealed before the experiment could apply, so it was skipped for this page load. Nothing changed and nobody was counted; it runs normally on the next load.
unsupportedThe snippet build served to this page does not include a feature the experiment needs, so it was skipped whole and nobody was counted. It runs again once the served build catches up, usually within minutes of publishing.
errorThe experiment's setup could not be evaluated.

The list is rebuilt on every evaluation, including single-page-app route changes, so it always describes the page the visitor is on right now.

Returns an empty array before the snippet has evaluated anything (for example under consent mode, before avsb.init() is called) and after avsb.disable(). Each call hands back a fresh copy, so changing the returned array cannot affect the snippet.

JavaScript
avsb.ready?.(function () {  var held = (avsb.getExperimentDecisions?.() ?? []).filter(function (d) {    return d.status === 'traffic-holdout'  })  console.log('Held out of', held.length, 'experiments')})
JavaScript6 lines

avsb.forceVariation

Plain text
avsb.forceVariation(experimentId: string | number, variationId: string | number, options?: { track?: boolean; persist?: boolean }) => boolean
Plain text1 line

Forces the current visitor into a specific variation, overriding normal bucketing. Both ids are the numeric Experiment ID and Variation ID from the Experiment details panel in the builder, as numbers or their string forms.

Returns true when the variation was applied, and false when an id is not in the live datafile. A false also prints a console warning naming the id it could not place, so a typo (or an internal UUID pasted by habit) says so instead of failing silently. The one silent false is after avsb.disable(): a visitor who opted out gets no new assignment, and that is not a mistake to warn about. Use it for QA: call it from the DevTools console to switch variation immediately. The forced assignment is stored in the visitor's cookie and persists across page loads, so you can click through the site without forcing again. Pass { persist: false } to force it on the current page only. avsb.exitPreview() undoes every persisted force (see Resetting forced variations).

Pass { track: false } to apply the variation without recording an exposure for this call. The default ({ track: true }) records one, exactly as normal bucketing would. Later page loads count a persisted force like any assignment, so mark your browser as internal traffic to keep QA out of your results.

Returns false after avsb.disable(): once a visitor has opted out, nothing writes a new assignment for them.

avsb.getOriginalReferrer

Plain text
avsb.getOriginalReferrer() => string | null
Plain text1 line

After a Split URL experiment redirect, the browser reports your own control page as the referrer, which your analytics tool reads as a self-referral and quietly miscredits the variant's traffic source. This method returns the referrer of the page the visitor was redirected from, captured just before the redirect, so your own analytics can undo that self-referral. Call it on the destination page, inside avsb.ready(...).

What it returns:

  • The original referrer string, when this tab went through a split-URL redirect.
  • '' (empty string), when it did and the visit before the redirect was direct.
  • null, when no split-URL redirect has happened in this tab (or storage is unavailable).

A second redirect later in the same tab overwrites the value with its own pre-redirect context, so the answer always describes the most recent redirect. The handoff is same-origin only: a destination page on a different domain cannot read it.

The method is optional in the types because snippet builds older than the one that added it do not have it, so call it in the optional form:

JavaScript
avsb.ready?.(function () {  var source = avsb.getOriginalReferrer?.()  if (source !== null && source !== undefined) {    // hand the true referrer to your own analytics  }})
JavaScript6 lines

avsb.refresh

Plain text
avsb.refresh() => void
Plain text1 line

Re-runs every experiment against the page as it is now: tears down the active variations, re-runs your Project JavaScript, and evaluates the full targeting and audience gauntlet again.

Client-side route changes already do this automatically. Call it yourself when your app changes what the page is without changing the URL: a multi-step form, a modal route, a locale switch, a virtualised list that swaps its whole contents. Safe to call as often as you like; it does nothing until the snippet has finished its first evaluation. See Single Page Apps.

avsb.version

Plain text
avsb.version: string
Plain text1 line

The snippet build running on this page, for example 1.1.0. Handy in a bug report, and the quickest way to confirm the browser is not serving a stale cached bundle.

avsb.buildVariant

Plain text
avsb.buildVariant?: string
Plain text1 line

Which of the four snippet files this page is running: full, visual, shop or core. Your site is served the smallest one that covers what your project uses, and publishing works that out for you, so this value can change by itself after a publish. See Your snippet build for what each one carries.

Optional, so read it with a fallback: it is absent on snippet builds that predate named files, and until the first install stamp lands. A build that does not name its file always carries everything, so treat an absent value as full.

JavaScript
const build = window.avsb?.buildVariant ?? 'full'if (build === 'core') {  // Point-and-click changes are not part of this build.}
JavaScript4 lines

avsb.waitUntil

Plain text
avsb.waitUntil(target: AvsbWaitTarget, opts?: AvsbWaitOptions) => AvsbGuardedThenable
Plain text1 line

Promise-based wait for a CSS selector, a window.x.y global path, a predicate function, or an array of these. Chains with .then(); no .catch() required, because a failed or timed-out wait is logged gracefully instead of raising an unhandled-rejection error. Call .stop() on the returned AvsbGuardedThenable to cancel early. Default timeout is 10000 ms. Note: this is the global form, and it is NOT automatically cleaned up when a variation is removed. Inside trigger and variation code, prefer options.waitUntil, which is auto-cleaned on teardown. See the Wait Until reference page for the full parameter table and examples.

avsb.utils

Plain text
avsb.utils: AvsbUtils
Plain text1 line

A toolkit of helpers for variation and trigger code: wait utilities (waitUntil, poll, waitForElement, onMutation), timing helpers (once, throttle, debounce, raf, idle, domReady, retry), DOM manipulation ($, $$, createElement, insertAfter, insertBefore, wrap, remove, setText, setHtml), event utilities (on with delegation, onUrlChange), data access (cookie, query, storage.local, storage.session, state), and a scoped logger (log). Also accessible as options.utils inside trigger and variation code, where every observer and listener is auto-cleaned on variation removal. See the Utilities reference page for descriptions and examples of every helper.

avsb.recs

Plain text
avsb.recs.get(req: AvsbRecsRequest) => Promise<AvsbRecsResult>avsb.recs.trackClick(productId: string, opts?: { position?: number }) => voidavsb.recs.trackView(sku: string, meta?: { category?: string }) => void
Plain text3 lines

The headless recommendations client. get({ recipe, context, maxItems }) resolves a recipe's items as plain product data for your page to render. It never throws, and a miss resolves { items: [], served: false }. Inside experiment variation code use the pre-bound options.recs instead, so impressions and clicks attribute to the running variation automatically. trackClick records a rec:click (or stamp rendered cards with data-avsb-rec for automatic click tracking). trackView(sku, meta?) records a product view. The snippet keeps the visitor's last 20 viewed SKUs in localStorage, IDs only, with no personal data. This feeds the recently-viewed seed context, and it feeds the viewed-product history behind the Products viewed condition in Commerce Conditions. Pass meta.category to enable category-based matching there. See the Recommendations API reference page for request/response shapes, examples, and the rec:impression / rec:click event attribute vocabulary.

avsb.on

Plain text
avsb.on('event', callback: (record: AvsbIntegrationRecord) => void) => () => void
Plain text1 line

Subscribe to every experiment event: a visitor being shown a variation, a goal firing, a purchase, or a recommendation being seen or clicked. Returns a function that removes your subscription. You can subscribe as many times as you like, and each subscriber receives every event.

Use this to pipe experiment data into a tool the Integrations tab does not cover, with no server side work. Subscribe from Project JS, or from the pre-load stub, so you catch the first experiment view. See the Event bus reference for the full record and the setup order.

onEvent has been removed

window.avsb.onEvent no longer exists. It held a single callback, so a second integration silently replaced the first. Replace window.avsb.onEvent = fn with avsb.on('event', fn); the data your function receives is the same, with more fields on it.

The options toolkit: inside user code

Every user-written code surface (initVariation, initTrigger, initProject) receives an options object as its first argument. This toolkit is distinct from the global window.avsb API: it is scoped to the current variation or project run, and the self-cleaning helpers within it are automatically torn down when that run ends.

TypeScript
// One shape serves all three surfaces. The experiment fields are present in// variation and trigger code; `projectId` is present in project code. Published// as `AvsbCodeOptions` in @avsbhq/snippet-types/variation-code, with the aliases// AvsbVariationOptions, AvsbTriggerOptions and AvsbProjectOptions.//// initVariation runs only after activation, so apply your changes directly in the// function body. onActivation IS provided on every surface, but for a variation it// fires the moment your function returns, and a callback registered later runs// immediately. Use onRemove for teardown.interface AvsbCodeOptions {  /** Present in variation and trigger code. */  experimentId?: string  experimentName?: string  variationId?: string  variationName?: string  variationType?: 'control' | 'variant'  /** Present in project code only. */  projectId?: string  /** Runs when the variation is activated. In variation code it fires as soon as your function returns. */  onActivation(cb: () => void): void  /** Runs when the variation is removed (client-side navigation, teardown, forced switch). */  onRemove(cb: () => void): void  track: AvsbTrackFunction  /** Impressions and clicks attribute to this variation automatically. */  recs: AvsbRecsClient  getVisitorId(): string | null  /** These three speak the numeric dashboard ids, NOT the internal ids in the fields above. */  getVariation(experimentId: string | number): string | null  getActiveExperiments(): Array<{ experimentId: string; variationId: string }>  forceVariation(experimentId: string | number, variationId: string | number, options?: { track?: boolean; persist?: boolean }): boolean  /** Cancelled automatically on teardown, unlike `avsb.waitUntil`. */  waitUntil: AvsbWaitUntilFn  utils: AvsbUtils  /** Same numeric handle as the browser's own. Cancelled for you on teardown. */  setTimeout(handler: () => void, ms?: number): number  setInterval(handler: () => void, ms?: number): number  addEventListener(target: EventTarget, type: string, handler: EventListenerOrEventListenerObject, opts?: AddEventListenerOptions | boolean): void}declare function initVariation(options: AvsbVariationOptions): voiddeclare function initTrigger(options: AvsbTriggerOptions, activate: () => void, deactivate: () => void): voiddeclare function initProject(options: AvsbProjectOptions): void
TypeScript42 lines

The metadata fields are optional on the type because one shape covers three surfaces. In variation and trigger code the experiment fields are always set; in project code projectId is. A typed example:

TypeScript
function initVariation(options: AvsbVariationOptions): void {  options.waitUntil<HTMLElement>('.hero h1').then((heading) => {    options.utils.setText(heading, 'A clearer headline')    options.track.event('hero_seen')  })  options.onRemove(() => {    // Timers, listeners and waits registered through `options` are already    // cancelled for you. Undo anything else here.  })}
TypeScript11 lines
Prefer options helpers over global avsb inside user code

Inside initVariation, initTrigger, and initProject, always use options.waitUntil, options.setTimeout, options.setInterval, and options.addEventListener rather than their global equivalents. The options versions are automatically cancelled when the variation or project run is torn down (for example, on SPA navigation), preventing memory leaks and stale callbacks.

Deep dives

Each method has a dedicated page with parameter tables, detailed explanations, and code examples covering common scenarios.

Was this helpful?