Blog·July 27, 2026

Shopify "one use per customer" not working? Here's why

The limit counts accounts, not people. Here's what it actually enforces, how customers route around it, and what enforcing "one per person" really takes.

You ticked “limit to one use per customer.” The same person redeemed your welcome code three times anyway. Nothing is broken. The setting is doing exactly what it says. The problem is what it says.

What the limit actually counts

Shopify’s one-use-per-customer limit counts customer records. And a customer record is, for practical purposes, an email address.

So the enforcement question Shopify asks at checkout isn’t “has this person used this code?” It’s “has this exact customer account used this exact code?” Which means every fresh email is a fresh customer with a fresh allowance:

  • sarah@gmail.com — first use, approved
  • sarah+deals@gmail.com — new customer as far as Shopify knows, approved
  • sarah.k@googlemail.com — same inbox, different string, approved
  • her old Outlook address, a guest checkout with her work email, and so on

None of this is hacking. Gmail’s +tag aliases and the googlemail.com domain all deliver to the same inbox; creating a storefront account takes thirty seconds. The person at the door keeps being someone new, on paper.

It gets worse with unique-code campaigns

Here’s the detail that surprises even technical folks. Run a campaign of unique single-use codes (the kind referral and email apps generate) and the per-customer limit acts per code, not per person across the set. We verified this directly: the same logged-in account can redeem multiple different codes from one bulk campaign, no aliases required. Each code only remembers its own history.

So a person who collects three referral codes can redeem all three, and every native setting is working as designed while they do it.

Why there’s no native fix

The advice you’ll find in forums amounts to: require accounts (kills conversion), manually review orders (doesn’t scale), or accept it as marketing spend (what most stores silently do). The structural issue is that Shopify has no concept of a person behind the customer records, and no setting toggles one into existence.

Enforcing “one per person” needs two things Shopify doesn’t have: a memory of past redemptions, and identity matching smart enough to see that sarah+deals@gmail.com and sarah@gmail.com are the same human.

What actual enforcement looks like

This is what we built Fraud Guard in PromoLock to do, and the shape of the solution explains a lot about the problem.

It remembers. On activation it reads up to a year of your discounted order history, so past redeemers are recognized from day one instead of only from today forward.

It normalizes identities. Email matching folds case, strips +tags, treats gmail.com and googlemail.com as one. Phone matching ignores formatting differences. Optionally, similar-matching catches the buyer whose name and shipping address are both near-copies of a previous redeemer. There’s a strictness dial, since “Jaimes” should probably match “James” but “Michael” shouldn’t.

It closes the set-wide hole. For bulk code campaigns generated in PromoLock, the guard enforces one code per person across the entire set — the enforcement Shopify doesn’t attempt.

It fails open. This part matters most. Only a definite match blocks a redemption; if a check can’t complete, the code goes through. The worst case is one leaked discount, never a blocked genuine customer. A checkout that errors on real first-timers costs more than the fraud ever did.

One honest caveat: the same-code check works for any once-per-customer code on your store, whatever created it. The set-wide guard only exists for bulk sets generated in PromoLock, and Fraud Guard runs on Shopify Plus.

The five-minute version

If you take one thing from this: the checkbox limits accounts, and accounts are free. For a shared code like WELCOME15, that’s the whole story of why it keeps getting farmed. Real enforcement means matching people, not emails. And if your welcome offer is generous enough to be worth farming, it’s generous enough to be worth protecting.