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
| Attribute | Required | Meaning |
|---|---|---|
data-url | yes | Canonical product URL. Tracking parameters are stripped server-side; the product is upserted by this URL. |
data-id | no | Your product id. |
data-offer-id | no | Offer id (integer) if you manage offers separately. |
data-title | no | Product title shown in the dialog and the wishlist. |
data-description | no | Short description. |
data-image-url | no | Absolute image URL; the image is copied to Share a Wish storage on save. |
data-price | no | Price in minor units (cents), integer. |
data-currency | no | ISO 4217 code, e.g. EUR. |
data-market | no | Market / locale code such as de-DE (default de-DE). |
data-metadata | no | JSON 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
| Event | Payload | When |
|---|---|---|
saved | Item payload sent by the hosted page | The shopper saved the product to a list. |
close | — | The popup was closed. |
open | { token } | The popup navigated to the hosted page with a valid token. |
error | WidgetError with code, trial_expired | Init 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".