2.0 Beta

Smootify 2.0 is in public beta. Your 1.x store keeps working. Move when you want.

What changed

Shopify AJAX API

The Shopify theme endpoints Smootify answers on a Webflow site (/cart.js, /cart/add.js, /products/{handle}.js and more), what each one supports, how to start app code after Smootify, and how to turn the emulation off.

v2.0 beta
Open .md
On this page
  1. How it works
  2. The endpoints
  3. Start the app’s code after Smootify
  4. App proxy paths
  5. Turn it off
  6. Where people get stuck
  7. Coming from 1.x

Apps written for Shopify themes call the theme’s AJAX endpoints, such as /cart.js or /cart/add.js. A Webflow site has no Shopify theme, so Smootify answers these calls on the page itself, from Shopify’s Storefront API, with the same response shape a theme gets. The cart they change is the page’s cart. This page lists what is answered and how to make an app’s code work with it.

How it works

  • What is intercepted. fetch and XMLHttpRequest calls to the site’s own address, and to the store’s .myshopify.com address, whose path is one of the endpoints below. Every other request goes out unchanged.
  • Same cart as the page. A change through /cart/add.js, /cart/update.js (or their .json forms), /cart/change.js or /cart/clear.js goes through Smootify’s cart: the page’s cart updates as if the visitor had used it, and smootify:cart_updated goes out (with smootify:added_to_cart for an addition).
  • Filters apply. Lines added with /cart/add.js go through the add_to_cart_lines filters, with no element in the context.
  • The request address. As on Shopify, each answer carries the address of the request: response.url for fetch (its clones too), responseURL for XMLHttpRequest. Some app snippets tell an addition from a read by it.
  • window.Shopify. Smootify also sets Shopify.shop, Shopify.locale, Shopify.country, Shopify.routes.root and Shopify.theme ("Smootify"), which theme scripts read.
  • Shopify.actions.updateCart. The cart action of Shopify’s storefront web components, such as the Shopify Inbox chat. Smootify defines window.Shopify.actions.updateCart(payload) unless the page already has one: lines in the Storefront API shape (merchandiseId adds a line, the id of a /cart.json item key sets its quantity, 0 removes it), discountCodes replaces the codes, note sets the note. It answers { cart, userErrors }, with the cart in the Storefront API shape and line ids it accepts back. Smootify also writes Shopify’s cart cookie, which these components read.

The endpoints

EndpointStatusNotes
GET /cart.js, /cart.jsonansweredthe page’s cart
POST /cart/add.js, /cart/add, /cart/add.jsonansweredform data or JSON, items[], properties, selling_plan; sections ignored
POST /cart/update.js, /cart/update.jsonansweredupdates by id, key or position, note, attributes
POST /cart/change.jsansweredid or line, quantity, properties
POST /cart/clear.jsanswered
GET /products/{handle}.js, .jsonansweredfrom Smootify’s cache when it has the product
GET /products.jsonfirst pagelimit up to 250 (default 30); page above 1 answers an empty list
GET /collections/{handle}/products.jsonfirst pagelimit up to 250 (default 50)
GET /recommendations/products.jsonansweredproduct_id, limit up to 10, intent related (default) or complementary
GET /variants/{id}.jsonanswered{ product_variant }, as the Online Store answers
GET /search/suggest.jsonansweredq, resources[type], resources[limit] up to 10: products, collections, pages, articles, queries
POST /localizationansweredcountry_code, language_code change the market; no redirect
GET /cart/shipping_rates.json, POST /cart/prepare_shipping_rates.jsonnot supported422, with Shopify’s error shape: shipping rates exist only at checkout
/apps/*, /a/*, /community/*, /tools/*not answeredsee below

The same list is in the Reference: AJAX API.

products.json and collections/{handle}/products.json answer only their first page, because the Storefront API pages through results in another way.

Start the app’s code after Smootify

Smootify loads as an asynchronous module. A plain script at the end of the page runs before it: its /cart.js calls reach Webflow, which answers 404, and a snippet that wraps window.fetch there never sees /cart/add.js. Two ways to wait:

  • Change the snippet’s type to smootify-load. Smootify runs it right after smootify:loaded. Add data-type="module" if it was a module; its other attributes are kept.
  • Start it from a smootify:loaded listener registered in the Head code, before Smootify finishes loading. The event fires once per page: code added later, by a tag manager for example, does not see it.
<script type="smootify-load">
  fetch("/cart/add.js", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ items: [{ id: 44012345678901, quantity: 1 }] }),
  }).then((response) => response.json());
</script>

More in Run your scripts with Smootify. For designers adding an app’s snippet, see Shopify apps on a Webflow site.

App proxy paths

Some Shopify apps call their own server through the store, on paths such as /apps/…, /a/…, /community/… or /tools/…. These app proxies need Shopify’s Online Store. Smootify does not answer them: the calls reach the network as they are, and a Webflow site answers 404. On a .webflow.io address, the debugger names the calls.

Two exceptions keep working: Shopify Inbox’s /apps/ba-rev gets an empty answer, and the consent request to /api/unstable/graphql.json goes to the store.

An app that needs its proxy does not work on a Webflow site.

Turn it off

When another script on the page answers these endpoints, turn Smootify’s emulation off in the options:

<script>
  window.SmootifyUserOptions = { ...(window.SmootifyUserOptions || {}), ajaxApi: false };
</script>

Set it before the Smootify loader script.

Where people get stuck

Check these first

  • An app gets a 404 for /cart.js. Its code ran before Smootify. Change its script type to smootify-load.
  • An app that wraps fetch never sees additions. It wrapped fetch before Smootify did. Start it with smootify-load.
  • An app calls /apps/… and fails. App proxy paths need Shopify’s Online Store and are not answered.
  • A product list from products.json stops after the first page. Only the first page is answered. Raise limit, up to 250.
  • Shipping rates never load. Shipping rates exist only at checkout: the endpoints answer 422.

Coming from 1.x

1.x answered cart.js, cart/add.js, cart/update.js and products/{handle}.js. 2.0 adds every other endpoint in the table, and Shopify.actions.updateCart. App proxy paths went through a Smootify server route in 1.x; that route is switched off for good, so these calls already failed there.

    ↑ ↓ to moveEnter to openEsc to close