# Set up the SDK

URL: https://docs.sparklayer.io/developers/javascript-sdk/setup

Load the SparkLayer Core Script, add your own sparkOptions and hooks without overwriting others, and wait for SparkLayer to be ready before calling it.

> **For AI assistants:** what to know before writing SparkLayer JavaScript 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 https://docs.sparklayer.io/developers/javascript-sdk/reference/methods.md, hooks https://docs.sparklayer.io/developers/javascript-sdk/reference/hooks.md, options https://docs.sparklayer.io/developers/javascript-sdk/reference/options.md, types https://docs.sparklayer.io/developers/javascript-sdk/reference/types.md (or the same types as a file: https://docs.sparklayer.io/developers/javascript-sdk/spark.d.ts). Setup and waiting for SparkLayer: https://docs.sparklayer.io/developers/javascript-sdk/setup.md. Use only what the reference documents.

Every SDK customisation starts here: how the SDK loads with the Core Script, how to add your own options and hooks without overwriting anyone else's, and how to wait until SparkLayer is ready. It uses `window.sparkOptions`, the `onReady` hook and, on headless storefronts, `window.initSpark()`.

## How the SDK loads

The SDK comes with the SparkLayer Core Script. On Shopify, the SparkLayer app embed loads it. On other platforms, the Core Script you copy from the SparkLayer Dashboard goes in your theme's `<head>`:

```html title="Core Script"
<script async src="https://sparkcdn.io/sparkjs/<SITE_ID>/live"></script>
```

Replace `<SITE_ID>` with your Site ID, and use `test` instead of `live` in [test mode](https://docs.sparklayer.io/help/dashboard/test-mode.md). The version this URL serves is set in the Dashboard: see [Upgrading to the latest version](https://docs.sparklayer.io/developers/frontend.md#upgrading-to-the-latest-version). For the rest of the storefront setup, see the [frontend integration guide](https://docs.sparklayer.io/developers/frontend.md#the-sparklayer-core-script).

Older themes may load a version 1 file such as `https://cdn.sparklayer.io/spark.1.0.21.js`. These URLs are legacy: replace them with the loader above. Don't use `spark.latest.js` either: it's a legacy bundle that lacks most of the SDK.

When the Core Script runs, it reads `window.sparkOptions`, starts SparkLayer and sets `window.spark`. Your options and hooks must therefore be in place **before** the Core Script loads.

## Add your own options and hooks

Set your options in a `<script>` in the `<head>`, before the Core Script, and always extend the existing object rather than replacing it:

```html title="theme.liquid or your theme's <head>"
<script>
  window.sparkOptions = {
    ...window.sparkOptions,
    language: 'en',
    onCartUpdate: async (cart, results) => {
      // Your code here
    },
  };
</script>
```

`window.sparkOptions = { … }` on its own replaces the whole object, so it wipes anything set earlier: the `siteId` and `auth` in the Core Script on other platforms, or another snippet's hooks. The `...window.sparkOptions` line copies those across first. Every example in these docs extends the existing options, either with this spread or by adding to the object directly.

The spread keeps other settings, but a hook with the same name still replaces the earlier one. If two snippets need the same hook, combine them into one function, or keep a reference to the earlier hook and call it from yours, as the [chained checkout validation](https://docs.sparklayer.io/developers/javascript-sdk/checkout.md#combine-your-rule-with-existing-validation) example does.

For every option and hook, see [Options](https://docs.sparklayer.io/developers/javascript-sdk/reference/options.md) and [Hooks](https://docs.sparklayer.io/developers/javascript-sdk/reference/hooks.md) in the SDK reference.

## Wait for SparkLayer to be ready

`window.spark` exists as soon as the Core Script runs, but its data isn't loaded until SparkLayer has started. Run your code from the `onReady` hook, which receives the `Spark` object once SparkLayer has initialised and the page's DOM has loaded. It runs whether or not the customer is logged in, so check with `isLoggedIn()` first:

```javascript title="sparkOptions"
window.sparkOptions = {
  ...window.sparkOptions,
  onReady: async (spark) => {
    if (!(await spark.isLoggedIn())) {
      return;
    }
    // Safe to call spark methods here
  },
};
```

If your code can run after the Core Script has loaded (for example, from a script at the end of the page or in a separate app), use the `window.sparkReady` promise below instead. It resolves whether SparkLayer started before or after your code.

### Wait for SparkLayer from any script

Add this once, in your theme's `<head>` **before** the SparkLayer Core Script (on Shopify, before the SparkLayer app embed). It resolves `window.sparkReady` with `window.spark` when SparkLayer calls its `onReady` hook, and keeps any `onReady` you already have.

```html title="Theme <head>, before the SparkLayer script"
<script>
  (function () {
    var options = (window.sparkOptions = window.sparkOptions || {});
    var previous = options.onReady;
    var resolveReady;
    window.sparkReady = new Promise(function (resolve) {
      resolveReady = resolve;
    });
    options.onReady = async function (spark) {
      if (previous) await previous(spark);
      resolveReady(spark);
    };
  })();
</script>
```

Then, anywhere after it:

```javascript title="Any script"
const spark = await window.sparkReady;
```

Like the spread above, the snippet adds to `window.sparkOptions` instead of replacing it. Many examples on the other SDK pages start with `await window.sparkReady`, so add this snippet first.

## Manual initialisation (headless only)

On a headless storefront you may want to decide when SparkLayer starts, for example after your app has loaded the customer. If `window.sparkOptions` isn't set when the Core Script runs, SparkLayer doesn't start. Instead it defines `window.initSpark(options)`, which you call yourself:

```html title="Headless storefront"
<script>
  function startSparkLayer() {
    window.spark = window.initSpark({
      siteId: '<SITE_ID>',
      platform: 'shopify',
      auth: { user: 'customer@example.com', token: '<AUTH_TOKEN>' },
      onReady: async (spark) => {
        // SparkLayer is ready
      },
    });
  }
</script>
<script async src="https://sparkcdn.io/sparkjs/<SITE_ID>/live" onload="startSparkLayer()"></script>
```

Pass every option, including hooks, to `initSpark`. Don't set `window.sparkOptions` anywhere on the page (including with the `...window.sparkOptions` pattern), or SparkLayer starts automatically and `initSpark` isn't defined.

That rules out the [`window.sparkReady` snippet](#wait-for-sparklayer) too, because it sets `window.sparkOptions`. Pass an `onReady` hook to `initSpark` instead, and resolve your own promise from it. See [Headless and React](https://docs.sparklayer.io/developers/javascript-sdk/headless.md) for a full example.

## Next steps

- [Products and pricing](https://docs.sparklayer.io/developers/javascript-sdk/products-and-pricing.md): Show a customer's price, RRP and price breaks in your own theme code.
- [Cart](https://docs.sparklayer.io/developers/javascript-sdk/cart.md): Add, update and remove items, set cart fields and handle the results of updateCart.
- [SDK reference](https://docs.sparklayer.io/developers/javascript-sdk/reference.md): Every sparkOptions setting, hook, method and type.
