Run your scripts with Smootify
How your own code waits for Smootify, with window.Smootify.push, script type smootify-load or the smootify:loaded event, and the order in which they run at load.
Smootify loads as an asynchronous module. A plain script on the page usually runs before it: window.Smootify is not ready yet and the first events have already been missed. This page shows the three ways to make your code wait for Smootify, and the order in which they run.
Let Claude write it, in Smootify Studio
Smootify Studio, the desktop app for Mac and Windows, gives each site its own folder of custom scripts, and writes them with you through Claude:
- Write with Claude. A conversation opens in the app, in the script’s folder, with Smootify’s custom-script skill and the site’s details already loaded. Claude asks what the script should do, then writes it with Smootify’s conventions:
window.Smootify.push, the events and their payloads, the markup of the page, and the types below. - Try it on the site. Studio’s dev server runs your latest code on the real site at every reload, with no publishing to see a change.
- Build. One click type-checks the source and turns it into the single file the site loads.
- Put it on the site. Claude tells you how. A small script goes inline, pasted in the site’s custom code. One too big for Webflow’s custom code limits is uploaded to your own Cloudflare R2 storage, and the site loads it from there.
You can open the folder in your own editor or terminal at any time. Claude runs on your own Claude account.
Where to put your code
- Every page: Site settings, Custom code, in the Head code or the Footer code.
- One page: the page settings, Custom code.
- One place in the layout: a Code Embed element.
window.Smootify.push works from all of these places, and from a tag manager.
1. window.Smootify.push (recommended)
<script>
window.Smootify = window.Smootify || [];
window.Smootify.push((Smootify) => {
Smootify.on("cart_updated", (cart) => console.log(cart.totalQuantity));
});
</script>This is the same pattern as window.Webflow.push. Before Smootify loads, window.Smootify is a plain list of functions. When Smootify starts, it runs them with the API as the argument.
- When it runs. As soon as Smootify knows the visitor and the market, before it loads products and the cart. The session, the market and the price format are known at that point.
- Listeners and filters. A listener added there gets the events from the first
product_loadedandcart_updatedon. A filter added there applies from the first request to Shopify. - Functions pushed later. A function pushed after Smootify has loaded, by a tag manager for example, runs right away. By then the first events may have gone out:
{ replay: true }onSmootify.onalso calls your handler with the last one. - Errors. A function that throws is logged in the console and does not stop the others.
For data, use the async methods, such as getCart() and getCustomer(). To run code once everything has loaded, wherever the script sits:
window.Smootify = window.Smootify || [];
window.Smootify.push((Smootify) => {
Smootify.on(
"loaded",
() => {
// the session, the market and the cart are known
},
{ replay: true },
);
});2. <script type="smootify-load">
Use it for code that must not run before Smootify but does not call its API. The typical case is a snippet from a third-party app that calls Shopify’s AJAX API (/cart.js) or wraps fetch. Paste the snippet as it is and change only its type:
<script type="smootify-load">
fetch("/cart.js")
.then((response) => response.json())
.then((cart) => console.log(cart.item_count));
</script>The browser does not run a script with this type. Smootify runs it right after smootify:loaded, as a normal script. To give it another type, such as a module, add data-type="module". Its other attributes are kept.
What these snippets can call is in Shopify AJAX API.
3. The smootify:loaded event
This is the 1.x way. It works only when the listener is registered before Smootify finishes loading, for example in the Head code:
<script>
document.addEventListener("smootify:loaded", () => {
window.Smootify.getCart().then((cart) => console.log(cart.totalQuantity));
});
</script>The event fires once per page. Code added later, by a tag manager for example, never sees it. In 2.0, use push.
The order at load
What happens when Smootify loads, and where each way of waiting runs:
event goes out1your code runs, by its way of waiting aboveuser_auth_changeThe first one goes out before your functions run.push functions1window.Smootify.pushThe listeners and filters they add get every step below.cart_updatedsmootify:loaded3smootify:loaded listeners2smootify-load scriptsThe listeners first, then the scripts.product_loadedOnce per product.Because of step 2, a push function that needs the session uses getCustomer(), or listens to user_auth_change with { replay: true }. More in Events.
Types
smootify.d.ts describes window.Smootify, the events with their payloads and the filters. Each release publishes it at https://cdn.smootify.io/assets/v2/<version>/smootify.d.ts.
- In a TypeScript project, add the file to
includeintsconfig.json. - In a plain script, in an editor such as VS Code, start the file with
// @ts-checkand/// <reference path="./smootify.d.ts" />.
With either setup, window.Smootify and document.addEventListener("smootify:…") get their types. The methods, the events and the filters are the API. The Smootify elements on the page are not: do not script against their internals.
Where people get stuck
Check these first
window.Smootifyis undefined, or has no methods. The script ran before Smootify loaded. Put the code in apushfunction.- A tag manager script never sees
smootify:loaded. The event fires once per page, before the tag manager adds the script. UsepushwithSmootify.on("loaded", fn, { replay: true }). - The options have no effect.
SmootifyUserOptionsis set after the loader script, or a second script replaces the first one. Set it once, before the loader. - A third-party snippet gets a 404 for
/cart.js. It ran before Smootify, so Webflow answered. Change its type tosmootify-load. - A listener misses the first
user_auth_change. It goes out before thepushfunctions run. Add{ replay: true }, or callgetCustomer().
Coming from 1.x
smootify:loaded and <script type="smootify-load"> work as in 1.x. window.Smootify.push is new in 2.0: use it for scripts that can run late, such as the ones a tag manager adds. The window.* hooks of 1.x are replaced by filters.