Every SaaS founder eventually has the same idea: our users like the product, so let’s pay them to bring in more users. Give something away for every friend who signs up. It costs nothing to run and it spreads on its own.
We had that idea in September. We switched it off six weeks later. It wasn’t that nobody used it. The people who used it most were inviting themselves.
I’m sharing what happened because the usual advice on referral fraud (“just add verification”) skips the real trade-off. You can make a referral program impossible to abuse. You can also make it pleasant for honest users. As a small company, you almost certainly can’t do both at once.
Join The European Business Briefing
New subscribers this quarter are entered into a draw to win a Rolex Submariner. Join 40,000+ founders, investors and executives who read EBM every day.
SubscribeThe setup
We make a browser-based tool for backtesting forex and other markets: you replay historical charts candle by candle and log trades as if they were live. One of our paid features is multi-timeframe charting, which shows the same moment on the 5-minute, 1-hour and daily charts at the same time. Free users want it badly.
So the referral deal was simple. Invite a friend. When that friend signs up and closes five practice trades, you get multi-timeframe charting on your account permanently. The friend also gets one multi-timeframe session as a welcome.
We knew a free permanent unlock would attract people trying to game it. So before launch we built what we thought was a solid set of defenses:
- All decisions on the server. Who invited whom, how many trades counted, and whether the reward unlocked were all recorded and decided in our backend, inside database transactions. Nothing could be toggled from the browser console.
- Write-once attribution. An account’s inviter could be set only at registration and never changed.
- A real-usage threshold. A signup alone earned nothing. The invited person had to actually use the product and close five trades.
- A cooling-off period. An account that had been invited couldn’t send its own invites for seven days. That blocked chains where one person creates account B to unlock A, then C to unlock B, all within a minute.
- One account per device, and no inviting yourself on the same device. We already limited free signups per device. If the invited account was registered on the same device as the inviter, the referral was quietly dropped.
On paper, that’s a lot of defense for a feature whose reward was one chart layout.
What actually happened
By late October, 37 invited accounts had “qualified.” That looked like a success until we looked at the timing.
Many invitees reached five closed trades within one or two minutes of creating their account. Some of the inviting accounts had themselves been created only minutes before their invitee. Real people don’t sign up, learn a charting tool and finish five considered practice trades in ninety seconds. This was someone opening a second identity, rushing through the requirement and collecting the reward on the first.
We confirmed three accounts as clear self-referrers and revoked their unlocks by hand. A large share of the rest looked the same but wasn’t provable. We decided not to punish people on a hunch.
Why five rules weren’t enough
Looking back, both of the rules that mattered depended on something the user’s own browser told us.
The device check depended on a device ID the browser reported. A private window, a second browser or a cleared cache looks like a new device. We had built a lock that a home computer can get past in about four seconds.
The trade count was reported by the client. The server did the counting, but it counted what the app sent it. A determined person can make the app report “five trades done” without any real trading happening. All the server-side transaction logic in the world doesn’t help when the input itself is made up.
This is the general lesson. Moving logic to the server doesn’t make it trustworthy if the server is still taking the user’s word for the facts. Our backend faithfully enforced rules about events it had no way to verify.
The fix we didn’t take
The obvious next step is a strong identity signal: require phone verification for both people in a referral. One phone number per account is much harder to fake than a browser ID.
We considered it and said no, because of what it costs honest users.
Our product has a free tier because people want to try a trading tool before committing to it. Many of them are cautious about handing personal details to yet another fintech site, and frankly they should be. Asking every new user for a phone number at signup would cut abuse. It would also cut the very signups the referral program was meant to bring in. A phone wall that blocks 30 fraudsters and turns away 300 genuine people is a bad trade.
Phone numbers also aren’t a perfect fix. Virtual numbers are cheap, and SMS verification costs money on every attempt, including the attempts made by abusers. You end up paying to be attacked.
That’s the trap. Each extra layer of verification raises the cost for abusers and for real users at the same time. You never get a setting where only the abusers feel it.
What we did instead
We removed the reward entirely. Multi-timeframe charting is now available only through a free trial or a paid plan. Existing honest unlocks stayed in place. Only the confirmed abusers lost theirs.
If we bring referrals back, the reward will be tied to something that costs an abuser as much as it costs us. That means a started paid trial or an actual payment, checked against a payment card that differs from the inviter’s. Faking a phone number is cheap. Faking a new valid card with a different fingerprint on every attempt is a real deterrent, and the payment processor checks it, not our JavaScript.
Lessons for any team running incentives
Assume a free permanent reward will be farmed. How quickly it happens depends on how much the reward is worth, not on how clever your rules are. Ours was worth having, so people farmed it within weeks.
List every input your rules depend on, then ask who controls each one. If the honest answer is “the user’s browser,” the rule is a suggestion, however well the server enforces it.
Measure time to qualify, not just number of qualifications. The giveaway wasn’t how many people qualified. It was how fast they did it. A “minutes from signup to reward” chart would have caught this weeks earlier.
Price your friction in lost honest users. Before adding a verification step, estimate how many real signups it will lose. Often the cheapest fix for abuse is a smaller or different reward, not a bigger wall.
Tie rewards to value that has already happened. “Signed up and clicked around” can be faked. “Started paying” mostly can’t. If the reward only unlocks once the referral has already made you money, abuse costs the abuser more than it costs you.
We like products that let people test an idea against reality before risking anything. That’s the whole point of backtesting forex. Our referral program was an untested strategy we launched straight into production, and the market did what markets do: it found the weakest assumption and exploited it.
The program failed, but the lesson was worth having. Every incentive you design will be tested by someone, so design it assuming they’re trying hard.



































