Switchboard DocsPolaris-native Shopify Functions

Switchboard Storefront SDK

window.Switchboard — one global, all three features.

The SDK is a thin theme app extension. It exposes helpers that wrap Shopify's /cart/*.js AJAX endpoints and Switchboard's signing-proxy endpoint, with a single in-flight queue so concurrent calls can't clobber each other.


Enabling it

The SDK loads via Shopify's theme app embed system. It does not auto-enable on install — the merchant has to flip the toggle in the theme editor.

  1. Storefront admin → Online Store → Themes → Customize (on the active theme).
  2. Click the puzzle-piece icon (left rail) → App embeds.
  3. Toggle Switchboard SDK to on. Save.

After save, <script defer src="...switchboard-sdk.js"> is injected on every storefront page (cart, product, collection, home — everywhere). The script self-initializes and creates window.Switchboard.

Verify it loaded in DevTools console on any storefront page:

typeof window.Switchboard;  // → "object"

If it's "undefined", the embed isn't enabled.


Configuration block (optional)

In the same theme-editor App embeds panel, the Switchboard SDK embed has one setting: Debug logging. Flip it on while integrating to see SDK activity in the console (prefixed [Switchboard]). Off in production.


Public API

All methods return Promises. All write operations are serialized through a single in-flight queue, so you can fire setPickup + setCartAttribute + signAndSetPrice in parallel without race conditions on the cart.

Pickup Reorder

Switchboard.setPickup(value)

Writes the pickup hint. Accepts:

  • A string (e.g. "Quebec") → pin that one location
  • An array of strings (e.g. ["Quebec","Winnipeg"]) → sort to the top in order
  • null, "", or [] → clear the hint

Returns Promise<cart> (the updated cart object from /cart/update.js).

Switchboard.clearPickup()

Convenience for setPickup(null).

Switchboard.readPickup()

Returns Promise<string | string[] | null> — whatever's currently in the _switchboard_pickup cart attribute, normalized.

See /docs/pickup-reorder for the matching rule modes + match-style options.


Cart Validation

Switchboard.setCartAttribute(key, value)

Sets ONE attribute inside the _switchboard rollup blob. key is the attribute name your validation rules reference; value is stringified.

Returns Promise<cart>.

Switchboard.setBatch({ key1: value1, key2: value2, ... })

Sets multiple attributes in ONE cart write. Always prefer this over multiple setCartAttribute calls when you have several attributes to set at once.

Switchboard.clear(key)

Removes one attribute from the rollup blob.

Switchboard.read(key)

Returns Promise<string | undefined> — the current value, or undefined if not set.

Declarative mode

Any DOM element with data-switchboard-attr="key" auto-syncs its value (or checked state, for checkboxes / radios) into the cart attribute on every change event. No JS required:

<select data-switchboard-attr="loyalty_tier">
  <option value="basic">Basic</option>
  <option value="vip">VIP</option>
</select>

<input type="checkbox" data-switchboard-attr="age_confirmed" value="true">

<input type="radio" name="shipping_preference"
       data-switchboard-attr="shipping_preference" value="express">
<input type="radio" name="shipping_preference"
       data-switchboard-attr="shipping_preference" value="standard">

See /docs/validation for the rule-tree shape.


Cart Transform

Switchboard.signAndSetPrice(lineItemKey, priceCents, options?)

Mints a signed token + applies it to a cart line in one round-trip. lineItemKey is cart.items[i].key from /cart.js. priceCents is a non-negative integer.

Optional options.ruleId — required ONLY when the shop has more than one active Cart Transform rule. With one active rule, the backend auto-selects.

Returns Promise<cart>.

Switchboard.setLineItemProperty(lineItemKey, propertyKey, value)

Sets one property on a line without minting a new token. Use this to copy a pre-minted token between lines, or to clear _switchboard_price (pass an empty string).

Switchboard.addLineItemWithProperties(variantId, qty, properties)

Adds a new line item with the properties already attached. Useful for "add the hidden shipping protection product with the signed-price token already on it" flows — one round-trip instead of two.

See /docs/cart-transform for the full signing flow + safety rails.


Error handling

Every method that hits the network can reject. Common cases:

Rejection Why
Switchboard: cart update failed 404 The endpoint URL is wrong (Shopify changed /cart/update.js? Unlikely.)
Switchboard: cart/change failed 422 Line key doesn't exist in the cart (it was removed since you read /cart.js)
Switchboard: cart/add failed 422 Variant ID is invalid or out of stock
Switchboard: sign-price failed 400/409 Cart Transform: rule misconfigured, or the rule_id you passed isn't active
Switchboard.signAndSetPrice: line ... not in cart The line key was already removed when the function ran

Recommendation: wrap SDK calls in try/catch (or .catch) and gracefully degrade. The function side never blocks checkout, so worst case is your discount didn't apply — surface that to the user if material.

try {
  await Switchboard.signAndSetPrice(line.key, 500);
} catch (e) {
  console.warn('Pricing override failed, customer will see variant price:', e);
  // Optional: show a "discount couldn't be applied" toast
}

Concurrency

All write operations go through a single Promise chain so they execute serially. You can fire many calls in parallel from event handlers and they'll resolve in submission order:

// Safe — both queued, executed back-to-back
Switchboard.setCartAttribute('foo', 'bar');
Switchboard.setCartAttribute('baz', 'qux');

// More efficient — single cart write
Switchboard.setBatch({ foo: 'bar', baz: 'qux' });

The cart-line property merge logic (setLineItemProperty / signAndSetPrice) reads the current line's properties via /cart.js, merges, then writes the combined set via /cart/change.js. Shopify's /cart/change.js REPLACES properties wholesale, so this read-merge-write is mandatory.


Debugging

Flip Debug logging on in the theme-editor embed settings. The SDK logs every operation with the [Switchboard] prefix:

[Switchboard] setPickup (string) Quebec
[Switchboard] write attribute blob {country: "CA", loyalty_tier: "vip"}
[Switchboard] mergeLineProperties shopify-pickup-points-12345 ["_switchboard_price"]

Inspect cart attributes / properties at any time:

fetch('/cart.js').then(r => r.json()).then(c => {
  console.log('attrs:', c.attributes);
  console.log('lines:', c.items.map(i => ({ key: i.key, price: i.price, props: i.properties })));
});

For a full reviewer-grade test plan, see SHOPIFY_QA.md in the repo.


Versioning / changes

The SDK lives in extensions/switchboard-storefront/assets/switchboard-sdk.js. It's deployed to merchants' themes via the Shopify CLI on every shopify app deploy. The merchant gets the latest version the next time their theme renders a page.

Breaking changes will be communicated via the app's release notes in the App Store listing.

If you need a stable API, lock to a major version of @shopify/shopify-app-remix in your own deps (see package.json) — Switchboard's SDK API tracks Shopify's underlying surfaces.