> For the complete documentation index, see [llms.txt](https://help.dollarlabs.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.dollarlabs.io/dollarback-store-credit/developer-tools/storefront-window-api.md).

# Storefront window API

For theme developers: DollarBack exposes a JavaScript API on `window.dollarlabs` so custom themes can read cashback data, read the cashback total for the whole cart, compute cashback for any product, open the rewards widget from their own controls, re-initialize widgets after AJAX navigation, and react to cart changes. This is the reference for that API.

<figure><img src="https://2844543096-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcVBfwy7Yj4tU8TsxkHEr%2Fuploads%2Fgit-blob-94079291b625abc75824f4e9f0aeae7cb2c910a3%2Fdb-storefront-api-page-annotated.png?alt=media" alt="The Storefront API page with a &#x22;No API key&#x22; note, the openWidget function, the open-widget and ready events, and a Quick start code block."><figcaption><p>The Storefront API page in the app lists the same functions, events and objects, each with a Copy button.</p></figcaption></figure>

## Prerequisite: the window-variable embed

The **cashback-window-variable** app embed must be enabled in your theme. It injects the initial data (`common`, `data`, `globals`, `widgetMessages`) before the deferred JS bundle loads. Without it, `window.dollarlabs` is undefined.

<figure><img src="https://2844543096-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcVBfwy7Yj4tU8TsxkHEr%2Fuploads%2Fgit-blob-8e05d2c9753827b9c1f496c645032f282a55ccab%2Fdb-theme-app-embeds-dollarback-annotated.png?alt=media" alt="The App embeds panel of the Shopify theme editor filtered to &#x22;Cashback&#x22;, showing the Cashback Widget and Cashback Window Variable embeds switched on." width="560"><figcaption><p>Both DollarBack app embeds live in the theme editor's App embeds panel.</p></figcaption></figure>

{% hint style="warning" %}
If `window.dollarlabs` is `undefined` in the console, check this embed first. It is by far the most common cause. Before debugging anything else, open the theme editor's app embeds and confirm **cashback-window-variable** is on. See [A widget isn't showing on my store](/dollarback-store-credit/troubleshooting-and-faq/widget-isnt-showing.md) for the embed checklist.
{% endhint %}

## Wait for readiness

The bundle loads deferred. Read the namespace only after the `dollarback:ready` event fires on `window`:

```js
window.addEventListener("dollarback:ready", () => {
  // window.dollarlabs is fully populated here
});
```

## The namespace map

| Path                                          | Contents                                                                                                                                                                                                                                    |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `window.dollarlabs.common`                    | Shop and customer context, available on every page: `customerId`, `isCustomerLoggedIn`, `customerFirstName`, `customerTags`, `customerAcceptsMarketing`, `customerReferralCode`, `customerBalance`, `currencyFormat`, `routes`.             |
| `window.dollarlabs.dollarback.data`           | Cashback program state: `cashbackEnabled`, the enabled `configurations`, `referralSettings`, tiers (`tiersEnabled`, `customerTierName`, `tierMultiplier`), and `redemptionRules` as configured in the app.                                  |
| `window.dollarlabs.dollarback.globals`        | The inputs the cashback engine runs on: every configuration (enabled or not), `shopCurrency`, `currencyFormat`, `presentCurrencyRate`, `roundUpCashback`, `maximumOrderCashback`, plus the widget display settings.                         |
| `window.dollarlabs.dollarback.widgetMessages` | The widget message templates.                                                                                                                                                                                                               |
| `window.dollarlabs.dollarback.pdpResult`      | Latest cashback calculation for the product page being viewed: `config`, `cashbackAmount`, `formattedCashbackAmount`, `currency`. Set on product pages after the bundle runs.                                                               |
| `window.dollarlabs.dollarback.cartResult`     | Latest cashback calculation for the whole cart: the total, a per-line breakdown, and order-goal progress. Set on every page once the cart has been read. See [Read the cashback total for the cart](#read-the-cashback-total-for-the-cart). |
| `window.dollarlabs.dollarback.calculate`      | The per-product calculator. See [calculate()](#calculate-for-cashback-on-any-product).                                                                                                                                                      |

These objects are read-only display snapshots. Read them, but don't mutate them and don't treat them as an authoritative balance ledger; the app recalculates them itself.

`data` and `globals` share some key names but not their values: `globals.configurations` holds every configuration, while `data.configurations` holds only the enabled ones. Read each from where it lives rather than merging the two.

`customerBalance` is `null` when the customer is not logged in or has no credit, so guard before reading it:

```js
const common = window.dollarlabs.common;
if (common.isCustomerLoggedIn && common.customerBalance) {
  console.log("Store credit:", common.customerBalance.formatted);
}
```

## Read the cashback total for the cart

`window.dollarlabs.dollarback.cartResult` holds what the whole cart earns right now. DollarBack reads `/cart.js` on every page, works out the best offer for each line, adds the lines up, and then applies your maximum-per-order cap and rounding. The result is the same total the stock cart message shows, so a custom cart drawer, a mini-cart, or a header badge can show it without the cart block on the page.

| Field                                         | What it holds                                                                                                                                                                                                                                                                                                                              |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cashbackAmount`                              | The cart's cashback total in **minor units** (cents), already converted to the customer's currency: `750` means 7.50. It is missing, not `0`, when nothing in the cart earns, so read it as `cashbackAmount ?? 0`.                                                                                                                         |
| `formattedCashbackAmount`                     | The same total formatted with your store's money format, such as `"$7.50"`. It is the number `0` when nothing earns. Use it for display.                                                                                                                                                                                                   |
| `currency`                                    | Your store's currency code.                                                                                                                                                                                                                                                                                                                |
| `configs`                                     | The per-line breakdown: one `{ item, config, cashbackAmount }` entry for each cart line that earns, where `item` is the `/cart.js` line and `cashbackAmount` is in minor units.                                                                                                                                                            |
| `bestConfig`                                  | The cashback offer behind the total.                                                                                                                                                                                                                                                                                                       |
| `remainingAmount`, `nextAmount`, `goalConfig` | Order-goal progress, set when the cart hasn't reached an order goal's next tier yet: how much more to spend, what that tier pays (an amount, or a percentage for percentage goals), and the order goal it belongs to. Both amounts are formatted strings.                                                                                  |
| `messageType`                                 | `"earned_and_more"` (earning now, and there's a higher goal tier to reach), `"progress"` (nothing earned yet, but there's a goal tier to reach), `"earned"` (an order goal is fully reached), or `"max_ceiling_applied"` (the maximum-per-order cap kicked in). It is missing for a plain percentage or fixed offer with no goal to reach. |
| `discountRewards`                             | Discount-code rewards the cart qualifies for, if you [reward discount codes instead of store credit](/dollarback-store-credit/earning-cashback-programs/reward-discount-codes-instead-of-store-credit.md). These don't count toward `cashbackAmount`.                                                                                      |

The cart is read after `dollarback:ready`, so `cartResult` may not be set yet when that event fires. Read it if it is already there, then listen for `dollarbackCartUpdated`. That event fires with the new result each time the total is recalculated: on page load, and again whenever the cart changes.

```js
function renderCartCashback(result) {
  const el = document.querySelector("#my-cart-cashback");
  if (!el) return;
  el.textContent = (result.cashbackAmount ?? 0) > 0
    ? `You'll earn ${result.formattedCashbackAmount} in store credit`
    : "";
}

const existing = window.dollarlabs?.dollarback?.cartResult;
if (existing) renderCartCashback(existing);

window.addEventListener("dollarbackCartUpdated", (e) => {
  renderCartCashback(e.detail);
});
```

To show cashback per line in a drawer, match `configs` entries against the drawer's lines by `item.key`:

```js
const perLine = new Map(
  (window.dollarlabs.dollarback.cartResult?.configs || [])
    .map(({ item, cashbackAmount }) => [item.key, cashbackAmount])
);
```

The total is an estimate from the cart as it stands. The cashback actually issued is calculated on the order, after checkout discounts, so it can come out lower. See [How cashback is calculated](/dollarback-store-credit/earning-cashback-programs/how-cashback-is-calculated.md).

## calculate() for cashback on any product

```js
window.dollarlabs.dollarback.calculate(
  productId,             // required: numeric product ID
  variantPrice,          // required: price in minor units (cents)
  variantId,             // optional: numeric variant ID
  productCollectionsIds, // optional: the product's collection GIDs
  discountCodes          // optional
);
```

This runs the same engine as the product-page message for one variant, so a custom theme can render its own cashback line anywhere, such as on collection grids, quick views, or bundle builders. It considers purchase offers only, and applies the customer's eligibility, tier multiplier, maximum-per-order cap and rounding.

Pass the price in minor units, the way Shopify's `variant.price` Liquid object and `/products/<handle>.js` give it: `5800` for 58.00. Pass collections as GIDs (`"gid://shopify/Collection/289123456789"`), not bare numbers. Offers limited to certain collections only match if you do.

It returns one of three things:

* `null`: no offer applies to this product or customer.
* `{ config, cashbackAmount, formattedCashbackAmount, currency, currencyFormat }` for a percentage or fixed offer. `cashbackAmount` is in minor units.
* `{ config, cashbackType: "orderGoal", requiresCartCalculation: true }` when the best offer is an order goal. An order goal's cashback depends on the whole cart, so there's no per-product amount to return. Read `cartResult` instead.

```js
window.addEventListener("dollarback:ready", () => {
  const result = window.dollarlabs.dollarback.calculate(
    8123456789012,                             // product ID
    5800,                                      // variant price: a $58.00 serum
    45123456789012,                            // variant ID
    ["gid://shopify/Collection/289123456789"]  // collection GIDs
  );
  if (result && !result.requiresCartCalculation) {
    document.querySelector("#my-cashback-line").textContent =
      `Earn ${result.formattedCashbackAmount} cashback on this purchase`;
  }
});
```

Compare your custom rendering against the stock PDP block's message to confirm the numbers match.

## openWidget() to open the panel

```js
window.dollarlabs.dollarback.openWidget(options?)
```

Opens the floating widget's panel from your own JavaScript, so a header link, an icon, or any custom button can act as the entry point. It requires the **Cashback Widget** app embed to be enabled; the call opens the panel that embed renders.

`options` is optional:

| Option     | Type                                    | Effect                                                                                       |
| ---------- | --------------------------------------- | -------------------------------------------------------------------------------------------- |
| `tab`      | `"home"`, `"offers"`, `"referral"`      | The navigation tab to open on.                                                               |
| `view`     | `"redeem"`, `"history"`, `"membership"` | Opens the redeem-rewards, reward-history or membership screen directly.                      |
| `configId` | `string`                                | A cashback offer id. Opens the Offers tab, scrolls to that offer, and briefly highlights it. |

```js
window.dollarlabs.dollarback.openWidget()                    // home screen
window.dollarlabs.dollarback.openWidget({ tab: 'offers' })   // ways-to-earn offers
window.dollarlabs.dollarback.openWidget({ tab: 'referral' }) // refer-a-friend
window.dollarlabs.dollarback.openWidget({ view: 'redeem' })  // redeem rewards
window.dollarlabs.dollarback.openWidget({ view: 'history' }) // reward history
window.dollarlabs.dollarback.openWidget({ view: 'membership' }) // membership plans
```

From markup:

```html
<button onclick="window.dollarlabs.dollarback.openWidget({ tab: 'offers' })">
  View rewards
</button>
```

There is no matching `closeWidget()`. Customers close the panel with the launcher button, by clicking outside it, or by pressing Escape.

For the full recipe that hides the floating launcher and drives the panel from a navigation menu item instead, see [Open the widget from a menu link](/dollarback-store-credit/widgets-and-storefront/open-the-widget-from-a-menu-link.md).

## Init actions to re-mount after AJAX navigation

Themes that swap DOM without full page loads (AJAX product loads, quick-view modals, cart drawers) can re-initialize surfaces manually:

| Action                         | Use                                                                                                                                                                                       |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `initPDP(config)`              | Re-initialize the product-page context. Config fields: `productId`, `productCollectionIds`, `variants` (array of `{ id, price }`), `giftCard`, `initialVariantId`, `initialVariantPrice`. |
| `initCart()`                   | Re-initialize the cart context.                                                                                                                                                           |
| `initCartDrawerInjector()`     | Re-attach the cart-drawer message injection.                                                                                                                                              |
| `initPDPReactRender()`         | Re-mount the PDP message component.                                                                                                                                                       |
| `initCartReactRender()`        | Re-mount the cart message component.                                                                                                                                                      |
| `initWidgetReactRender()`      | Re-mount the floating widget.                                                                                                                                                             |
| `initLoyaltyPageReactRender()` | Re-mount the loyalty page.                                                                                                                                                                |

All live under `window.dollarlabs.dollarback`.

## Events

| Event                      | Fires                                                                                                   | Detail                                                                                                   |
| -------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `dollarback:ready`         | On `window`, when the bundle has loaded.                                                                | (none)                                                                                                   |
| `cart_changed`             | On `window`, whenever the cart watcher detects additions, removals or quantity changes.                 | `{ detail: newCart }` (the new cart, as `/cart.js` returns it).                                          |
| `dollarbackCartUpdated`    | On `window`, each time the cart's cashback is recalculated.                                             | The new `cartResult`. See [Read the cashback total for the cart](#read-the-cashback-total-for-the-cart). |
| `dollarbackProductUpdated` | On `window`, each time the product page's cashback is recalculated (variant, quantity or cart changes). | The new `pdpResult`.                                                                                     |
| `dollarback:open-widget`   | You dispatch it on `window` to open the panel.                                                          | The same options object `openWidget()` takes.                                                            |

Dispatching the event is equivalent to calling `openWidget()`, and is useful when you'd rather not touch the namespace at all:

```js
window.dispatchEvent(
  new CustomEvent('dollarback:open-widget', { detail: { view: 'redeem' } })
);
```

DollarBack's own messages recalculate off `cart_changed`; your theme can hook it too:

```js
window.addEventListener("cart_changed", (e) => {
  console.log("New cart:", e.detail);
});
```

## Legacy globals (deprecated)

Older themes may use the globals below. They still work, and each one points at the same object or function as its replacement, so the values always agree. They are deprecated, though: write new code against `window.dollarlabs` only, and move old code over when you next touch it.

| Deprecated global                                                                                                           | Use instead                                                |
| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `window._dollarlabs.common`                                                                                                 | `window.dollarlabs.common`                                 |
| `window._dollarlabs.dollarback`                                                                                             | `window.dollarlabs.dollarback.data`                        |
| `window._dollarlabs.WidgetMessageTemplate`                                                                                  | `window.dollarlabs.dollarback.widgetMessages`              |
| `window.dollarbackGlobals`                                                                                                  | `window.dollarlabs.dollarback.globals`                     |
| `window.DollarbackCalculate`                                                                                                | `window.dollarlabs.dollarback.calculate`                   |
| `window.DollarlabsProduct`                                                                                                  | `window.dollarlabs.dollarback.pdpResult`                   |
| `window.DollarbackCart`                                                                                                     | `window.dollarlabs.dollarback.cartResult` (the cart total) |
| `window._dollarlabs_balance`                                                                                                | `window.dollarlabs.common.customerBalance.formatted`       |
| `window.initPDP`, `window.initCart` and the other bare `init*` functions, `window.CartWatcher`, `window.CashbackCalculator` | The same names under `window.dollarlabs.dollarback`        |

A theme that reads the cart total from `window.DollarbackCart.cashbackAmount` keeps working. The equivalent now is `window.dollarlabs.dollarback.cartResult.cashbackAmount`, read as shown in [Read the cashback total for the cart](#read-the-cashback-total-for-the-cart).

## The short-link bridge

Clicks on anchors pointing at `link.dollarlabs.io` (the trackable short links used by social-follow rewards) automatically get the logged-in customer's ID appended as `?c=`. That's how social-reward clicks are attributed. You don't need to add anything, but don't strip the parameter.

## Common issues

* `window.dollarlabs` is `undefined`: the cashback-window-variable embed is off (see the prerequisite above), or you read it before `dollarback:ready`.
* `openWidget()` does nothing: the **Cashback Widget** app embed is off, so there is no panel to open, or the call ran before `dollarback:ready` fired.
* `calculate()` returns `null`: no config matches that product/variant, or the customer is excluded; see [How cashback is calculated](/dollarback-store-credit/earning-cashback-programs/how-cashback-is-calculated.md). For offers limited to certain collections, check that you passed collection GIDs, not bare IDs.
* Amounts are 100 times too big, or too small: `cashbackAmount` and `calculate()`'s `variantPrice` are in minor units (cents). For display, use `formattedCashbackAmount`.
* `cartResult` is `undefined`: the cart hasn't been read yet. Listen for `dollarbackCartUpdated` rather than reading it once on `dollarback:ready`.
* Messages vanish after AJAX navigation: call the relevant init action after your theme swaps the DOM.
* A widget won't render at all: see [A widget isn't showing on my store](/dollarback-store-credit/troubleshooting-and-faq/widget-isnt-showing.md).

## Related articles

* [Merchant API: keys & endpoints](/dollarback-store-credit/developer-tools/merchant-api-keys-and-endpoints.md)
* [Open the widget from a menu link](/dollarback-store-credit/widgets-and-storefront/open-the-widget-from-a-menu-link.md)
* [Widget map: what shows where](/dollarback-store-credit/widgets-and-storefront/widget-map-what-shows-where.md)
* [Product page & cart cashback messages](/dollarback-store-credit/widgets-and-storefront/product-page-and-cart-cashback-messages.md)
* [Cart drawer integrations](/dollarback-store-credit/integrations/cart-drawer-integrations.md)
