I used a modified version of this ajax solution:
https://gist.github.com/elghorfi/ce7e5b1080aae37d0a415643f33bc79e
It is complex but I can confirm that it works.
It’s an interesting find! But I don’t get why his solution is so… convoluted I’d say. I actually shared my own solution on the gist feed (I believe much simpler and more efficient), could be interesting to compare the pros & cons.
A few things I wanted to add:
fetch(`/checkout?discount=${code}`);
This alone seems to work, as does this:
fetch(`/discount/${code}`);
I’m wondering if anyone has seen a case when only doing one or other fails in some cases.
Also, with some of the built-in themes (Refresh, Craft) I’ve seen many cases where the cart views (both the cart drawer and the dedicated cart page) end up getting cached so they only ever show whatever discount was applied the first time you viewed that particular page. This has nothing to do with applying a code via either fetch call either, as the results held true even when applying the discount code manually in the checkout as a user would normally.
Anyway, in my tests, either fetch call above works to get the discount in the checkout but I’m betting not all themes would see the same result.
Also, with some of the built-in themes (Refresh, Craft) I’ve seen many cases where the cart views (both the cart drawer and the dedicated cart page) end up getting cached so they only ever show whatever discount was applied the first time you viewed that particular page. This has nothing to do with applying a code via either fetch call either, as the results held true even when applying the discount code manually in the checkout as a user would normally.
You might be talking about automatic discouts? Automatic discounts will apply in cart page “automatically” as their name imply (as long as the cart liquid template is using the discount_allocation and discount_application objects).
What seems to be new (in my experience) since the release of these objects, is that now the manual discounts that are applied also render within these objects, which is quite convenient and opens up some possibilities.
This isn’t with automatic discounts, but it seems like some newer versions of these Shopify-provided themes will show you any cart-level discounts that you may have applied during checkout in the cart view. For example, in this view YUM10 isn’t an automatic discount, but one I added during checkout and then clicked back to the store to continue shopping. In my experience, if I then go back to checkout, remove YUM10, then click from the checkout back to “Cart”, the old discount is still there, even if reloading the page manually. I thought this was a bug with our plugin but it turns out this behavior exists even with no plugins installed.
Anyway, would love to hear if you’ve noticed any difference between the /checkout?discount=CODE and the /discount/CODE fetch techniques. Both seem to work equally well in my case.
Okay I see, so this is what I mentioned in the second part of my message. The caching issue, this might be a miss on Shopify side, or maybe due do the page caching by the browser, which happens when returning to a page with the back button (typical use case for navigation from checkout to cart).
I suppose this could be detected with javascript pageshow event, and then fetching a fresh version of the cart.
I’ve only used the ‘/discount/CODE’ technique, which I guess is originally the API intended for shareable discount urls. I have not had any issue with it yet but I’ve only played around with it for a month, and since it’s undocumented…
I suppose this method ‘/checkout?discount=CODE’ might allow to apply multiple manual discounts at once (comma separated) whereas it’s not possible with the first method. I have not checked for myself though.
Oh wow, I am really interested to see how this is achieved - do you have a link to the store? I wonder if it is checking the cookie, and showing it accordingly BUT the discount amount isn’t stored in the cookie I don’t think, so I’d be curious how it is doing that. Maybe the theme is using a discount API or something? My understanding was you couldn’t show manual discounts in the cart because they rely on checkout data to check if eligible.
I tried out 6 apps that promised to add a discount code validation to the cart but turns out 5 out of 6 had various issues with stacked discounts or free shipping discounts, or didn’t work at all. Decided to write down a detailed review of all of them here: https://appreviewhq.com/shopify-discount-app-review-2024. TLDR: the only app I found that supported both stacked discounts and free shipping discounts was https://apps.shopify.com/discount-before-checkout. Still crazy to me how this is not a built-in feature, and how many apps seem to get it wrong.
Usually I’d agree (I think Shopify has a lot of crazy stuff and I actively complain about it!) but this is actually a complex feature once you dive below the surface - some discounts are limited to specific customer emails/once per customer/address locations, and this information is not captured until checkout. Another missing but complex feature, due to similar constraints, is shipping costs on cart page.
Of course, it can be achieved in both scenarios via JavaScript/API, but needs consideration for certain use cases; what should the message be if I add a discount to the cart that requires information collected in checkout? Perhaps something like “Sorry, you can only add this discount during checkout”, but then the user experience gets a bit messy because some discounts I can add in cart, and some I can’t. The alternative I think would be to allow all discounts to be added in cart, and totals adjusted, but then kick off a discount with an error message if once entering checkout details the discount is no longer valid, but that could annoy the customer’s expectations.
So I think I can see why they opted to leave discounts and shipping in checkout by default - much simpler, but still allowing developers/apps to achieve it via JavaScript/API if absolutely necessary. That said, there’s no excuse for apps not delivering what they promise (too common, sadly). Glad you found one that can do it (thanks for sharing the link) - I’d be interested how it deals with the challenges I mentioned above.
An aside, Shopify uses a white-label version of Stripe checkout, so it may even be a decision at the Stripe level.
I’ve found the best solution for the discount input field on the cart page or in the cart drawer. It’s a bit complex to explain in a comment, but my solution performs much better compared to using a marketplace app from the app store, as far as I can see. Check out the attached video https://screenrec.com/share/YkamSOF5sx . I didn’t use any app—everything is implemented directly in the theme, giving me full control. I have used GraphQL and Storefront API. Used cartDiscountCodesUpdate mutation. Feel free to contact me on LinkedIn: https://www.linkedin.com/in/bhshiam/
Here is the mutation Code.
mutation {
cartDiscountCodesUpdate(
cartId: "gid://shopify/Cart/Z2NwLWV1cm9wZS13ZXN0MzowMUo4OUtWM0RYQU44VjcyUFJSRkpNSDBaNg?key=d37071d35414d5f784bc04eaf4e2089f"
discountCodes: ["abo5"]
) {
cart {
id
discountCodes {
code
applicable
}
checkoutUrl
}
userErrors {
code
field
message
}
}
}
