JavaScript API
The methods of window.Smootify by task, for the cart, products, the customer, the market and consent, with short examples and how each kind of method answers.
window.Smootify gives your scripts the cart, the products, the logged-in customer, the visitor’s market and their consent. This page goes through the main methods by task, with short examples. Every method, with its full signature, is in the Reference under API.
Note
Call the methods from a window.Smootify.push function, so they run once Smootify is ready: see Run your scripts with Smootify. The examples on this page are the body of such a function, where Smootify is its argument.
window.Smootify = window.Smootify || [];
window.Smootify.push(async (Smootify) => {
const cart = await Smootify.getCart();
console.log(cart.totalQuantity, Smootify.formatMoney(cart.cost.totalAmount.amount));
});Methods, events, filters or the AJAX API
Your code works with Smootify in four ways. This page covers the methods; the other three have their own pages:
Methods: ask and act
- Use it to
- Read the cart, the products, the customer or the market; add to the cart; open the mini cart.
- For example
getCart(),addToCart(),getCustomer()- Good to know
- Call them from a
pushfunction. Most return a Promise.
Events: react to what happened
- Use it to
- Keep your own counter in sync, track additions, start analytics after consent.
- For example
cart_updated,added_to_cart,consent_changed- Good to know
- What the handler returns is ignored.
oncestops after the first event.
Filters: change it before it happens
- Use it to
- Check or enrich the lines added to the cart, change the checkout address or a draft order, choose the metafields the page asks for.
- For example
add_to_cart_lines,checkout_url- Good to know
- Answer the value changed, nothing to keep it, or
falseto stop.
AJAX API: apps written for Shopify themes
- Use it to
- Run an app's snippet as it is: Smootify answers the theme endpoints on the page.
- For example
/cart.js,/cart/add.js,/products/{handle}.js- Good to know
- Same cart as the page. Start the snippet with
type="smootify-load".
How the methods answer
- Most methods return a Promise.
isLoggedIn(),formatMoney(),selectVariant()and the listeners answer at once. - Some resolve with Shopify’s errors instead of the cart.
addToCart,applyCouponCodeandapplyGiftCardresolve with the cart, or with a list of errors ({ message, field, code }). Tell them apart withArray.isArray. - The other cart methods reject with Shopify’s errors. Use
try/catcharoundupdateCartLines,removeCartLines,removeCouponCode,removeGiftCard,updateCartNote,updateCartAttributesandcheckout. - Ids are Shopify’s global ids. A variant is
gid://shopify/ProductVariant/<id>, a cart linegid://shopify/CartLine/<id>, a productgid://shopify/Product/<id>. - The data has the Storefront API shape: the cart, the products and the customer carry the fields Smootify asks Shopify for, and
nullwhere Shopify has no value. The shapes are insmootify.d.ts.
Cart errors also go out with the smootify:errors event.
Cart
| Method | What it does |
|---|---|
getCart(), getCartID() | the cart, or its id |
addToCart(lines, goToCheckout) | adds lines; true goes on to checkout |
updateCartLines(lines), removeCartLines(ids), clearCart() | change, remove or empty the lines |
applyCouponCode(code), removeCouponCode(code) | discount codes |
applyGiftCard(code), removeGiftCard(id) | gift cards; the id is from cart.appliedGiftCards |
updateCartNote(note), updateCartAttributes(attributes) | the cart note and the cart attributes |
checkout() | goes to checkout, as the cart’s checkout button |
openCart(), closeCart() | open or close the page’s mini cart |
reloadCart() | asks Shopify for the cart again |
Add a variant from your own button, then open the mini cart:
document.querySelector("[data-add-sample]")?.addEventListener("click", async () => {
const answer = await Smootify.addToCart([
{ merchandiseId: "gid://shopify/ProductVariant/44012345678901", quantity: 1 },
]);
if (Array.isArray(answer)) console.warn(answer[0]?.message);
else await Smootify.openCart();
});Every addition goes through the add_to_cart_lines filters, then fires added_to_cart and cart_updated. A line can carry attributes ([{ key, value }], shown at checkout, hidden when the key starts with _) and a sellingPlanId.
Change the quantity of a line:
const cart = await Smootify.getCart();
const line = cart.lines.nodes[0];
if (line) {
try {
await Smootify.updateCartLines([{ id: line.id, quantity: line.quantity + 1 }]);
} catch (errors) {
console.warn(errors);
}
}A code that Shopify accepts but does not apply to this cart comes back in cart.discountCodes with applicable: false, not as an error.
checkout() goes through the checkout_url filters, like the cart’s button. openCart() and closeCart() work on a mini cart (a smootify-cart that opens), not on a cart page.
Two cart methods serve add-ons: addBoxToCart(lines, { title, image }, goToCheckout) adds lines as one Magic Box, and getCartAsDraftOrderData(email, note, customAttributes) gives the cart as a draft order (see Quotes and B2B).
Products
getProductByHandle(handle): a product by its handle, ornullwhen the visitor’s market does not sell it.getProductsById(ids): several products by their global ids, as an object keyed by id. Products the market does not sell are missing from it.selectVariant(element, variantId): selects a variant of asmootify-producton the page. The element is the product or any element inside it; the id is the variant number or its global id. It answersfalsewhen the product has no such variant.
const product = await Smootify.getProductByHandle("oak-chair");
if (product) console.log(product.title, product.variants.nodes.length);
const card = document.querySelector("smootify-product");
if (card) Smootify.selectVariant(card, 44012345678901);The product page’s product carries every variant. Elsewhere a product carries its first 250.
Customer
The customer methods need Shopify’s customer accounts and the newCustomerAccountsPublicKey option: see Customer accounts.
getCustomer(): the logged-in customer, ornullfor a guest, once the session is known.isLoggedIn(): answers at once, and isfalseuntil the session is known. PrefergetCustomer()at load.passwordlessLogin()starts Shopify’s login,logout()ends the session on the site and on Shopify.queryCustomer(fields): a Customer Account API query on the customer.fieldsis what goes insidecustomer { … }, and the answer is{ customer }.setCustomerMetafields(...metafields): writes metafields of the logged-in customer (namespaceiscustomwhen left out). In Shopify, the metafield definition needs Customer accounts access set to Read and write.getNewCustomerAccessToken(): the Customer Account API token of the session,""for a guest.
const customer = await Smootify.getCustomer();
if (customer) {
const { customer: data } = await Smootify.queryCustomer(
"orders(first: 3, reverse: true) { nodes { name totalPrice { amount currencyCode } } }",
);
console.log(customer.displayName, data);
}Market and money
getLocalization(): the visitor’s country (with its currency), language and market, and the countries and languages the store sells in.changeCountryByIsoCode(isoCode)andchangeMarketLanguage(languageCode): change the market. They answertruewhen it changed, and the page follows the new market.formatMoney(amount): an amount in the store’s money format. It takes a number in cents (1250) or an amount as Shopify sends it ("12.50").
const { country, language } = await Smootify.getLocalization();
console.log(country.isoCode, country.currency.isoCode, language.isoCode);
const changed = await Smootify.changeCountryByIsoCode("DE");
if (changed) console.log("Prices are now for Germany");The codes are Shopify’s: DE for a country, IT for a language.
Consent
getConsent(): the visitor’s consent, from Shopify’s Customer Privacy API. It loads Shopify’s consent script if the page has not loaded it yet.setConsent(choices): saves the visitor’s choices formarketing,analytics,preferencesandsaleOfData, and answers the new consent.
const consent = await Smootify.getConsent();
if (consent.allowed.analytics) {
// start your own analytics
}
await Smootify.setConsent({ analytics: true, marketing: false });To react when the visitor answers the banner, listen to consent_changed. The banner itself is in Cookie consent.
Toasts
toast(name, items) shows the page’s [toast="name"] template, the way Smootify shows its own toasts, with items written into its [toast-item] parts. It answers false when the page has no such template.
Smootify.toast("added-to-cart", { title: "Gift wrap", price: "€4.00" });
Smootify.toast("booking-saved", { message: "See you on Tuesday at 10:00" });A name of your own works when the designer adds a template with that name, such as [toast="booking-saved"]: only your code shows it. A name ending in -error falls back to the [toast="error"] template when its own is missing.
Storefront API
query(query, variables) sends a Storefront API query with the store’s access and answers its data. It rejects with the GraphQL errors. Use it for data no attribute shows.
The query runs as you write it. To get the visitor’s prices and translations, add Shopify’s @inContext directive with the country and language from getLocalization():
const { country, language } = await Smootify.getLocalization();
const data = await Smootify.query(
`query ($handle: String!, $country: CountryCode, $language: LanguageCode)
@inContext(country: $country, language: $language) {
product(handle: $handle) { title tags }
}`,
{ handle: "oak-chair", country: country.isoCode, language: language.isoCode },
);
console.log(data);Where people get stuck
Check these first
addToCartseems to succeed but nothing is added. It resolved with Shopify’s errors, such as a sold-out variant. Check the answer withArray.isArray.- An error thrown by
updateCartLinesis not caught. These methods reject:awaitthem insidetry/catch. isLoggedIn()isfalsefor a logged-in customer. The session is not known yet. Useawait Smootify.getCustomer().- Products come back empty.
getProductsByIdtakes global ids (gid://shopify/Product/…), and a product that is not published to the store’s sales channel, or not sold in the visitor’s market, is not returned. queryshows prices in the wrong currency. The query has no@inContextdirective.setCustomerMetafieldsanswers errors. The metafield definition in Shopify does not give customer accounts write access.
Coming from 1.x
The 21 methods of 1.x keep their names and arguments. 2.0 adds push, on, once, addFilter, isLoggedIn, getCustomer, logout, getLocalization, getConsent, setConsent, getProductByHandle, removeCouponCode, removeGiftCard, updateCartNote, updateCartAttributes, checkout, selectVariant, openCart and closeCart.
window.Smootify.storeand the other internals of 1.x are gone: only the methods ofwindow.Smootifyare supported.formatMoneyaccepts its two extra 1.x arguments and ignores them.passwordlessLoginandqueryCustomerwork only with Shopify’s new customer accounts.