Navigating Regional Pricing: Why Your Shopify Discounts Might Miss the Mark on Apple Pay (And How to Fix It!)
Hey everyone! As a Shopify expert who spends a lot of time digging through community discussions, I often come across really insightful threads that tackle tricky issues. One recent conversation caught my eye because it hits on something many of you might be trying to do: adjusting product prices based on where your customers are located.
The original question, posed by @JiangMintun, was about a very specific problem: their carefully crafted regional discount wasn't applying when customers used Apple Pay. They were using a UI extension to grab the shipping address, add it to the cart, and then a discount function to apply product-specific discounts. For express checkouts like Apple Pay, they were relying on the billing address. But then, a real order came through via Apple Pay, and poof – no discount. The big question: Does express payment *always* provide the billing address to our function?
The Short Answer: No, It's Not Guaranteed!
This was the resounding consensus from the community experts, and it’s a crucial piece of information. As @DiegoCosta2428 and @v.marychenka pointed out, both cart.billingAddress and the delivery group’s deliveryAddress in the Discount Function input are nullable. Shopify's own documentation doesn't explicitly state that accelerated checkouts like Apple Pay or Google Pay will always pass a filled billing address.
@Mustafa_Ali chimed in with a great guess (which @DiegoCosta2428 also suggested confirming): address details usually only become available once the buyer authorizes in the wallet sheet. This means your function could run *earlier* in the checkout flow when the billing address is still empty or undefined. That's a major reason why your discount might not be firing!
What Else Could Be Going Wrong?
@v.marychenka highlighted another critical documented gap: "Attribute changes aren’t available when the buyer uses an accelerated checkout method such as Apple Pay or Google Pay." If your UI extension is saving the address as a cart attribute, those changes simply won't be there for accelerated checkouts. This is a big deal, as it means your extension's efforts to pre-fetch and store address data might be completely bypassed by Apple Pay.
The Best Way to Handle Regional Pricing: Shopify Markets
Before we dive into complex workarounds for discount functions, let's talk about the ideal, built-in Shopify solution for regional pricing: Shopify Markets.
@DiegoCosta2428 brought this up, and it's a game-changer for anyone wanting different prices by country. With Markets, you can set market-specific prices directly in your Shopify admin. This happens before checkout even begins, meaning Apple Pay or any other payment method will simply process the price that's already been determined for that customer's market. No complex address logic in functions needed!
The only "catch" is that a market follows the buyer’s country (often detected via IP address or browser settings), not necessarily their billing address. For most regional pricing scenarios, this is exactly what you want. It's much more robust and less prone to the kind of issues @JiangMintun faced.
If You Must Use Discount Functions (and Address Logic): Here's Your Action Plan
Sometimes, Shopify Markets might not fit your exact, hyper-specific discount logic, or you might be tied to an existing function setup. If you absolutely need to use discount functions and rely on address data, here's a synthesized approach based on the community's expert advice:
1. Debug Like a Pro: Find Out What Your Function Actually Received
This is step one, and it's non-negotiable. Don't guess; confirm. For that Apple Pay order that failed, or for new test orders:
- Open the function run log: Go into your app's logs in your Shopify admin to see the input your function received during that specific checkout.
- Replay the run with the CLI: If you're a developer, use the CLI's
function replaycommand to simulate the exact run and inspect the data.
This will tell you definitively if billingAddress (or deliveryAddress) was null when your function executed.
2. Fortify Your Address Logic: Handle Nulls and Fallbacks
Since addresses aren't guaranteed, your function's code needs to be resilient:
- Prioritize delivery address: As @DiegoCosta2428 suggested, key on the
deliveryAddressfirst. It's often available earlier than the billing address, especially with wallets. - Use billing as a fallback: If
deliveryAddressis null, then trycart.billingAddress. - Always handle null for both: Your code must gracefully handle scenarios where *both* addresses are null. Don't let your function crash or fail silently; have a default behavior (e.g., no discount) in such cases.
// Example pseudo-code for your function (concept only)
let targetAddress = cart.deliveryGroups[0]?.deliveryAddress || cart.billingAddress;
if (targetAddress && targetAddress.countryCode === "CA") {
// Apply Canadian discount
} else {
// Default pricing or other logic
}
3. Re-evaluate Your UI Extension's Role
Given that cart attribute changes aren't available for accelerated checkouts, if your UI extension's primary purpose is to add address data as attributes for your discount function, you might need to rethink its role. The Discount Function API directly provides `delivery group’s delivery address` and `cart’s billing address` in its input. You might not even need the extension for this specific task!
As @v.marychenka advised, test an Apple Pay order *before* dropping your extension to confirm if the function can get the necessary address data directly without the extension's intervention.
4. Test, Test, Test (with Real Apple Pay Orders!)
This can't be stressed enough. The nuances of accelerated checkouts mean that what works in a standard checkout might not work with Apple Pay or Google Pay. Create real test orders using these payment methods to validate your logic and ensure your discounts are applying as expected.
So, what's the big takeaway here? If you're looking to implement regional pricing on Shopify, your first stop should almost always be Shopify Markets. It's designed for this exact purpose and bypasses many of the complexities of real-time address availability during accelerated checkouts. If you're deep in custom discount functions and need address data, be prepared for nullable fields, debug meticulously, and build your logic with robust fallbacks. It's a common challenge, but with the right approach, you can ensure your customers get the correct pricing, no matter how they choose to pay.