Skip to main content
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, or through a Custom code block’s React mode for a block that renders its own UI.
Plenty of what merchants ask the SDK for is already a setting. Before writing a script, check whether a cart block, conditions by market/country/currency, or a cart setting already does it. Those keep working through cart redesigns, and your script may not.

The global entry point

Everything hangs off one global:
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.
Four parts do the work:

Configure

Set how the cart behaves: when the drawer opens, how money is formatted, whether Aftersell intercepts add-to-cart.

Events

React to what happens: the cart loaded, an item was added, the drawer opened, checkout was clicked.

Actions

Read and change the cart: open it, add an item, update a quantity, read the current state.

Hooks

Change how the cart itself works: hide or relabel lines, reorder them, attach extra data, control add-to-cart.
If a script of yours stopped firing on add-to-cart, start with Add-to-cart interception. It explains why Aftersell takes over the add, and every way to opt a form out.
Plus three smaller members:

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: 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:

Set-up calls: safe immediately

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.

Actions: wait for ready()

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.

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.
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.

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.
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.
To show different block settings by market, country, or currency, use conditions in the cart editor instead. No script required. The full Conditions UI ships on Rewards today.

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:
Target the same public cart-external-* classes that Custom CSS uses. Those are the supported handles. The cart-internal-* twins are the cart’s own plumbing, so query the external ones instead.
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.
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:

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:
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:

Where to go next

Configure

Every option, with an example each.

Events

Every event, when it fires, and what not to do in a handler.

Actions

Every action, with a snippet each.

Hooks

Every hook, and how registrations compose.

Cart object

The shape of the cart and its lines.

Use cases

Complete, runnable solutions to common requests.