Skip to content

JavaScript API

Plan: every plan, including Free.

On every storefront page with the Cove Wishlist app embed on, window.CoveWishlist works the shopper’s wishlist from your own theme code. It uses the same calls as Cove’s hearts, for the same shopper (signed in or guest), and every heart, button and counter on the page updates with it. There is nothing to install.

Cove’s script loads deferred, so window.CoveWishlist exists once it has run. Code that may run earlier can wait for the cove:ready event on document, which fires once when the script has set up:

function onCove(callback) {
if (window.CoveWishlist) callback(window.CoveWishlist);
else
document.addEventListener(
'cove:ready',
() => callback(window.CoveWishlist),
{ once: true }
);
}
onCove(async cove => {
console.log('Saved items:', await cove.count());
});

With the app embed off, or while the app is paused on your store, the API isn’t defined and cove:ready never fires.

Every method returns a promise. Product and variant IDs are numeric Shopify IDs, as strings or numbers.

Method Resolves with What it does
get() Item[] The saved items.
count() number Saved products and variants. An item in two lists counts once.
has(productId, variantId?) boolean Whether it’s saved. Without a variant: the product is saved at all, in any variant. With one: that variant, or the product saved without a variant (which covers all of its variants).
add(productId, variantId?) Item[] Saves it to the shopper’s default list. Resolves with the items after the save.
remove(productId, variantId?) Item[] Unsaves it from every list, together with every save that makes has() true for it: without a variant, the product in any variant; with one, that variant and a product-level save. Resolves with the items after the removal.
toggle(productId, variantId?) Item[] Adds it if it isn’t saved, removes it if it is (as has() decides).

Call toggle on the object (window.CoveWishlist.toggle(…)); it reads has from it.

Each item in the array is:

{
"productId": "8123456789",
"variantId": "45123456789",
"listIds": ["clx0examplelistid0000"]
}

variantId is null for a product saved without a variant. listIds names the shopper’s lists that hold it.

get(), count() and has() wait for the shopper’s wishlist to load the first time, then answer from memory. For a shopper who has never saved anything (no account wishlist, no guest list in this browser) there is nothing to load, so they answer at once without a request.

add() and toggle() save through the same storefront endpoint as the hearts, so a new save counts as one wishlist action, like any storefront save, and the store’s settings apply: if guest wishlists are off, a guest’s save is refused with sign_in_required. Re-saving something the shopper removed in the last 10 minutes brings the same save back and uses no action. See wishlist actions and guest wishlists.

The API shows nothing: no toast, no Undo, no sign-in prompt. That’s your UI’s job. The hearts and buttons on the page still update to the new saved state, and cove:change fires (see events).

A failed call rejects with an Error whose code is the storefront’s error code:

code When
invalid_request A missing or non-numeric product ID. Refused at once, without a request.
sign_in_required The store turned guest wishlists off and the shopper isn’t signed in.
quota_reached The store has used its monthly wishlist actions.
list_full The list already holds 500 items.
rate_limited Too many saves too quickly from this shopper.
paused Cove’s storefront features are paused on the store.

A network failure rejects with the browser’s own error, which has no code. Treat any other code as a generic failure.

A heart in your own theme markup:

<button
type="button"
id="my-heart"
data-product-id="8123456789"
aria-pressed="false"
>
Save
</button>
const button = document.querySelector('#my-heart');
async function paint() {
const saved = await window.CoveWishlist.has(button.dataset.productId);
button.setAttribute('aria-pressed', String(saved));
button.textContent = saved ? 'Saved' : 'Save';
}
button.addEventListener('click', async () => {
try {
await window.CoveWishlist.toggle(button.dataset.productId);
} catch (error) {
if (error.code === 'sign_in_required') location.href = '/account/login';
else button.textContent = 'Try again';
}
});
// Repaint whenever the wishlist changes, from this button or any other.
document.addEventListener('cove:change', paint);
paint();

Save one variant:

await window.CoveWishlist.add('8123456789', '45123456789');

List the saved product IDs:

const items = await window.CoveWishlist.get();
const productIds = [...new Set(items.map(item => item.productId))];

Set text with textContent, as above: product IDs are safe, but anything a shopper typed (a list name, a note) must never go into innerHTML.

  • Events: cove:change after every save and removal.
  • Custom elements: ready-made buttons, counts and links, no code.
  • REST API: the same wishlists from your server.