> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abconvert.io/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript API reference

> Every global, method, event, and object on window.ABConvert.

This page lists every global, method, event, and object on `window.ABConvert`. For what the API is for and how to use it, read [JavaScript API](/api-reference/browser-api) first.

## Globals

| Global                  | Defined when                                                       | Use it for                                                                                                               |
| ----------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `window.ABConvertQueue` | Your code or ABConvert creates it; ABConvert keeps one you created | Running a callback when ABConvert is ready. Before ready, callbacks wait; after ready, `push` runs them at once.         |
| `window.ABConvert`      | The ABConvert app embed has run                                    | Every method below. Code that runs after the app embed can call it directly, but assignments are not known before ready. |

Do not define your own `window.ABConvert`: ABConvert replaces it when it runs. The ABConvert object reaches your `window.ABConvertQueue` callback as its argument.

## Methods

| Method                                     | Defined when  | Returns                         | Empty result when                                                                                                                                       |
| ------------------------------------------ | ------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onReady(callback)`                        | Always        | `void`                          | Never                                                                                                                                                   |
| `getAssignments()`                         | Always        | `Assignment[]`                  | `[]`: the visitor is in no test                                                                                                                         |
| `getAssignment(experimentId)`              | Always        | `Assignment \| null`            | `null`: the visitor is not in that test                                                                                                                 |
| `getPriceByVariantId(variantId, options?)` | Price test    | `Price \| null`                 | `null`: no test price applies to this visitor. [See the rules](/api-reference/browser-api#prices)                                                       |
| `getPriceByProductId(productId, options?)` | Price test    | `Price \| null`                 | `null`: the same cases as `getPriceByVariantId`, per product                                                                                            |
| `formatPrice(amount, currency?)`           | Always        | `string`                        | Never                                                                                                                                                   |
| `getShippingRates(options?)`               | Shipping test | `ShippingRate[] \| null`        | `null`: the visitor is in no shipping test<br />`[]`: the test group has no rates, or `zone` names a zone the test does not have                        |
| `getFreeShippingThreshold(options?)`       | Shipping test | `FreeShippingThreshold \| null` | `null`: the visitor is in no shipping test, or no single threshold exists. [See the rules](/api-reference/browser-api#read-the-free-shipping-threshold) |
| `getOffers()`                              | Offer test    | `Offer[]`                       | `[]`: the visitor is in no offer test, or their test group has no offer                                                                                 |
| `track(name, payload?)`                    | Always        | `void`                          | Never                                                                                                                                                   |
| `getVisitorId()`                           | Always        | `string`                        | Never                                                                                                                                                   |
| `getCountry()`                             | Always        | `string`                        | `''`: the country is not known yet                                                                                                                      |
| `forceTestGroup(experimentId, index)`      | Always        | `void`                          | Never                                                                                                                                                   |
| `clearForcedTestGroup(experimentId)`       | Always        | `void`                          | Never                                                                                                                                                   |

A method marked with a test type exists only while your store has a test of that type running or in preview.

### onReady

Runs `callback` when ABConvert is ready, or at once if it already is. The same as pushing onto `window.ABConvertQueue`; use it from code that already holds the object.

<ParamField path="callback" type="(ABConvert) => void" required>
  Receives the `ABConvert` object.
</ParamField>

### getAssignments

Returns one [`Assignment`](#assignment) per test the visitor is in. Tests that excluded the visitor are absent.

### getAssignment

Returns the visitor's [`Assignment`](#assignment) for one test, or `null`.

<ParamField path="experimentId" type="string" required>
  The test ID shown in the ABConvert admin, as a string: `'49603'`.
</ParamField>

### getPriceByVariantId

Returns the visitor's [`Price`](#price) for one product variant, or `null` when no test price applies. See the [null rules](/api-reference/browser-api#prices).

<ParamField path="variantId" type="string" required>
  The product variant ID as a numeric string: `'47522361606401'`.
</ParamField>

<ParamField path="options" type="PriceOptions">
  <Expandable title="fields">
    <ParamField path="country" type="string">
      ISO 3166-1 alpha-2 code. Reads that country's price. Defaults to the country the page rendered for.
    </ParamField>
  </Expandable>
</ParamField>

### getPriceByProductId

Returns one [`Price`](#price) for a product, or `null`, under the same rules as `getPriceByVariantId`.

<ParamField path="productId" type="string" required>
  The product ID as a numeric string: `'6654464491584'`.
</ParamField>

<ParamField path="options" type="PriceOptions">
  <Expandable title="fields">
    <ParamField path="country" type="string">
      As in `getPriceByVariantId`.
    </ParamField>

    <ParamField path="aggregate" type="'min' | 'max' | 'first'" default="'min'">
      Which product variant's price to return. `'min'` and `'max'` pick among the product variants the test prices for this visitor. `'first'` picks the product's first product variant, or the first one the test prices.
    </ParamField>
  </Expandable>
</ParamField>

### formatPrice

Returns `amount` formatted in `currency` for the visitor's locale, such as `'$62.70'`. For a currency code the browser does not know, returns the code and the amount with two decimals, as in `'NOPE 49.50'`.

<ParamField path="amount" type="number" required />

<ParamField path="currency" type="string">
  ISO 4217 code. Defaults to the page currency, then to `'USD'`.
</ParamField>

### getShippingRates

Returns the [`ShippingRate`](#shippingrate)s the visitor's test group offers, cheapest first within each zone and currency. Returns `null` when the visitor is in no shipping test, and `[]` when the test group has no rates.

<ParamField path="options" type="ShippingOptions">
  <Expandable title="fields">
    <ParamField path="zone" type="string">
      A shipping zone name, as in the Shopify admin. Returns that zone's rates only, and `[]` for a zone the test does not have. Defaults to every zone.
    </ParamField>
  </Expandable>
</ParamField>

### getFreeShippingThreshold

Returns the lowest order subtotal at which the visitor's test group gets a free rate in a zone, as a [`FreeShippingThreshold`](#freeshippingthreshold), or `null` when the visitor is in no shipping test or no single threshold exists. See the [null rules](/api-reference/browser-api#read-the-free-shipping-threshold).

<ParamField path="options" type="ShippingOptions">
  <Expandable title="fields">
    <ParamField path="zone" type="string">
      A shipping zone name. Required when the visitor's shipping tests cover more than one zone.
    </ParamField>
  </Expandable>
</ParamField>

### getOffers

Returns one [`Offer`](#offer) per offer test the visitor is in. A test group with no offer contributes none.

### track

Records a [custom JS event](/analytics/custom-events#custom-js-event) for this visitor. At most once per page load; an unknown slug, or a page outside the event's page scope, records nothing.

<ParamField path="name" type="string" required>
  The event's slug from the custom event library: `'product_builder_completed'`.
</ParamField>

<ParamField path="payload" type="{ value?: unknown }">
  `value` is stored with the event.
</ParamField>

### getVisitorId

Returns the ID ABConvert records this visitor's assignments under, creating it if needed. Use it to match your own logs with ABConvert data. When the browser blocks `localStorage`, every call returns a new ID, so read it once and reuse it. To segment other tools by test group, send `testGroup.index`, not the visitor ID.

### getCountry

Returns the visitor's country as an ISO 3166-1 alpha-2 code such as `'US'`, or `''` while it is still unknown. It is the country ABConvert detected, not the market the page rendered for, so it can differ from `Price.country`. Preview with a chosen country returns that country.

### forceTestGroup

Puts you in a test group from the next page load. For seeing a test group yourself; see [Force a test group](/api-reference/browser-api#force-a-test-group).

<ParamField path="experimentId" type="string" required>
  The test ID. Throws a `TypeError` when empty.
</ParamField>

<ParamField path="index" type="number" required>
  The test group's position, counting from 0. Throws unless it is an integer of 0 or more. A position past the last test group shows Control.
</ParamField>

### clearForcedTestGroup

Undoes `forceTestGroup` for one test, from the next page load.

<ParamField path="experimentId" type="string" required>
  The test ID. Throws a `TypeError` when empty.
</ParamField>

## Events

ABConvert fires two events on `window`. `abconvert:assignment-ready` fires before ABConvert changes the page; `abconvert:ready` fires after.

| Event                        | When                                                                                                                       | `event.detail`         |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `abconvert:ready`            | Once per page load, when ABConvert is ready. Fires even when the visitor is in no test.                                    | The `ABConvert` object |
| `abconvert:assignment-ready` | Once per assignment on every page load, before `abconvert:ready`. Fires for an assignment kept from an earlier visit, too. | The `Assignment`       |

Rules for `abconvert:ready`:

* **It fires once and does not replay.** Prefer `window.ABConvertQueue`, which runs your callback whether you push before or after the event.
* **It does not fire again on client-side navigation.** A theme that swaps page content without a full load gets one event, on the first load.

Rules for `abconvert:assignment-ready`:

* **It fires before your queue callback runs.** Add the listener at the top level of your script, not inside a `window.ABConvertQueue` callback, or it never runs. To read assignments after the fact, call `getAssignments()` instead.
* **It does not fire for a forced or preview assignment.** A visit forced with `forceTestGroup`, a link, or Preview appears in `getAssignments()` but sends no event.
* **It fires once per test.** A combined test's changes register as one assignment and send one event.

When you need one DOM event per assignment, for example as a tag manager trigger, use the events:

```js theme={null}
window.addEventListener('abconvert:ready', function (event) {
  const ABConvert = event.detail;
  console.log(ABConvert.getAssignments());
});

window.addEventListener('abconvert:assignment-ready', function (event) {
  const assignment = event.detail;
  console.log(assignment.experimentId, assignment.testGroup.index);
});
```

## Objects

### Assignment

<ResponseField name="experimentId" type="string">
  The test ID shown in the ABConvert admin, as a string.
</ResponseField>

<ResponseField name="experimentName" type="string" />

<ResponseField name="type" type="string">
  One of `price`, `shipping`, `theme`, `template`, `url_redirect`, `checkout`, `offer`, `visual_editor`, `combined`, `personalization`.
</ResponseField>

<ResponseField name="status" type="'active' | 'preview'">
  The [test lifecycle](/experiments/lifecycle#what-each-state-means) states a visitor can see.
</ResponseField>

<ResponseField name="testGroup" type="TestGroup">
  The visitor's [test group](#testgroup).
</ResponseField>

<ResponseField name="reason" type="string">
  How the visitor got the test group:

  | `reason`             | Set when                                                                                                            |
  | -------------------- | ------------------------------------------------------------------------------------------------------------------- |
  | `random_split`       | [Random group assignment](/targeting/overview#random-split) picked the test group                                   |
  | `force_assign_group` | A [targeting rule](/targeting/overview#targeting-rules) whose action is **Assign to test group** set the test group |
  | `preview_override`   | [Preview](/experiments/lifecycle#preview-before-you-launch) set the test group                                      |
  | `url_force_assign`   | `forceTestGroup` or a [link](/experiments/lifecycle#see-one-test-group-with-a-link) set the test group              |
</ResponseField>

### TestGroup

<ResponseField name="index" type="number">
  The test group's position in the test, counting from 0. Use it as the identifier.
</ResponseField>

<ResponseField name="name" type="string">
  A display label. Can change at any time.
</ResponseField>

<ResponseField name="control" type="boolean">
  `true` for Control. `false` for every test group of a personalization.
</ResponseField>

<ResponseField name="split" type="number">
  The test group's share of traffic, an integer from 0 to 100.
</ResponseField>

### Price

<ResponseField name="experimentId" type="string" />

<ResponseField name="testGroup" type="TestGroup" />

<ResponseField name="amount" type="number" />

<ResponseField name="compareAtAmount" type="number | null">
  `null` when the test group sets no compare-at price.
</ResponseField>

<ResponseField name="currency" type="string">
  ISO 4217. The currency this price is stated in.
</ResponseField>

<ResponseField name="country" type="string">
  ISO 3166-1 alpha-2. The country this price is for. Empty when unknown.
</ResponseField>

<ResponseField name="productId" type="string" />

<ResponseField name="variantId" type="string" />

### ShippingRate

<ResponseField name="experimentId" type="string" />

<ResponseField name="testGroup" type="TestGroup" />

<ResponseField name="zone" type="string">
  The shipping zone name, as in the Shopify admin.
</ResponseField>

<ResponseField name="name" type="string">
  The rate name shown at checkout.
</ResponseField>

<ResponseField name="amount" type="number">
  `0` for a free rate.
</ResponseField>

<ResponseField name="currency" type="string">
  The currency you set the rate in, which can differ from the page currency.
</ResponseField>

<ResponseField name="condition" type="object | null">
  `null` for a rate with no condition.

  <Expandable title="fields">
    <ResponseField name="type" type="'price' | 'weight'" />

    <ResponseField name="minimum" type="number | null" />

    <ResponseField name="maximum" type="number | null" />

    <ResponseField name="unit" type="string | null">
      The weight unit for a `weight` condition.
    </ResponseField>
  </Expandable>
</ResponseField>

### FreeShippingThreshold

<ResponseField name="experimentId" type="string" />

<ResponseField name="testGroup" type="TestGroup" />

<ResponseField name="zone" type="string" />

<ResponseField name="amount" type="number">
  `0` for a free rate with no condition.
</ResponseField>

<ResponseField name="currency" type="string">
  The currency you set the rate in, which can differ from the page currency.
</ResponseField>

### Offer

<ResponseField name="experimentId" type="string" />

<ResponseField name="testGroup" type="TestGroup" />

<ResponseField name="title" type="string" />

<ResponseField name="discounts" type="Discount[]">
  The offer's discounts. The `Discount` shapes are in the [TypeScript](#typescript) block below.
</ResponseField>

## TypeScript

Copy this into a `.d.ts` file for autocompletion and type checking. Methods marked `?` exist only while your store has that test type.

```ts theme={null}
interface ABConvertAPI {
  onReady(callback: (api: ABConvertAPI) => void): void;
  getAssignments(): Assignment[];
  getAssignment(experimentId: string): Assignment | null;
  getPriceByVariantId?(variantId: string, options?: PriceOptions): Price | null;
  getPriceByProductId?(productId: string, options?: PriceOptions): Price | null;
  formatPrice(amount: number, currency?: string): string;
  getShippingRates?(options?: ShippingOptions): ShippingRate[] | null;
  getFreeShippingThreshold?(options?: ShippingOptions): FreeShippingThreshold | null;
  getOffers?(): Offer[];
  track(name: string, payload?: { value?: unknown }): void;
  getVisitorId(): string;
  getCountry(): string;
  forceTestGroup(experimentId: string, index: number): void;
  clearForcedTestGroup(experimentId: string): void;
}

interface Window {
  ABConvert?: ABConvertAPI;
  ABConvertQueue?: Array<(api: ABConvertAPI) => void>;
}

interface Assignment {
  experimentId: string;
  experimentName: string;
  type: 'price' | 'shipping' | 'theme' | 'template' | 'url_redirect' | 'checkout' | 'offer' | 'visual_editor' | 'combined' | 'personalization';
  status: 'active' | 'preview';
  testGroup: TestGroup;
  reason: 'random_split' | 'force_assign_group' | 'preview_override' | 'url_force_assign';
}

interface TestGroup {
  index: number;
  name: string;
  control: boolean;
  split: number;
}

interface Price {
  experimentId: string;
  testGroup: TestGroup;
  amount: number;
  compareAtAmount: number | null;
  currency: string;
  country: string;
  productId: string;
  variantId: string;
}

interface PriceOptions {
  country?: string;
  aggregate?: 'min' | 'max' | 'first';
}

interface ShippingRate {
  experimentId: string;
  testGroup: TestGroup;
  zone: string;
  name: string;
  amount: number;
  currency: string;
  condition: { type: 'price' | 'weight'; minimum: number | null; maximum: number | null; unit: string | null } | null;
}

interface FreeShippingThreshold {
  experimentId: string;
  testGroup: TestGroup;
  zone: string;
  amount: number;
  currency: string;
}

interface ShippingOptions {
  zone?: string;
}

interface Offer {
  experimentId: string;
  testGroup: TestGroup;
  title: string;
  discounts: Discount[];
}

type Discount =
  | { type: 'product_discount';   value: DiscountValue; scope?: DiscountScope; condition?: DiscountCondition }
  | { type: 'order_discount';     value: DiscountValue; condition?: DiscountCondition }
  | { type: 'shipping_discount';  value: DiscountValue; scope?: ShippingDiscountScope; condition?: DiscountCondition }
  | { type: 'volume_discount';    tiers: VolumeTier[]; scope?: DiscountScope; condition?: DiscountCondition }
  | { type: 'threshold_discount'; tiers: ThresholdTier[]; condition?: DiscountCondition };

type DiscountValue =
  | { unit: 'percentage'; value: number; maxDiscountAmount?: Money }   // percent off, capped at maxDiscountAmount
  | { unit: 'fixed'; amount: Money };

type DiscountScope =                                            // omitted = all products
  | { type: 'all_products' }
  | { type: 'specific_products'; productIds: string[] }
  | { type: 'specific_collections'; collectionIds: string[] };

type ShippingDiscountScope =                                    // omitted = all rates
  | { type: 'all_rates' }
  | { type: 'specific_rates'; rateNames: string[] };

type DiscountCondition =
  | { type: 'order_price'; minimum: Money }
  | { type: 'quantity'; minimum: number };

type VolumeTier = { threshold: number; value: DiscountValue };      // threshold: item count
type ThresholdTier = { threshold: Money; value: DiscountValue };    // threshold: order subtotal
type Money = { amount: number; currency: string };
```
