Geo-targeted offers that don't leak to the wrong customer
What the numbers say
- 01
Of 8 signals a Shopify store could gate a geo offer on, only 1 cannot be altered by the shopper without also changing where the order ships.
Trust boundary audit of Shopify cart, checkout and customer fields.
- 02
A discount code carries 0 geographic properties, so a code shared outside its intended zone applies at full value with no further effort.
Shopify discount code behaviour.
- 03
Cart attributes are writable through the public Ajax Cart API, putting exactly 1 HTTP request between a shopper and a geo-gated discount.
Shopify Ajax Cart API, cart update endpoint.
- 04
Gating on cart.deliveryGroups[0].deliveryAddress.zip means the only bypass is shipping the order into the target zone, which converts 100% of successful bypass attempts into genuine in-zone orders.
Shopify Discount Function input fields.
The trust boundary in a Shopify checkout
Every geo-gated offer answers one question at checkout: is this order going to a zone that qualifies. The security of the offer is entirely determined by which field supplies that answer.
Fields in a Shopify order fall on two sides of a trust boundary.
Shopper-supplied. Values the visitor can set or change from the browser, directly or through a public API, without changing anything about the order that matters to them.
Platform-asserted. Values Shopify derives from the order itself, where changing the value necessarily changes the order.
A gate on the first side is a suggestion. A gate on the second side is a constraint.
The distinction is not about difficulty. Assume any shopper-supplied field will be altered the first time the offer is worth altering it for, because the instructions will be in a group chat within a week of launch.
Signal by signal: which gates leak
| Signal | Written by | Shopper can change it | Changing it changes the order | Safe to gate on |
|---|---|---|---|---|
| Discount code string | Shopper | Yes | No | No |
| Cart attribute | Theme or shopper | Yes, via Ajax API | No | No |
| Line item property | Theme or shopper | Yes, via Ajax API | No | No |
| Cart note | Shopper | Yes | No | No |
| Pincode checker widget value | Shopper | Yes | No | No |
| IP or edge geo header | Network | Yes, via VPN | No | No |
| Customer tag | Merchant | No | No | Partly |
| Delivery address on cart | Shopify, at checkout | Yes | Yes | Yes |
Eight signals, one of which holds. The pattern is visible in the fourth column rather than the third.
Several signals are shopper-changeable, which is expected. Only one is shopper-changeable in a way that also moves the parcel, and that coupling is the entire security model.
Customer tags sit in an awkward middle. They cannot be tampered with, because only the merchant writes them, but they describe an address recorded at some earlier point rather than the address on this order, and they do not exist for guest checkouts.
Why discount codes cannot be geo-gated at all
A discount code is a string. Strings have no geographic properties.
The common workaround is to issue a distinct code per zone and distribute it only to customers in that zone. This fails on first contact with a group chat, because distribution is not enforcement.
Codes also fail in a way that is worse than leaking. Once MUMBAI25 is public, the leak is permanent, indexed by coupon aggregator sites within days, and visible to every shopper on your own checkout page who searches for it before paying.
Per-customer unique codes narrow the blast radius but do not solve it. They convert one shared code into a marketplace of shared codes, and they add a redemption limit as the only remaining defence.
The structural fix is to remove the code. An automatic discount evaluates a condition at checkout, so there is no string to distribute and nothing to search for.
Why cart attributes fail
Cart attributes are the most common wrong answer, because they are the easiest thing for a theme developer to reach for.
The usual pattern is a pincode checker widget on the product page that writes the entered pincode into a cart attribute, and a discount rule that reads it. Any visitor can call the same public cart update endpoint the widget calls.
That is one HTTP request between a shopper and the discount. No tooling is required beyond a browser console.
Line item properties and cart notes fail identically and for the same reason. All three are shopper-supplied input that a theme happens to have written first.
The general rule: if a value can be set without changing the delivery address, it is not evidence about the delivery address. A widget writing a pincode into a cart attribute is recording a claim, not establishing a fact. Where the underlying order-density analysis fits is covered in pincode marketing as a geo lever.
Why IP geolocation answers the wrong question
IP and edge geo headers are frequently proposed as the tamper-resistant alternative. They fail on two independent grounds.
The first is that they are not tamper-resistant. A VPN changes the answer in under a minute and costs nothing.
The second is more fundamental and applies even against an honest shopper. Where someone is browsing from is not where the parcel is going.
Ordering to a home address from an office network, a parent ordering to a child’s hostel, a customer ordering while travelling: these are ordinary Indian D2C cases. Gate on IP and you deny the discount to qualifying customers while granting it to non-qualifying ones, which is both failure modes at once.
Edge geo headers remain useful for content decisions such as which banner to show. They are not usable as a gate on money.
The one field that holds
The delivery address on the cart is the only signal where changing the value changes the outcome the shopper cares about.
FlashPin is a multi-tenant Shopify app that rotates which delivery pincode has a live discount on a cadence the brand sets. Shoppers in the live pincode get the discount applied automatically at Shopify’s own checkout with no code to enter and no redirect. Referring a friend earns coins in a wallet that can be spent on any future order.
The implementation reads cart.deliveryGroups[0].deliveryAddress.zip inside a Shopify Discount Function, with the currently live pincode held in a shop metafield that a rotation clock writes to.
Three properties follow from that choice.
There is no code to share, because the discount applies automatically. There is no client-side value to rewrite, because the evaluation runs server-side inside the Function. And the only way to make the condition true is to enter a delivery address inside the zone.
That last one is why the gate holds. A shopper who bypasses it has committed to a real delivery into the zone, paying real in-zone freight, which is the order the offer was trying to buy in the first place.
Implementation checklist
Work through these in order before launching a geo offer.
Confirm the gate reads a delivery field. Open the Function input and check that the pincode comes from the delivery group, not from a cart attribute the theme populated.
Remove every code path. If a code exists as a fallback for support cases, it is the leak, regardless of how rarely it is used.
Handle the empty case explicitly. Before a delivery address is entered, the field is absent. Decide what happens then, and make the default no discount rather than discount applied.
Fail closed on missing configuration. If the metafield holding the live pincode is empty or malformed, the Function should grant nothing.
Check the pincode format. Indian PIN codes are six digits and address forms accept anything. Normalise before comparing, and reject on length mismatch rather than passing through.
Log the delivery pincode against every discounted order. Without this you cannot audit leaks after the fact, and you cannot measure the zone against its own baseline, which is what a hyperlocal flash sale without a physical store depends on.
Residual leak paths and what they cost
One path remains open and it should stay open.
A shopper outside the zone can ship to a friend or relative inside it. The order is then a genuine delivery into the target pincode, with the freight profile and the delivery timeline of an in-zone order.
That is not a leak in any meaningful sense. It is a referral with extra steps, and the economics are the ones you signed up for.
Two smaller paths are worth knowing. Multi-destination carts split into several delivery groups, so a rule reading only the first group can be gamed by ordering a low value item to the zone alongside high value items elsewhere. Check whether your Function evaluates per delivery group or per cart.
Address edits after purchase are the other. A support agent changing a delivery address post-payment does not re-evaluate the discount, so a customer who claims a mistake keeps the money.
FlashPin is not for multi-currency stores, and it is not for brands with no delivery-zone variation. If delivery is uniform across your map, none of this trust boundary work buys anything, because the gate would be separating populations that behave identically.
The limitation worth naming is that a leak-proof gate does not make an offer worth running. A perfectly enforced discount aimed at a zone that was going to buy anyway is a well-engineered way to lose money, and the enforcement question is downstream of the targeting question. Settle which zones deserve the offer first, which is what the marketing channel nobody has touched is about.
Questions people actually ask
How do you prevent discount code sharing?
Stop using a code. A code is a string with no geographic properties, so once it is posted anywhere it applies for everyone who enters it. Automatic discounts that evaluate a server-side condition at checkout cannot be shared, because there is nothing to copy and paste. The condition does the gating instead of the secret.
Can shoppers edit Shopify cart attributes?
Yes. Cart attributes and line item properties are writable through the public Ajax Cart API, which any visitor can call from the browser console. Anything a theme writes there, a shopper can rewrite. Treat cart attributes as shopper-supplied input, never as an assertion about the shopper.
Is IP geolocation good enough to gate a regional offer?
No, for two independent reasons. It is trivially changed with a VPN, and it answers the wrong question, because where someone browses from is not where the parcel goes. A shopper on office wifi in one city ordering to their home in another is a normal case, not an edge case.
Why not just tag customers by region and gate on the tag?
Customer tags are merchant-writable, which makes them safe from tampering, but they go stale and they miss guests. A tag reflects an address at the moment it was written, not the address on this order. Use tags for messaging and segmentation, never as the gate on money.
What is the residual leak risk on a delivery-address gate?
Someone shipping to a friend's address inside the zone. That is the only meaningful path, and it is self-limiting, because the parcel genuinely has to go to that address. The order is a real in-zone delivery with real in-zone freight, which is the outcome the offer was designed to buy.