API ReferenceGuides
Log In
API Reference

Custom Wishlist Experience

Build custom wishlist experiences using the Swym JS SDK without any default UI.

SDK-Only Mode

Build a fully custom wishlist experience using the Swym JS SDK — no default Swym UI, total creative control.

SDK-only mode loads the Swym JavaScript SDK (window._swat) on your storefront without rendering any default UI (buttons, drawer, header icon, notifications). You get full API access and build your own UI from scratch.

When to Use SDK-Only Mode

  • Agencies building custom storefronts for Shopify Plus merchants
  • Headless / composable commerce builds (Hydrogen, Next.js, custom frontends)
  • Merchants who want complete design control over their wishlist experience
  • Developers integrating wishlist data into custom themes or apps

What You Get

Available in SDK-Only ModeNOT available (you build these)
window._swat — full SDK instanceWishlist buttons on product pages
All JavaScript APIs (add, remove, fetch, lists)Wishlist page UI
Event system for real-time updatesCollection page buttons
Back-in-stock subscription APIsHeader icon with count badge
Multi-wishlist supportConsent popup (if GDPR-required)
Shared wishlist APIsToast notifications

Prerequisites

  1. Swym Wishlist Plus app installed on your Shopify store
  2. In your Shopify theme editor (Online Store > Customize > App Embeds):
    • Wishlist App Embed must be enabled (this loads the SDK)
    • Storefront UI Elements must be present with "Show UI" unchecked

Verify SDK-Only Mode

Open your storefront in a browser and run these in the console:

// Run these in your browser console (verification only — not for production code)

window._SwymSDKOnlyMode; // true — SDK-only mode is active
typeof window._swat;      // "object" — SDK is loaded

If _swat is undefined, the SDK may still be loading. Always use the SwymCallbacks pattern instead of accessing _swat directly.


The SwymCallbacks Pattern

This is the canonical entry point for all custom code. Never access window._swat directly — always use SwymCallbacks to ensure the SDK is ready. All swat API calls must happen inside this callback.

window.SwymCallbacks = window.SwymCallbacks || [];
window.SwymCallbacks.push(function(swat) {
  // swat === window._swat — fully initialized
  // ALL API calls MUST go inside this callback
});

Rule: Every code example in this guide wraps all swat calls inside SwymCallbacks. Your custom code must do the same.


Product Data Shape

Every wishlist item uses this data structure:

FieldTypeDescriptionShopify Liquid Source
epiNumberVariant ID{{ variant.id }}
empiNumberProduct ID{{ product.id }}
duStringProduct URL (absolute){{ shop.url }}{{ product.url }}
dtStringProduct title{{ product.title }}
iuStringProduct image URL{{ product.featured_image | image_url }}
prNumberPrice (cents){{ variant.price }}
stkNumberStock (1 = in stock, 0 = OOS){% if variant.available %}1{% else %}0{% endif %}
qtyNumberQuantity (optional, defaults to 1)N/A (set in code)
noteStringCustom note (optional)N/A (set in code)
cpropsObjectCustom properties — arbitrary key-value pairs (optional)N/A (set in code)
sourceStringTracking source (optional). Valid: pdp, collections-grid, quick-view, featured-grid, recommendations, search-results, plpN/A (set in code)

Extracting Product Data in Liquid

<div id="swym-product-data"
  data-product-id="{{ product.id }}"
  data-variant-id="{{ product.selected_or_first_available_variant.id }}"
  data-product-url="{{ shop.url }}{{ product.url }}"
  data-product-title="{{ product.title | escape }}"
  data-product-image="{{ product.featured_image | image_url: width: 400 }}"
  data-product-price="{{ product.selected_or_first_available_variant.price }}"
  style="display:none;">
</div>

SwymPageData: On product pages, Swym's SDK automatically sets window.SwymPageData with the current product data. You can use this instead of extracting from Liquid data attributes.

SwymProductVariants: window.SwymProductVariants is a lookup by variant ID — use it to get variant-specific data when the user changes variants.

GDPR Note: In SDK-only mode, the Swym consent popup does not render. If your store requires marketing consent (EU, UK, etc.), implement your own consent gate before making SDK API calls.


Theme Architecture Detection

Before writing any code, determine your theme's architecture — this affects how you inject the wishlist button.

Read your product section file (found via templates/product.json → section type):

ThemeSection typeFile
Dawnmain-productsections/main-product.liquid
Ritualproduct-informationsections/product-information.liquid
Prestigemain-product-detailsections/main-product-detail.liquid

Then check if it uses block loops:

{% for block in section.blocks %}
  • Block-based themes (Ritual, Prestige, Impact, Symmetry): Product form elements are rendered inside block loops. You cannot drop a <button> in the Liquid — it will render outside the product grid. Use JavaScript-based injection instead.
  • Template-based themes (Dawn, Craft, Colorblock): Product info is rendered inline. You can add Liquid markup directly near the buy buttons.

Rule: Always read your product section file before choosing an approach. The Wishlist Button guide covers both approaches.


Identity & Guest-to-Login Sync

The SDK automatically handles guest-to-logged-in user wishlist sync. No custom code is needed for Shopify Liquid themes.

How it works

  1. Guest visits — SDK assigns a unique device ID (RegID) via cookie and tracks their wishlist
  2. Guest logs in — Swym's Liquid snippet (loaded by the App Embed) reads Shopify's {{ customer }} object and sets window.swymCustomerId = "{{ customer.id }}". This is Shopify's standard Liquid customer object — it's only available when a customer is logged in.
  3. SDK detects the login — on init, the SDK reads window.swymCustomerId and calls the backend sync endpoint
  4. Backend merges — guest's wishlist items are merged into the customer's account
  5. SDK updates — local identity is refreshed, customerInfoRefreshed event fires

Checking login status in your code

Use the SDK's built-in method — don't check window.swymCustomerId directly:

window.SwymCallbacks = window.SwymCallbacks || [];
window.SwymCallbacks.push(function(swat) {
  var isLoggedIn = swat.platform.isLoggedIn();
  // Use this for login nudges, gated features, etc.
});

How it works under the hood: Swym's Liquid snippet contains window.swymCustomerId = {% if customer %}"{{ customer.id }}"{% else %}null{% endif %}. The customer object is Shopify's built-in Liquid variable — it's only truthy when a customer is logged in. The SDK reads this on initialization. swat.platform.isLoggedIn() is the canonical way to check this state.

This runs on every page load, so it also handles:

  • Customer switching (different account logs in) — clears device state, re-syncs
  • Logout — clears identity, re-registers as guest
  • Email detection — if a guest enters their email in a third-party form (Klaviyo, Privy, etc.), the SDK detects it and links their wishlist to that email

Listening for identity changes

window.SwymCallbacks = window.SwymCallbacks || [];
window.SwymCallbacks.push(function(swat) {
  if (swat.evtLayer) {
    swat.evtLayer.addEventListener('sw:customerInfoRefreshed', function() {
      // Identity synced — refresh your wishlist UI
      // e.g., re-fetch wishlisted items, update count badge
    });
  }
});

Headless builds — manual sync required

If you're not using Shopify Liquid (Hydrogen, Next.js, custom frontend), the theme won't set window.swymCustomerId for you. You must do it manually:

// Set this BEFORE the SDK initializes, or call validateUserLogin after
window.swymCustomerId = YOUR_SHOPIFY_CUSTOMER_ID;

Or, if the SDK is already loaded, trigger the sync explicitly:

window.SwymCallbacks = window.SwymCallbacks || [];
window.SwymCallbacks.push(function(swat) {
  // Call this when your app detects a login
  swat.validateUserLogin('shopify', YOUR_SHOPIFY_CUSTOMER_ID, function() {
    // Sync complete — guest wishlist merged into customer account
  });
});

Important: For headless builds, ensure window.swymCustomerId is set on every page load when the customer is logged in — the SDK checks it each time to detect login/logout transitions.


Guides

Build each component independently — pick what you need: