Custom Cart Integration

Integrating Abra promotions with a native Shopify theme cart. Abra is loaded as a global app embed and already runs on the storefront. This spec is what the theme/cart must do to work with it.

Constraints

  1. Cart mutations must use Shopify's AJAX Cart endpoints: /cart/add.js, /cart/change.js, /cart/update.js, /cart/clear.js (or full page reload). Abra detects cart changes by observing these requests and re-renders itself. A custom cart that mutates only via Storefront GraphQL with no reload will not trigger Abra.

  2. Cart updates must use fetch (not XMLHttpRequest ) for /cart/change.js.

Line-item properties to handle

Abra writes metadata onto cart lines (line-item properties) and onto the cart (cart attributes) to track promotion state: which lines are free gifts/rewards, which lines are a bundle and its components, the bundle definition, and which promo code is attributed to the cart. Your theme reads this metadata to style and lock the relevant lines.

Where to read them:

  • Liquid: item.properties.<key> on each cart line; cart.attributes.<key> for cart-level.

  • AJAX API: GET /cart.jsitems[].properties.<key> per line; top-level attributes.<key> for cart-level.

Values come back as strings. The ones marked "JSON" below are JSON-encoded strings you must JSON.parse.

Property

Value

Required theme behavior

__hide_quantity

true

Hide/disable the quantity selector for this line.

_abra_bundle

non-empty JSON string

This line is the merged bundle (also has Shopify

has_components). Style as bundle; hide quantity.

_abra_bundled

marker string

This line is a bundle component. Style as bundle child.

__abra

JSON {"discount":"..."}

Line tied to an Abra promotion (gift/reward). Optional to display.

Cart-level attributes (on cart.attributes):

Attribute

Value

_abra_bxgy_bundle

JSON array of bundle configs (bundle definition).

__abra

JSON {"code","redeemCode","attributedAt"} (promo attribution).

Gift and reward lines

Free gifts come from Gift-with-Purchase promotions and from any "free gift" tier of a tiered / volume / multi-effect promo — all use the same mechanism. Abra auto-adds the gift as a normal cart line and tags it:

  • __hide_quantity "true") → Optionally hide/disable the quantity selector on this line.

  • __abra {"discount":"<promo title>"}) → which promotion the gift belongs to.

if (item.properties?.__hide_quantity) {
	// gift / reward line → hide the quantity selector
}

Bundle identification

Identify Abra bundles by these line item properties:

  • _abra_bundle = the one merged line the customer sees as "the bundle." This is the line you style and quantity-lock.

  • _abra_bundled (the components) = the individual products that were folded into it.

  • _abra_bxgy_bundle (cart attribute, not a line property) = the bundle's definition (title, items, fixed price) Abra uses to build/rebuild it.

In other words, the merged _abra_bundle line is the top-level line; the _abra_bundled products are its components beneath it.

What this looks like in /cart.js:

{
  "attributes": {
    "_abra_bxgy_bundle": "[{\"bundleTitle\":\"Father's Day Bundle\",\"bundleItems\":[...],\"fixedPriceCents\":3999,\"currencyCode\":\"USD\"}]",
    "__abra": "{\"code\":\"SAVE20\",\"redeemCode\":null,\"attributedAt\":\"2026-06-16T...\"}"
  },
  "items": [
    {
      "has_components": true,
      "properties": {
        "_abra_bundle": "{\"discountTitle\":\"Father's Day Bundle\",...}"
      }
    },
    {
      "properties": {
        "_abra_bundled": "Father's Day Bundle::0"
      }
    },
    {
      "properties": {
        "__hide_quantity": "true",
        "__abra": "{\"discount\":\"Free Gift\"}"
      }
    }
  ]
}

Cart UI events

Abra re-renders its own injected content (discounted prices, banners) on its own when it sees cart requests — you don't trigger that. But when Abra changes the cart contents itself (auto-adds/removes a gift, merges a bundle), your cart drawer doesn't know. Wire up two events:

  1. Listen to abra:cart:changed — Abra fires this after it mutates the cart. Re-fetch and re-render your cart so Abra-added gifts/bundles appear.

window.addEventListener('abra:cart:changed', async () => {
  // Your re-render
});
  1. Dispatch abra:render if you want to re-render the Abra banner

window.dispatchEvent(new CustomEvent('abra:render'));