Methods
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 oldcdn.sparklayer.io/spark.latest.jsandspark.1.x.jsfiles 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 whenwindow.sparkOptionsisn'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 (checkawait 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 withgetVariantand callcalculatePricingForVariantData(variant, qty). - Cart:
updateCart({ products: [{ sku, adjustQuantity }] })adds or removes relative to what's in the cart (alsocustomAttributes: [{ key, value }],clearCart: true). It resolves to the results, ornullafter 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) andonCheckoutValidation(cart, cartUiState)(return[{ message }]to block checkout, ornull). 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.
Wait for SparkLayer
window.spark is set as soon as the Core Script runs, but its methods only work once SparkLayer is ready. Call them from the onReady hook, or add the Wait for SparkLayer snippet and start with const spark = await window.sparkReady;, as the examples on this page do.
The Spark object
The Spark object is available as window.spark, and is passed to the onReady and onLoad hooks. Its public members are:
type Spark = {
options: SparkLayerOptions;
isLoggedIn(): Promise<boolean>;
switchImpersonatingCustomer(customerId: string | null): Promise<UserData | null>;
refreshGlobalData(): Promise<UserData | null>;
getActiveCustomerVerificationToken(): Promise<string | null>;
setActiveCompanySection(sectionId: string): Promise<boolean>;
getProduct(parentProductId: string): Promise<Product>;
getProductBySlug(slug: string): Promise<Product>;
getVariant(parentProductId: string, variantSku: string): Promise<ProductVariant>;
getPriceForProduct(parentProductId: string): Promise<SimplifiedProductPrice>;
getPricingForVariant(
parentProductId: string,
variantSku: string,
): Promise<{
price: number | null;
rrp: number | null;
rrpCurrencyCode: string | null;
priceBreaks: VariantPriceBreak[];
currencyCode: string;
}>;
getRrpPriceForVariant(
parentProductId: string,
variantSku: string,
): Promise<{ rrp: number | null; currencyCode: string | null }>;
getPackSizeForVariant(parentProductId: string, variantSku: string): Promise<number>;
calculatePricingForVariant(
parentProductId: string,
variantSku: string,
qty: number,
qtyAcrossVariants?: number | null,
): Promise<ProductVariantPricing>;
calculatePricingForVariantData(
variant: ProductVariantDataPricing,
qty: number,
qtyAcrossVariants?: number | null,
): ProductVariantPricing;
getCart(): Promise<Cart | null>;
getCartCache(): Cart | null;
updateCart(
input: Partial<UpdateCart>,
cartSuccessHandledLocally?: boolean,
cartErrorsHandledLocally?: boolean,
): Promise<CartResults[] | null>;
addCustomLineItem(customItem: CustomLineItemInput): Promise<Cart | null>;
externalClearBasket(): Promise<void>;
openDrawer(initialTab?: DrawerUIState): void;
closeDrawer(): void;
uploadFile(fileName: string, fileData: Blob): Promise<string>;
fetch<Q extends GraphqlQueryOrMutation<unknown, Record<string, unknown>, GraphqlError | GraphqlExtensionError>>(
query: Q,
variables?: VariablesOf<Q>,
useImpersonatingCustomer?: boolean,
bypassAppProxy?: boolean,
signal?: AbortSignal,
): Promise<FetchResponse<ResponseOf<Q>, ErrorOf<Q>>>;
};options
Type: SparkLayerOptions
The options SparkLayer is running with, after merging your sparkOptions with the platform defaults. See Options.
const spark = await window.sparkReady;
console.log(spark.options.platform, spark.options.language);Customers and session
isLoggedIn()
Checks whether the user is logged in.
isLoggedIn(): Promise<boolean>;Returns: Promise<boolean>
const spark = await window.sparkReady;
if (await spark.isLoggedIn()) {
// Show B2B content
}switchImpersonatingCustomer()
Switches the customer a sales agent is impersonating, or ends impersonation when you pass null.
switchImpersonatingCustomer(customerId: string | null): Promise<UserData | null>;| Name | Type | Description |
|---|---|---|
customerId | string | null | The customer to impersonate, or null to end impersonation. |
Returns: Promise<UserData | null>
const spark = await window.sparkReady;
const customer = await spark.switchImpersonatingCustomer('<CUSTOMER_ID>');
await spark.switchImpersonatingCustomer(null); // End impersonationrefreshGlobalData()
Refetches the current active customer and site configuration, and updates the cached copy both are read from.
refreshGlobalData(): Promise<UserData | null>;Returns: Promise<UserData | null>
const spark = await window.sparkReady;
const user = await spark.refreshGlobalData();getActiveCustomerVerificationToken()
Refetches the current active customer and returns a fresh form customer verification token. It uses the impersonated customer when a sales agent is impersonating, otherwise the logged-in customer.
getActiveCustomerVerificationToken(): Promise<string | null>;Returns: Promise<string | null>
const spark = await window.sparkReady;
const token = await spark.getActiveCustomerVerificationToken();setActiveCompanySection()
Selects the company section used for purchasing. If the cart isn't empty, the user is asked to confirm and the cart is cleared. The page then reloads.
setActiveCompanySection(sectionId: string): Promise<boolean>;| Name | Type | Description |
|---|---|---|
sectionId | string | The ID of one of the logged-in customer's company sections. |
Returns: Promise<boolean>: false if the section isn't available to the customer, the user cancels, or the cart couldn't be cleared.
const spark = await window.sparkReady;
const user = await spark.refreshGlobalData();
const section = user?.companySections[0];
if (section) await spark.setActiveCompanySection(section.id);Products and pricing
Each method takes your platform's parent product ID and, for a variant, its SKU. Prices are for the logged-in customer.
getProduct()
Fetches the GraphQL product object for a parent product ID.
getProduct(parentProductId: string): Promise<Product>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
Returns: Promise<Product>
Throws: if the product isn't found or an error occurs fetching it.
const spark = await window.sparkReady;
const product = await spark.getProduct('6660191387839');
console.log(product.variants.map((variant) => variant.sku));getProductBySlug()
Fetches the GraphQL product object for a product slug.
getProductBySlug(slug: string): Promise<Product>;| Name | Type | Description |
|---|---|---|
slug | string | The product slug. |
Returns: Promise<Product>
Throws: if the product isn't found or an error occurs fetching it.
const spark = await window.sparkReady;
const product = await spark.getProductBySlug('mother-mug');getVariant()
Fetches the GraphQL variant object for a parent product ID and variant SKU.
getVariant(parentProductId: string, variantSku: string): Promise<ProductVariant>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
variantSku | string | The variant SKU. |
Returns: Promise<ProductVariant>
Throws: if the product or variant isn't found or an error occurs fetching the product.
const spark = await window.sparkReady;
const variant = await spark.getVariant('6660191387839', 'MUG-MOM');
console.log(variant.name, variant.stockDisplay?.status);getPriceForProduct()
Fetches the pricing for a parent product, including price breaks, the lowest price and the number of prices.
getPriceForProduct(parentProductId: string): Promise<SimplifiedProductPrice>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
Returns: Promise<SimplifiedProductPrice>: all price-related data for the parent product, including price breaks, the lowest price and the number of prices. Use the number of prices to decide whether to show "from" before the price.
Throws: if the product isn't found or an error occurs fetching it.
const spark = await window.sparkReady;
const { fromPrice, numberOfPrices, currencyCode } = await spark.getPriceForProduct('6660191387839');
const label = `${numberOfPrices > 1 ? 'From ' : ''}${fromPrice} ${currencyCode}`;getPricingForVariant()
Fetches the pricing for a variant.
getPricingForVariant(
parentProductId: string,
variantSku: string,
): Promise<{
price: number | null;
rrp: number | null;
rrpCurrencyCode: string | null;
priceBreaks: VariantPriceBreak[];
currencyCode: string;
}>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
variantSku | string | The variant SKU. |
Returns: all price-related data for the variant: price, rrp, rrpCurrencyCode, priceBreaks (each a VariantPriceBreak) and currencyCode.
Throws: if the product or variant isn't found or an error occurs fetching the product.
const spark = await window.sparkReady;
const pricing = await spark.getPricingForVariant('6660191387839', 'MUG-MOM');
console.log(pricing.price, pricing.currencyCode, pricing.priceBreaks);getRrpPriceForVariant()
Fetches the RRP for a variant.
getRrpPriceForVariant(
parentProductId: string,
variantSku: string,
): Promise<{ rrp: number | null; currencyCode: string | null }>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
variantSku | string | The variant SKU. |
Returns: the RRP (null if not set for the currency) and the currency code.
Throws: if the product or variant isn't found or an error occurs fetching the product.
const spark = await window.sparkReady;
const { rrp, currencyCode } = await spark.getRrpPriceForVariant('6660191387839', 'MUG-MOM');getPackSizeForVariant()
Fetches the pack size for a variant.
getPackSizeForVariant(parentProductId: string, variantSku: string): Promise<number>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
variantSku | string | The variant SKU. |
Returns: Promise<number>: the variant's pack size, or 1 if none is set.
Throws: if the product or variant isn't found or an error occurs fetching the product.
const spark = await window.sparkReady;
const packSize = await spark.getPackSizeForVariant('6660191387839', 'MUG-MOM');
const quantity = Math.ceil(10 / packSize) * packSize; // Round 10 up to whole packscalculatePricingForVariant()
Returns the price for a quantity of a variant, given its parent product ID and SKU.
calculatePricingForVariant(
parentProductId: string,
variantSku: string,
qty: number,
qtyAcrossVariants?: number | null,
): Promise<ProductVariantPricing>;| Name | Type | Description |
|---|---|---|
parentProductId | string | The parent product ID. |
variantSku | string | The variant SKU. |
qty | number | The quantity to calculate pricing for. |
qtyAcrossVariants? | number | null | For tiered pricing, the quantity across variants (if configured). Defaults to null. |
Returns: Promise<ProductVariantPricing>: the total price (quantity × unit price), the unit price and the price breaks.
Throws: if the product or variant isn't found or an error occurs fetching the product.
const spark = await window.sparkReady;
const pricing = await spark.calculatePricingForVariant('6660191387839', 'MUG-MOM', 2);
console.log(pricing.totalPrice, pricing.unitPrice, pricing.currencyCode);calculatePricingForVariantData()
Calculates the pricing for a variant from variant data you already have, without fetching.
calculatePricingForVariantData(
variant: ProductVariantDataPricing,
qty: number,
qtyAcrossVariants?: number | null,
): ProductVariantPricing;| Name | Type | Description |
|---|---|---|
variant | ProductVariantDataPricing | Variant data, including the RRP and price breaks. A ProductVariant or CartItem works. |
qty | number | The quantity to calculate pricing for. |
qtyAcrossVariants? | number | null | For tiered pricing, the quantity across variants (if configured). Defaults to null. |
Returns: ProductVariantPricing: the total price (quantity × unit price), the unit price and the price breaks.
const spark = await window.sparkReady;
const variant = await spark.getVariant('6660191387839', 'MUG-MOM');
const pricing = spark.calculatePricingForVariantData(variant, 24); // No requestSee Live price as the quantity changes for a full example.
Cart
See Cart for worked examples.
getCart()
Fetches the cart from GraphQL.
getCart(): Promise<Cart | null>;Returns: Promise<Cart | null>: the cart, or null if it couldn't be fetched (an error toast is shown).
const spark = await window.sparkReady;
const cart = await spark.getCart();
console.log(cart?.items.length, cart?.totals.total.charge.gross.number);getCartCache()
Gets the cached cart, if available, without a request.
getCartCache(): Cart | null;Returns: Cart | null: the cached cart, or null if it isn't available.
const spark = await window.sparkReady;
const cart = spark.getCartCache() ?? (await spark.getCart());updateCart()
Runs an update cart mutation, shows the appropriate toasts and returns the result. It makes every change to the cart: adding, updating and removing items, and setting cart-level fields.
updateCart(
input: Partial<UpdateCart>,
cartSuccessHandledLocally?: boolean,
cartErrorsHandledLocally?: boolean,
): Promise<CartResults[] | null>;| Name | Type | Description |
|---|---|---|
input | Partial<UpdateCart> | Follows the GraphQL updateCart mutation's variables. Each product is a CartItemInput. |
cartSuccessHandledLocally? | boolean | Don't show success toasts, as you'll handle the result yourself (useful in the cart, where the update itself shows the change). Defaults to false. |
cartErrorsHandledLocally? | boolean | Don't show toasts for the messages in the results, as you'll handle them yourself. Defaults to false. |
Returns: Promise<CartResults[] | null>: the results, or null if the update failed. It doesn't throw: on failure it shows an error toast and logs the error to the console. See What updateCart returns.
const spark = await window.sparkReady;
const results = await spark.updateCart({
products: [{ sku: 'RED-SHIRT-M', adjustQuantity: 1 }],
});addCustomLineItem()
Adds a custom line item (a free-text name, price and quantity not tied to a SKU) to the cart. The active customer must have custom cart items enabled, otherwise the request is rejected.
addCustomLineItem(customItem: CustomLineItemInput): Promise<Cart | null>;| Name | Type | Description |
|---|---|---|
customItem | CustomLineItemInput | The name, unit price (as a decimal string) and quantity. |
Returns: Promise<Cart | null>: the refreshed cart, or null if the item couldn't be added.
const spark = await window.sparkReady;
const cart = await spark.addCustomLineItem({ name: 'Artwork set-up', quotedPrice: '25.00', quantity: 1 });externalClearBasket()
Tells SparkLayer to clear the basket. Designed for your order confirmation (thank you) page.
externalClearBasket(): Promise<void>;Returns: Promise<void>
const spark = await window.sparkReady;
await spark.externalClearBasket();Drawer
openDrawer()
Opens the SparkLayer drawer, optionally on a specific tab.
openDrawer(initialTab?: DrawerUIState): void;| Name | Type | Description |
|---|---|---|
initialTab? | DrawerUIState | The tab to open on. Defaults to "cart". |
Returns: void
const spark = await window.sparkReady;
spark.openDrawer('account');To switch a drawer that's already open to another tab, dispatch the view-update event.
closeDrawer()
Closes the SparkLayer drawer.
closeDrawer(): void;Returns: void
const spark = await window.sparkReady;
spark.closeDrawer();Files and GraphQL
uploadFile()
Uploads a file to the SparkLayer file store. Pass the returned ID as a cart item attribute to attach the file (see Attach a file).
uploadFile(fileName: string, fileData: Blob): Promise<string>;| Name | Type | Description |
|---|---|---|
fileName | string | The name of the file, including its extension. It must match the type of the data in fileData. |
fileData | Blob | The file data as a Blob. |
Returns: Promise<string>: the uploaded file's ID (a GID).
Throws: if the file type isn't supported, the file is too large, the file path is invalid, or the upload fails.
const spark = await window.sparkReady;
const gid = await spark.uploadFile('design.png', fileBlob);
await spark.updateCart({
products: [{ sku: 'SHIRT-CUSTOM', adjustQuantity: 1, customAttributes: [{ key: 'Design', value: JSON.stringify([gid]) }] }],
});fetch()
Runs a GraphQL query or mutation as the authenticated user.
fetch<Q>(
query: Q,
variables?: VariablesOf<Q>,
useImpersonatingCustomer?: boolean,
bypassAppProxy?: boolean,
signal?: AbortSignal,
): Promise<FetchResponse<ResponseOf<Q>, ErrorOf<Q>>>;Type parameter: Q extends GraphqlQueryOrMutation<unknown, Record<string, unknown>, GraphqlError | GraphqlExtensionError>. See GraphqlQueryOrMutation.
| Name | Type | Description |
|---|---|---|
query | Q | The GraphQL query string. |
variables? | VariablesOf<Q> | The GraphQL variables. |
useImpersonatingCustomer? | boolean | Whether to make the request as the customer being impersonated, rather than as the sales agent. |
bypassAppProxy? | boolean | Call the API directly rather than through the platform's app proxy. |
signal? | AbortSignal | Aborts the request, for example when its result is no longer needed. |
Returns: Promise<FetchResponse<ResponseOf<Q>, ErrorOf<Q>>>: a standard Response object. Check status, and call json() to get the data and errors.
const spark = await window.sparkReady;
const response = await spark.fetch(`query { loggedInCustomer { id email } }`);
if (response.status === 200) {
const { data, errors } = await response.json();
if (!errors?.length) console.log(data.loggedInCustomer.email);
}See Run a GraphQL query.
Next steps
Last updated