The default Shopify “Buy It Now” button dynamically displays branded or unbranded options based on certain conditions. However, I require only the unbranded version, which isn’t possible with the default implementation.
So, I’m planning to create a custom “Buy Now” button using Liquid. The issue I’m facing is that when a cart already contains items (added via “Add to Cart”) and the user clicks this custom “Buy Now” button, the existing cart gets cleared.
How can I implement the correct “Buy Now” behavior without clearing the existing cart?
Moeed
April 30, 2026, 7:03am
2
Hey @Anish2001
Can you share the code of the custom “Buy Now” button that you have created? It’ll probably need some modifications to get it work right.
Best,
Moeed
<div class="custom-buy-now-wrapper">
<button
type="button"
id="CustomBuyNowButton"
class="button custom-buy-now-button"
>
Buy now
</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const buyNowButton = document.getElementById('CustomBuyNowButton');
if (!buyNowButton) return;
const productForm = document.querySelector('form[action^="/cart/add"]');
if (!productForm) {
console.warn('Custom Buy Now: No product form found on this page.');
return;
}
buyNowButton.addEventListener('click', async function () {
const formData = new FormData(productForm);
const variantId = formData.get('id');
if (!variantId) {
alert('Please select a variant before continuing.');
return;
}
let quantity = formData.get('quantity') || 1;
quantity = parseInt(quantity, 10) || 1;
const rootUrl =
window.Shopify && window.Shopify.routes && window.Shopify.routes.root ? window.Shopify.routes.root : '/';
async function clearCart() {
const response = await fetch(rootUrl + 'cart/clear.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
if (!response.ok) {
throw new Error('Failed to clear cart');
}
}
async function addLineItem() {
const payload = {
id: variantId,
quantity: quantity,
};
const response = await fetch(rootUrl + 'cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorData = await response.json().catch(() => null);
console.error('Add to cart error:', errorData || response.statusText);
throw new Error('Failed to add item to cart');
}
return response.json();
}
buyNowButton.disabled = true;
buyNowButton.classList.add('is-loading');
try {
// 1) Clear existing cart so ONLY this product is in checkout
await clearCart();
// 2) Add the selected variant
await addLineItem();
// 3) Redirect to checkout
window.location.href = rootUrl + 'checkout';
} catch (error) {
console.error('Custom Buy Now error:', error);
alert('Sorry, something went wrong starting the checkout. Please try again.');
} finally {
buyNowButton.disabled = false;
buyNowButton.classList.remove('is-loading');
}
});
});
</script>
try using this code in your product template liquid file
<button id="buy-now">Buy Now</button>
<script>
document.getElementById('buy-now').addEventListener('click', function() {
fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: {{ product.selected_or_first_available_variant.id }},
quantity: 1
})
})
.then(() => window.location.href = '/checkout');
});
</script>
Moeed
April 30, 2026, 7:41am
6
@Anish2001 Update your code to this code below.
<div class="custom-buy-now-wrapper">
<button
type="button"
id="CustomBuyNowButton"
class="button custom-buy-now-button"
>
Buy now
</button>
</div>
<script>
document.getElementById('CustomBuyNowButton').addEventListener('click', function () {
const productForm = document.querySelector('form[action^="/cart/add"]');
if (!productForm) return;
const formData = new FormData(productForm);
const variantId = formData.get('id');
if (!variantId) {
alert('Please select a variant before continuing.');
return;
}
const quantity = parseInt(formData.get('quantity'), 10) || 1;
const rootUrl = window.Shopify?.routes?.root || '/';
fetch(rootUrl + 'cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: variantId, quantity: quantity })
})
.then(function () {
window.location.href = rootUrl + 'checkout';
})
.catch(function () {
alert('Sorry, something went wrong. Please try again.');
});
});
</script>
This should work exactly how you require.
Cheers,
Moeed
@mastroke I have tried the code you have provided, but it adds the “buy now” product along with the previous cart and in the checkout it shows both products, one from the buy now and the other from the previous cart.
Your code clears the cart, adds the item, then goes straight to checkout. Standard buy it now button. I don’t see an issue there, except for maybe some race conditions and any properties it has don’t get carried over.
This is the way a buy it now button works… if you don’t want to clear the cart why did you put clearCart function in?
In the ideal case, if we have a previous cart with 3 items and I try buy now with a entirely different product and once placing the order using the buy now and came back to cart, it will show the previous 3 items in the cart. It doesnt clears and the cart persists like in the flipcart.
Here in my code i was clearing the previous cart because, if I was not clearing the previous cart, the buy now product is added to the previous cart and the entire cart is now moved to checkout. But actually using buy now, only that particular product need to be moved to checkout. Thats why im clearing.
@Moeed using the code you provided, if I was having a non empty previous cart, the buy now product is also getting added to the same cart and moved to checkout.
@Maximus3 Please check this
I don’t think any of us are understanding what exactly is wrong and what exactly you want to happen…
You want product added to cart with the existing cart items.
You want to clear existing cart, add item to cart.
Those are the only 2 options… after that, then tell us the action you want.
Do nothing.
Open cart drawer.
Go to cart page.
Go straight to checkout.
No. Anish wants “buy now” button to go to checkout with current variant only and keep whatever is in cart there for future use. Like, say Amazon does.
You can try using cart permalinks for your “buy now” button.
Or, in your JS code you can save current cart cookie and restore it after checkout.
Core behaviour of Buy now
Clicking it skips the cart page and goes directly to checkout
Creates a completely separate, independent checkout session
Does not add the item to the existing cart
Does not clear, modify, or interfere with the existing cart in any way
The existing cart remains exactly as it was before the click
But in shopify I was not able to achieve this, when I try it add the buy now product to the previous cart, thats why Im clearing the previous cart. Without clearing that how to achieve this.
Yeah, this is what exactly I mean. Using session storage/local storage we can store the previous cart and later ad it back. Other than that is there any method. I will check the cart permalinks.
<div class="custom-buy-now-wrapper">
<button
type="button"
id="CustomBuyNowButton"
class="button custom-buy-now-button"
>
Buy now
</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const buyNowButton = document.getElementById('CustomBuyNowButton');
if (!buyNowButton) return;
const productForm = document.querySelector('form[action^="/cart/add"]');
if (!productForm) {
console.warn('Custom Buy Now: No product form found on this page.');
return;
}
buyNowButton.addEventListener('click', function () {
const formData = new FormData(productForm);
const variantId = formData.get('id');
if (!variantId) {
alert('Please select a variant before continuing.');
return;
}
const quantity = parseInt(formData.get('quantity'), 10) || 1;
const rootUrl = window.Shopify?.routes?.root ?? '/';
// Build line item properties if present
const params = new URLSearchParams();
params.set('quantity', quantity);
for (const [key, value] of formData.entries()) {
if (key.startsWith('properties[')) {
params.set(key, value); // carries over line item properties
}
}
// Bypass cart entirely — existing cart is untouched
window.location.href =
rootUrl + `cart/${variantId}:${quantity}?` + params.toString();
});
});
</script>
This should bypass the cart
This one will also add the buy now express checkout product to the prev cart if any present.
Try “Buy Button” way of creating cart permalinks as it is a separate channel from online store – simple permalink resets current cart.
No, it does not help.
So you can use cart permalink as a way to “push” a single product to checkout, but it also resets the previous cart.
So you’d need to save /restore the cart cookie yourself.
Something like this, though it’s an old solution – https://freakdesign.com.au/blogs/news/get-shipping-estimates-on-a-product-page
So you want to save, clear, then restore? Like Flipkart?
Yeah, I want the functionality like in the Flipkart and Amazon. But I think, they are not saving the previous cart and saving it back. In shopify without saving is there any other method. If not suggest the best possible method to save and restore the cart.
So that is gonna be tab dependent… if they open in new tab, session storage probably won’t persist.
<div class="custom-buy-now-wrapper">
<button
type="button"
id="CustomBuyNowButton"
class="button custom-buy-now-button"
>
Buy now
</button>
</div>
<script>
(function () {
'use strict';
const ROOT_URL = window.Shopify?.routes?.root ?? '/';
const STORAGE_KEY = 'buy_now_saved_cart';
async function maybeRestoreCart() {
const saved = sessionStorage.getItem(STORAGE_KEY);
if (!saved) return;
const path = window.location.pathname;
if (
path.includes('/checkout') ||
path.includes('/thank_you') ||
path.includes('/orders')
) return;
sessionStorage.removeItem(STORAGE_KEY);
let items;
try {
items = JSON.parse(saved);
} catch (e) {
console.error('Buy Now: Failed to parse saved cart.', e);
return;
}
if (!Array.isArray(items) || items.length === 0) return;
try {
await fetch(ROOT_URL + 'cart/clear.js', { method: 'POST' });
const res = await fetch(ROOT_URL + 'cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({ items }),
});
if (!res.ok) {
const err = await res.json().catch(() => null);
console.error('Buy Now: Cart restore failed.', err);
return;
}
console.log('Buy Now: Previous cart restored successfully.');
document.dispatchEvent(new CustomEvent('cart:restored', {
bubbles: true,
detail: { items },
}));
} catch (err) {
console.error('Buy Now: Cart restore error.', err);
}
}
function initBuyNowButton() {
const buyNowButton = document.getElementById('CustomBuyNowButton');
if (!buyNowButton) return;
const productForm = document.querySelector('form[action^="/cart/add"]');
if (!productForm) {
console.warn('Buy Now: No product form found on this page.');
return;
}
buyNowButton.addEventListener('click', async function () {
const formData = new FormData(productForm);
const variantId = formData.get('id');
if (!variantId) {
alert('Please select a variant before continuing.');
return;
}
const quantity = parseInt(formData.get('quantity'), 10) || 1;
const properties = {};
for (const [key, value] of formData.entries()) {
const match = key.match(/^properties\[(.+)\]$/);
if (match) properties[match[1]] = value;
}
buyNowButton.disabled = true;
buyNowButton.classList.add('is-loading');
try {
const cartRes = await fetch(ROOT_URL + 'cart.js', {
headers: { Accept: 'application/json' },
});
if (!cartRes.ok) throw new Error('Failed to fetch cart.');
const cart = await cartRes.json();
if (cart.items.length > 0) {
const snapshot = cart.items.map(item => ({
id: item.variant_id,
quantity: item.quantity,
properties: item.properties ?? {},
...(item.selling_plan_allocation?.selling_plan?.id && {
selling_plan: item.selling_plan_allocation.selling_plan.id,
}),
}));
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot));
}
const clearRes = await fetch(ROOT_URL + 'cart/clear.js', {
method: 'POST',
headers: { Accept: 'application/json' },
});
if (!clearRes.ok) throw new Error('Failed to clear cart.');
const addPayload = {
id: variantId,
quantity,
...(Object.keys(properties).length > 0 && { properties }),
};
const addRes = await fetch(ROOT_URL + 'cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify(addPayload),
});
if (!addRes.ok) {
const errData = await addRes.json().catch(() => null);
console.error('Buy Now: Add to cart failed.', errData);
throw new Error(errData?.description || 'Failed to add item to cart.');
}
window.location.href = ROOT_URL + 'checkout';
} catch (err) {
console.error('Buy Now error:', err);
alert(err.message || 'Something went wrong. Please try again.');
buyNowButton.disabled = false;
buyNowButton.classList.remove('is-loading');
}
});
}
document.addEventListener('DOMContentLoaded', function () {
maybeRestoreCart();
initBuyNowButton();
});
})();
</script>