Skip to content

Checkout

For AI assistants: what to know before writing SparkLayer SDK code
  • What it is: window.spark, added to the storefront by the SparkLayer Core Script (version 4.x). On Shopify the SparkLayer app embed loads it; elsewhere it's <script async src="https://sparkcdn.io/sparkjs/<SITE_ID>/<live|test>"></script> in the theme's <head>. The old cdn.sparklayer.io/spark.latest.js and spark.1.x.js files are legacy: never use them.
  • Options: Configure it with window.sparkOptions, set before the Core Script loads. Extend the object rather than replacing it: window.sparkOptions = { ...window.sparkOptions, … }, or the Site ID and other snippets' hooks are lost. Headless only: window.initSpark(options) is defined when window.sparkOptions isn't set.
  • When to call it: Only after SparkLayer is ready: inside the onReady(spark) hook, or after a promise resolved from it. Most methods are async; prices and the cart are only available to signed-in B2B customers (check await spark.isLoggedIn()).
  • Products and prices: Products are looked up by the platform's parent product ID (on Shopify, product.id) and variants by SKU: getPricingForVariant(parentProductId, sku), calculatePricingForVariant(parentProductId, sku, qty), getPackSizeForVariant(parentProductId, sku). For instant recalculation, fetch once with getVariant and call calculatePricingForVariantData(variant, qty).
  • Cart: updateCart({ products: [{ sku, adjustQuantity }] }) adds or removes relative to what's in the cart (also customAttributes: [{ key, value }], clearCart: true). It resolves to the results, or null after showing its own error message; it doesn't throw. getCart() reads the cart; openDrawer('cart') opens it.
  • Hooks: onCartUpdate(cart, results), onCartLoad(cart), onLogout(), preCartUpdateListener(input) (async: return the possibly changed input) and onCheckoutValidation(cart, cartUiState) (return [{ message }] to block checkout, or null). When adding a hook, call any existing one first.
  • Customising: Build around SparkLayer or customise its own components, including their HTML. Prefer documented options, hooks, CSS variables and custom slots where they fit; keep direct HTML changes targeted and re-check them after SparkLayer updates.
  • Docs: The reference: methods docs.sparklayer.io/developers/javascript-sdk/reference/methods.md, hooks docs.sparklayer.io/developers/javascript-sdk/reference/hooks.md, options docs.sparklayer.io/developers/javascript-sdk/reference/options.md, types docs.sparklayer.io/developers/javascript-sdk/reference/types.md (or the same types as a file: docs.sparklayer.io/developers/javascript-sdk/spark.d.ts). Setup and waiting for SparkLayer: docs.sparklayer.io/developers/javascript-sdk/setup.md. Use only what the reference documents.

Add your own rules to SparkLayer's checkout, for rules SparkLayer's own settings don't cover. This page uses the onCheckoutValidation hook, with examples that call your own API and that combine several rules.

Add custom checkout validation

onCheckoutValidation lets you check the cart against your own rules, or your own API, before the customer can check out. For example, you could check whether a customer has already used up a one-off discount or a product quota, or limit how many free samples go in one order.

The hook must be an async function. It receives the Cart and the current checkout step (a CartUIState, so your rules can vary by step), and returns null if the cart is valid or an array of { message } objects if it isn't.

SparkLayer shows each message to the customer and won't let them check out until the hook returns null. The hook runs every time the cart loads or changes, so keep it quick: avoid network requests unless your rule needs them, and keep any you make fast.

Check the cart against your API

This example sends the cart to your own endpoint and blocks checkout if it says the cart isn't valid:

sparkOptions
window.sparkOptions = {
  ...window.sparkOptions,
  onCheckoutValidation: async (cart, cartUiState) => {
    const response = await fetch('https://example.com/cart-validation', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(cart),
    });
    const { valid } = await response.json();

    if (valid) {
      return null;
    }

    return [{ message: 'This order is over your quota for one of these products.' }];
  },
};

Decide what should happen if your API is unreachable. Here, a failed request rejects the promise: SparkLayer logs the error to the console and doesn't apply a result.

Combine your rule with existing validation

Setting onCheckoutValidation replaces any hook another snippet has set. To add a rule without losing one that's already there, keep a reference to the earlier hook, call it, and add your messages to its list. This example limits free samples to three per order:

Theme <head>, before the SparkLayer script
<script>
  (function () {
    var options = (window.sparkOptions = window.sparkOptions || {});
    var previous = options.onCheckoutValidation;

    options.onCheckoutValidation = async function (cart, cartUiState) {
      var errors = (previous && (await previous(cart, cartUiState))) || [];

      var samples = cart.items
        .filter(function (item) {
          return item.sku && item.sku.indexOf('SAMPLE-') === 0;
        })
        .reduce(function (total, item) {
          return total + item.quantity;
        }, 0);

      if (samples > 3) {
        errors.push({
          message: 'You can order up to 3 samples per order. Remove ' + (samples - 3) + ' to continue.',
        });
      }
      return errors.length ? errors : null;
    };
  })();
</script>

Collect extra details at checkout

To ask customers for a PO number, a requested delivery date or your own fields at checkout, turn on checkout fields in the Help Center, or set them in code with the checkoutCustomElements option. To fill these values in from your own code, see Cart-level fields.

Next steps

Was this page helpful?

Last updated