Share a Wish

Add to Wishlist Save Button

One <script> tag and a public key turn any product page into a save-to-wishlist entry point. The button opens a hosted dialog on shareawish.shop where the shopper signs in and picks a list — nothing runs on your servers.

1. Drop-in script

Load the SDK from its canonical URL and put your key on the script tag. Then add data-shareawish to any button.

<script src="https://shareawish.shop/sdk/v1/widget.js" data-shareawish-key="pk_test_XXXXXXXXXXXXXXXX" defer></script>

<button
  data-shareawish
  data-url="https://shop.example.com/products/42"
  data-id="42"
  data-title="Blue Sneaker"
  data-description="Lightweight everyday sneaker"
  data-image-url="https://shop.example.com/img/42.jpg"
  data-price="7990"
  data-currency="EUR"
  data-market="de-DE">
  Save to wishlist
</button>

Canonical SDK URL: https://shareawish.shop/sdk/v1/widget.js. v1 is a major-version alias that receives backwards-compatible updates. The IIFE build exposes window.ShareAWish and auto-binds every [data-shareawish] element on load.

Legacy URLs (/sdk/save-sdk.js, cdn.shareawish.shop/sdk/v1/save-sdk.js, cdn.shareawish.com/widget.js) are deprecated and redirect to the canonical file. The legacy data-saw-key attribute is still accepted, but use data-shareawish-key.

Optional attributes on the script tag (or on <html>): data-shareawish-environment="test|live", data-shareawish-locale="de-DE", data-shareawish-allowed-domains="shop.example.com,*.example.com".

2. Button attributes

AttributeRequiredMeaning
data-urlyesCanonical product URL. Tracking parameters are stripped server-side; the product is upserted by this URL.
data-idnoYour product id.
data-offer-idnoOffer id (integer) if you manage offers separately.
data-titlenoProduct title shown in the dialog and the wishlist.
data-descriptionnoShort description.
data-image-urlnoAbsolute image URL; the image is copied to Share a Wish storage on save.
data-pricenoPrice in minor units (cents), integer.
data-currencynoISO 4217 code, e.g. EUR.
data-marketnoMarket / locale code such as de-DE (default de-DE).
data-metadatanoJSON string with variant / quantity data that is passed through to checkout (basket).

3. Programmatic init and open()

If you render buttons yourself, initialise once with your public key and open the dialog from a click handler. open() must run inside a user gesture, otherwise the browser blocks the popup.

<script src="https://shareawish.shop/sdk/v1/widget.js"></script>
<script>
  ShareAWish.init({ key: 'pk_test_XXXXXXXXXXXXXXXX', locale: 'de-DE' });   // legacy option name: publicKey

  document.querySelector('#save').addEventListener('click', function () {
    var handle = ShareAWish.open({
      productUrl: 'https://shop.example.com/products/43',
      productId: '43',
      title: 'Red Sneaker',
      price: 8990,
      currency: 'EUR',
      imageUrl: 'https://shop.example.com/img/43.jpg',
      metadata: { variantId: '987', quantity: 1 }
    });
    handle.ready.catch(function (err) { console.warn('init failed', err.code); });
  });
</script>

What happens: the SDK calls POST /widget/init with your key and window.location.origin, receives a widget token (10 minutes, bound to the origin) and navigates the popup to the hosted save page https://shareawish.shop/save. The hosted page performs the actual POST /widget/save after the shopper signed in. See the Wishlist API for the underlying calls.

init() options: key (or legacy publicKey), environment ('test'|'live', inferred from the key prefix), locale, allowedDomains, apiBase, widgetUrl. mount(el, options) binds a click handler and returns an unmount function; createInstance(options) gives you an independent instance if you use several keys on one page.

4. Events

EventPayloadWhen
savedItem payload sent by the hosted pageThe shopper saved the product to a list.
closeThe popup was closed.
open{ token }The popup navigated to the hosted page with a valid token.
errorWidgetError with code, trial_expiredInit failed (e.g. origin_not_allowed, subscription_required) or the popup was blocked (popup_blocked).
ShareAWish.on('saved', function (item) { console.log('saved', item); });
ShareAWish.on('close', function () { console.log('popup closed'); });
ShareAWish.on('error', function (err) { console.warn(err.code, err.trial_expired); });

on() returns an unsubscribe function; off(event, cb) is also available. Server-side error codes from /widget/init: invalid_input, unknown_key, origin_not_allowed, allowlist_required, subscription_required. Client-side: popup_blocked, init_no_token, key_required, not_initialised, mount_target_not_found. Full list on the error codes page.

5. React (npm package)

The same runtime ships as a typed ESM/CJS module: npm install @shareawish/widget. Exports: init, mount, open, on, off, createInstance, autoInit, VERSION, CDN_URL.

import { useEffect } from 'react';
import { init, mount, on } from '@shareawish/widget';

export function SaveButton({ product }) {
  useEffect(() => { init({ key: import.meta.env.VITE_SHAREAWISH_KEY }); }, []);
  useEffect(() => on('saved', (item) => console.log('saved', item)), []);

  return (
    <button
      type="button"
      ref={(el) => {
        if (!el) return;
        mount(el, {
          productUrl: product.url,
          productId: product.id,
          title: product.title,
          price: product.price,        // minor units
          currency: product.currency,
          imageUrl: product.imageUrl,
        });
      }}
    >
      Save to wishlist
    </button>
  );
}

If you prefer not to use a ref callback, call open({...}) inside onClick instead of mount. Product options accept productUrl (alias url), productId (alias id), offerId, title, description, imageUrl, price, currency, locale (alias marketCode) and metadata. Vue and plain TypeScript examples are in the package README.

6. Shopify

Shopify merchants do not need a script tag: the Share a Wish Shopify app ships a theme app extension with a Share a Wish Button block for product pages. For a custom Liquid theme you can still use the drop-in snippet with Liquid values:

<button data-shareawish
  data-url="{{ shop.url }}{{ product.url }}"
  data-title="{{ product.title | escape }}"
  data-price="{{ product.price }}"
  data-currency="{{ shop.currency }}"
  data-image-url="{{ product.featured_image | image_url: width: 800 }}"
  data-market="{{ request.locale.iso_code }}-{{ localization.country.iso_code | default: 'US' }}">
  Save to wishlist
</button>

FAQ

Do I need a backend to add the Save Button?

No. The drop-in script calls POST /widget/init with your public key from the browser, receives a 10-minute widget token and opens the hosted save dialog at https://shareawish.shop/save. Public keys are safe to ship in client-side code.

Which script URL should I use?

https://shareawish.shop/sdk/v1/widget.js. The v1 alias receives backwards-compatible updates. Legacy URLs are deprecated and redirect to the canonical file.

Can I test on localhost?

Yes. Create a key with environment Test (pk_test_…). localhost is always allowed and needs no domain allow-list. Test keys hit the same live API, so saves land in the customer's real wishlist.

What is the price format?

Pass the price in minor units (cents) as an integer, e.g. data-price="7990" for 79.90, together with data-currency="EUR".