window.aftersell.cart.hooks.
A hook changes what the shopper sees; an action changes what’s in their cart. Hiding a free gift line with a transform leaves it in the cart and in the total. Removing it with
removeItem takes it out for real.Hooks are set-up calls, so they’re safe to register at the very top of your script, with no need to wait for
ready(). Register them in your cart’s Initialization script (see Custom scripts).How registration works
Every hook is aregister* method. You call it with your function; it returns an unregister function you can call to remove yours.
A hook that throws, or that isn’t a function, is skipped; the rest still run, and the cart carries on. One broken integration can’t take down add-to-cart, the subscription picker, or the sort.
The flip side is that a broken hook of yours fails silently: nothing reaches the browser console. See Debugging for where those failures do surface.
registerLineTransform
registerLineTransform(fn) runs for every cart line before it renders. Use it to hide a line or change how it reads, without touching what’s actually in the shopper’s cart.
The function receives a read-only line plus setters. It returns an unregister function.
setInternalProperties is the setter behind bundle grouping: stamping the canonical bundle properties onto each line is how you make a third-party app’s separate cart lines render as one item. See Group bundle lines from another app.
registerLineComparator
A comparator in the same shapeArray.prototype.sort expects. It runs after hide and rename, so it sees the transformed lines.
0 for pairs you have no opinion about. That’s what hands the decision to the next comparator instead of forcing an order on it.
Use it for: floating subscriptions or high-value items to the top, sinking free gifts and add-ons to the bottom, keeping a sponsored product first.
registerCartEnricher
registerCartEnricher(registration) fetches extra product or variant data from the Shopify Storefront API and attaches it to each matching cart line at line.metadata[id]. Use it to surface metafields, tags, or anything else the Storefront API exposes, with no code change from Aftersell required.
Returns an unregister function.
Whenever the cart loads or changes, Aftersell fetches your fragment for every product or variant on the cart and attaches the result. The fetch is non-blocking: the cart renders immediately and re-emits
cart_updated once the data lands. A slow or failing fragment never delays or breaks the cart.
line.metadata.pricing is undefined until the first fetch resolves, and metadata itself defaults to {}.
Use it for: pulling a metafield onto every line (a delivery estimate, an ingredient list, a “ships separately” flag, a loyalty multiplier) and rendering it through a Custom code block. See showing metafield data on cart lines.
Multiple enrichers coexist happily, since each
id is its own namespace, so their data never collides.registerSubscriptionOptionsTransform
Hide or rename the selling plans offered on a line. Your function receives read-only options plus setters, and returns nothing.options.filter(...) and silently delete every other app’s plans on its way out. With setters you can only describe your own edits: patches merge per plan and per field, and the last writer wins a genuine conflict on the same field of the same plan. A transform that throws contributes nothing, and the others still apply.
Every transform sees the original options, not a half-patched view, so registration order doesn’t change what you’re reading.
Plan order stays as Shopify returned it, so a transform can’t reorder. To control which plan is offered first (and which one the one-time upgrade button subscribes to), use
registerDefaultSubscriptionOptionSelector, which promotes its pick to the front.discountPercent has no setter, because a plan Shopify won’t honor at checkout would just be a broken promise in the picker.
registerDefaultSubscriptionOptionSelector
Choose which plan is preselected on a line. Return a planid, or null to pass on it.
null for the lines you don’t care about rather than guessing. That hands the decision to the next selector instead of overriding it. An id that doesn’t match any plan on the line is treated the same as null and defers too, so a stale id can’t blank out the picker.
Your function receives (options, context), the same context the options transform gets.
registerSkipAddToCartRule
Returntrue to let a specific product form add to the cart normally, bypassing Aftersell entirely. This is useful for a form that needs its own redirect or handling.
true skips, so keep your rule narrow, matching the specific forms you own, and return false for everything else. Rules are evaluated in registration order and stop at the first true, so don’t put side effects in one: whether yours runs at all depends on what registered before it.
Use it for: a pre-order or quote form that needs its own redirect, a subscription app’s custom flow, a “buy it now” button that should go straight to checkout. To turn interception off for the whole page instead, use skip_add_to_cart_interceptor, but prefer this hook, which is scoped to the forms you name.
Where to go next
- Cart object: the shape of the line a transform receives.
- Events: everything you can subscribe to.
- Actions: reading and changing the cart.
- Use cases: complete solutions to common requests.