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.
When it’s ready
Section titled “When it’s ready”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.
Methods
Section titled “Methods”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.
Reads cost nothing for new shoppers
Section titled “Reads cost nothing for new shoppers”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.
Saves and the quota
Section titled “Saves and the quota”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.
No toast
Section titled “No toast”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).
Errors
Section titled “Errors”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.
Examples
Section titled “Examples”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.
Related
Section titled “Related”- Events:
cove:changeafter every save and removal. - Custom elements: ready-made buttons, counts and links, no code.
- REST API: the same wishlists from your server.