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

# Overview

> How the Aftersell Cart SDK works: the global entry point, the four parts of the API, when it loads, and how to run code against it safely.

The **Cart SDK** is a JavaScript API for the Aftersell Cart on your storefront. It lets you change how the cart behaves, react to what shoppers do, and read or change the cart's contents from code.

You run SDK code through [Custom scripts](/aftersell/cart/custom-scripts), or through a [Custom code block](/aftersell/cart/custom-code-blocks)'s React mode for a block that renders its own UI.

<Note>
  Plenty of what merchants ask the SDK for is already a setting. Before writing a script, check whether a [cart block](/aftersell/cart/blocks-overview), [conditions by market/country/currency](/aftersell/cart/blocks-overview#show-or-hide-by-market-country-or-currency), or a [cart setting](/aftersell/cart/cart-settings) already does it. Those keep working through cart redesigns, and your script may not.
</Note>

## The global entry point

Everything hangs off one global:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart
```

<Note>
  **Every snippet in these docs writes `window.aftersell.cart` out in full**, so any one of them works on its own when you paste it. Aliasing it once (`const cart = window.aftersell.cart;`) and using `cart` from then on is perfectly valid too, and safe even before the cart loads. Just remember to include that line if you shorten a snippet, since a bare `cart` on its own throws `cart is not defined`.
</Note>

Four parts do the work:

<Columns cols={2}>
  <Card title="Configure" icon="sliders" href="/aftersell/cart/sdk-configure">
    Set how the cart behaves: when the drawer opens, how money is formatted, whether Aftersell intercepts add-to-cart.
  </Card>

  <Card title="Events" icon="tower-broadcast" href="/aftersell/cart/sdk-events">
    React to what happens: the cart loaded, an item was added, the drawer opened, checkout was clicked.
  </Card>

  <Card title="Actions" icon="wand-magic-sparkles" href="/aftersell/cart/sdk-actions">
    Read and change the cart: open it, add an item, update a quantity, read the current state.
  </Card>

  <Card title="Hooks" icon="plug" href="/aftersell/cart/sdk-hooks">
    Change how the cart itself works: hide or relabel lines, reorder them, attach extra data, control add-to-cart.
  </Card>
</Columns>

<Note>
  If a script of yours stopped firing on add-to-cart, start with [Add-to-cart interception](/aftersell/cart/add-to-cart-interception). It explains why Aftersell takes over the add, and every way to opt a form out.
</Note>

Plus three smaller members:

| Member       | What it's for                                                    |
| ------------ | ---------------------------------------------------------------- |
| `ready()`    | A Promise that resolves once the cart has first loaded.          |
| `context`    | Server-rendered buyer context, readable synchronously.           |
| `shadowRoot` | The cart's shadow root, for querying elements inside the drawer. |

## Events, actions, or hooks?

The three are easy to mix up, and picking the wrong one is the most common reason a script doesn't do what its author expected:

| You want to…                           | Use        | Example                                        |
| -------------------------------------- | ---------- | ---------------------------------------------- |
| Run code *when something happens*      | **Event**  | Send an analytics event when an item is added. |
| *Change what's in* the cart            | **Action** | Add a free gift once the total passes \$50.    |
| Change *how the cart works or renders* | **Hook**   | Hide free gift lines from the drawer.          |

The distinction that matters most: an **action changes the shopper's actual cart** (and their total), while a **hook only changes what renders**. Hiding a line with a hook leaves it in the cart and in the total; removing it with an action takes it out for real.

## How and when it loads

The cart loads in two stages, and the SDK is built so you don't have to think about ordering:

1. A small **stub** creates `window.aftersell.cart` immediately, so it's always there.
2. The full SDK loads shortly after and takes over, upgrading the stub in place, so a reference you captured earlier keeps working.

That gives you two categories of call:

<Columns cols={2}>
  <Card title="Set-up calls: safe immediately" icon="circle-check">
    `configure(...)`, `events.on(...)`, and every `hooks.register*` call. Buffered before boot and replayed in order once the SDK loads. Put them at the top of your script.
  </Card>

  <Card title="Actions: wait for ready()" icon="clock">
    Everything under `actions.*`. Run them inside `ready()` or an event handler. Called too early they warn in the console and do nothing, safely: the async ones still resolve, so a `.then()` chain won't break.
  </Card>
</Columns>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Set-up: fine at the top level, before the cart has loaded.
window.aftersell.cart.configure({ open_on_add_to_cart: 'always' });

window.aftersell.cart.events.on('item_added', (payload) => {
  console.log('Added', payload.item.title);
});

// Actions: wait until the cart is ready.
window.aftersell.cart.ready().then(() => {
  const state = window.aftersell.cart.actions.getCart();
  console.log(state.itemCount, 'items');
});
```

### ready()

`ready()` returns a Promise that resolves once the first cart load **settles**. It resolves on failure as well as success, so a shopper on a flaky connection never leaves your script hanging. Check `getCart()` for `null` rather than assuming a cart arrived.

Calling `ready()` after the cart has already loaded resolves immediately, so it's safe to use as a general "the cart exists now" gate anywhere in your code.

<Tip>
  You don't need `ready()` inside an event handler. By the time `cart_loaded`, `cart_updated`, or `item_added` fires, the cart is loaded and actions are safe to call.
</Tip>

## context

`window.aftersell.cart.context` holds buyer data rendered by the server, readable synchronously, with no `ready()` needed. Use it for market or country branching that has to happen before the cart loads.

| Field                     | Description                                                                  | Available before boot              |
| ------------------------- | ---------------------------------------------------------------------------- | ---------------------------------- |
| `shopify_market`          | The buyer's Shopify market.                                                  | Yes                                |
| `customer_country`        | Two-letter country code.                                                     | Yes                                |
| `customer_currency`       | Active currency code.                                                        | Yes                                |
| `money_format`            | The store's Shopify money format.                                            | Yes                                |
| `backend_url`             | Direct backend host, used as a fallback when the app proxy isn't configured. | Yes                                |
| `storefront_access_token` | Token for Storefront API calls.                                              | **No** — added when the cart boots |

<Warning>
  `storefront_access_token` is the one `context` field the server does not render into `cart.context`. It is added to `context` when the cart boots, so reading it at the top of your script gets `undefined`. Await `window.aftersell.cart.ready()` first.
</Warning>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
if (window.aftersell.cart.context.customer_country === 'CA') {
  // Canada-only behavior, decided before the cart loads.
}
```

<Note>
  To show different block settings by market, country, or currency, use [conditions in the cart editor](/aftersell/cart/blocks-overview#show-or-hide-by-market-country-or-currency) instead. No script required. The full Conditions UI ships on [Rewards](/aftersell/cart/rewards-block#per-market-rewards) today.
</Note>

## shadowRoot

The cart renders inside a shadow root, so `document.querySelector` **cannot see anything inside the drawer**. To reach an element in the cart, query the shadow root:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const root = window.aftersell.cart.shadowRoot;
const button = root?.querySelector('.cart-external-checkout-button');
```

Target the same **public `cart-external-*` classes** that [Custom CSS](/aftersell/cart/custom-css) uses. Those are the supported handles. The `cart-internal-*` twins are the cart's own plumbing, so query the external ones instead.

<Warning>
  Reach for the shadow root only when no block, setting, or hook does the job. A hook survives a cart redesign; a DOM query is your code's problem to maintain.
</Warning>

The shadow root is only there once the cart has booted, so read it inside `ready()` or an event handler rather than at the top of your script.

## Debugging

A broken script must never take down add-to-cart or the drawer, so the SDK contains failures rather than letting them bubble. Where a failure surfaces depends on what broke:

| What failed                                                         | Where it shows up                                   |
| ------------------------------------------------------------------- | --------------------------------------------------- |
| Your script threw at the top level                                  | `console.error`, naming the line and what never ran |
| An [event](/aftersell/cart/sdk-events) handler threw                | `console.error`; the other handlers still run       |
| A [hook](/aftersell/cart/sdk-hooks) threw                           | Silent. Goes to the debug channel below             |
| An [action](/aftersell/cart/sdk-actions) ran before the cart loaded | `console.warn`; the call does nothing               |

### When your script throws

A custom script **stops at the first error**, so every `configure`, `events.on`, and `hooks.register*` below that line never runs. The cart says so explicitly:

```
[aftersell-cart] Initialization script error on line 12 — 4 more line(s) did not run;
any configure/events/hooks below are unregistered.
```

That's the message to look for when a handler you definitely registered never fires: it was probably never reached. The line number is the top-level statement where execution stopped, not the inner function that threw, and it's omitted rather than guessed at if the browser's stack isn't usable.

Your scripts also run under their own filenames, so they appear as `aftersell-cart-init.js` and `aftersell-cart-cart-update.js` in DevTools. You can open them from the Sources panel and set breakpoints like any other file.

### The debug channel

Hook failures are deliberately kept off the console so shoppers never see them. They go here instead:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// After reproducing the problem, inspect what was swallowed:
window.aftersellCartDebugEvents.filter((entry) => entry.level === 'ERROR');

// Or watch them live:
window.addEventListener('aftersell-cart-debug', (event) => console.log(event.detail));
```

## Where to go next

<Columns cols={2}>
  <Card title="Configure" icon="sliders" href="/aftersell/cart/sdk-configure">
    Every option, with an example each.
  </Card>

  <Card title="Events" icon="tower-broadcast" href="/aftersell/cart/sdk-events">
    Every event, when it fires, and what not to do in a handler.
  </Card>

  <Card title="Actions" icon="wand-magic-sparkles" href="/aftersell/cart/sdk-actions">
    Every action, with a snippet each.
  </Card>

  <Card title="Hooks" icon="plug" href="/aftersell/cart/sdk-hooks">
    Every hook, and how registrations compose.
  </Card>

  <Card title="Cart object" icon="table-list" href="/aftersell/cart/sdk-cart-object">
    The shape of the cart and its lines.
  </Card>

  <Card title="Use cases" icon="book-open" href="/aftersell/cart/sdk-use-cases">
    Complete, runnable solutions to common requests.
  </Card>
</Columns>
