You send a 40%-off launch code to your email list. It’s “one per customer.” By lunch, someone has posted it to a deal forum, and your redemptions chart looks like a hockey stick. Half the orders come from accounts created in the last ten minutes.
This is a different problem from a code being stacked or brute-forced. The code is valid, the checkout works as designed, and most redeemers are real people. What’s broken is the audience: a code meant for a few thousand subscribers is now open to anyone, and “one per customer” is being enforced per account, which is free to create.
This post covers containment: what to change in the next hour, how to enforce the limit on something sturdier than an account, and how to decide what to honor.
First hour: contain without breaking checkout
When you notice the leak, the instinct is to kill the code. That punishes the subscribers you sent it to, some of whom haven’t redeemed yet. Better options, roughly in order:
- Add a per-device redemption limit if you can deploy one quickly (more below). This lets the code keep working for real first-time redeemers.
- Restrict the code to accounts created before the send. If the code was for existing subscribers, an account created after the email went out wasn’t on the list. This is the fastest fix and usually needs only a date comparison.
- Cap total redemptions at a ceiling close to what you budgeted, so the damage is bounded while you work on the real fix.
- Retire the code and email a new one to the original list if the leak is bad. Per-recipient codes cost a little more to generate and are much harder to leak usefully.
None of these require a judgment about any individual order. They limit the blast radius.
Why “one per customer” fails
The deal-forum crowd isn’t one abuser; it’s many people, most of whom redeem once. The real cost comes from a smaller group who redeem again: they create a second account with a plus-addressed email, use a different card or a wallet, and order again. Some are resellers buying stock to flip. A per-account limit doesn’t see any of this, because each account really did redeem only once.
The tells that do work are about the device and the account’s age:
- Same device, several accounts, several redemptions. The strongest signal, and the one a per-account check can’t see.
- Accounts created minutes before checkout. Normal customers rarely sign up and redeem a launch code in the same session unless they arrived from a share.
- Shared shipping address or payment instrument across accounts. Useful, but resellers vary these more easily than they vary the laptop.
Enforce the limit per device
At checkout, identify the browser and send the requestId with the order. On the server, look at the event before applying the discount:
import { PryntServer } from '@prynt/node';
const prynt = new PryntServer({ secretKey: process.env.PRYNT_SECRET_KEY });
async function canRedeem(code, requestId, userId) {
const event = await prynt.getEvent(requestId);
if (event.decision === 'block') return { ok: false, reason: 'blocked' };
// Your own ledger: which devices already redeemed this code?
const prior = await db.redemptions.count({ code, visitorId: event.visitorId, userIdNot: userId });
if (prior >= 1) return { ok: false, reason: 'code_already_used_on_device' };
return { ok: true, visitorId: event.visitorId };
}
When the order completes, store visitorId on the redemption row. That ledger is yours: Prynt identifies the device, you decide what counts as a redemption. If your accounts are already linked to devices (with updateEvent(requestId, { linkedId }) at signup), event.accountsOnDevice also tells you how many accounts that device holds, which is a useful second check:
const accountsHere = event.accountsOnDevice.count;
if (accountsHere >= 3 && accountAgeMinutes(userId) < 60) {
// brand-new account on a device with several others: hold the discount for review
}
Make the refusal specific and polite: “This code has already been used on this device.” Real customers who share a computer with a partner can contact support, and you can whitelist them.
Spot the burst before the forum post does
You don’t have to wait for the chart to go vertical. Three numbers, checked hourly per active code, catch most leaks early:
| Metric | What it suggests |
|---|---|
| Redemptions per hour vs. the first day’s average | A sudden multiple means a new audience found it |
| Share of redemptions from accounts under one hour old | Rising share means the code is pulling in signups, not customers |
| Redemptions per device | Above 1 for more than a handful of devices means repeat use |
The third only works if you store visitorId on redemptions. That’s the cheapest part of this whole post and the most useful one after the fact.
On the Scale plan, the risk.high and decision.block webhooks can feed the same alerting channel, so a spike of risky redemptions shows up next to the business metrics instead of in a separate tool.
Decide what to honor
After the incident, someone will ask whether to cancel the discounted orders. A defensible line:
- Honor the first redemption per device, even from new accounts. These are mostly real people who saw a public deal. Cancelling them generates support tickets and bad reviews that cost more than the discount.
- Void or cancel the second and later redemptions from the same device across different accounts. Your terms said one per customer; the device evidence shows one customer.
- Review high-value or high-quantity orders from new accounts, especially on limited stock, before they ship. This is where resellers concentrate.
Write the decision down along with the evidence for each cancelled order (visitorId, accounts on the device, redemption times). If a customer disputes it, you have something concrete to point to rather than “our system flagged you.”
Next launch
The structural fixes are boring and effective: per-recipient codes for targeted sends, redemptions tied to accounts created before the send, a per-device limit on any public code, and visitorId stored on every redemption from day one. Then a leak is a marketing surprise rather than a margin problem.
For adjacent patterns, see coupon stacking detection, the broader promo abuse prevention guide, and referral fraud at signup. The ecommerce solutions page shows how the same device signals apply across checkout.
Try it free
Prynt is device intelligence with a free tier — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics, powered by a cross-site network. Start free.