Referral programs: no bonus for inviting yourself
The simplest referral fraud has one person on both sides: they share their own link, open it in the same browser and sign up again. Keep the device ID of every account, compare the new one with the referrer's, and pay the bonus only when the new customer is real.
The problem
A self-invite costs twice: the bonus for the referrer, and often a welcome bonus for the "friend". Programs that pay at sign-up are hit hardest.
This recipe never pays at sign-up. It pays when the invited customer makes a first payment, and it sends doubtful cases to a manual look instead of paying them automatically.
What the API gives you
device.id | Saved with every account at sign-up. The same ID for the referrer and the new account means the same browser profile. |
seen.accounts_on_device_30d | Several accounts on the new account's device in 30 days: a farm of "friends". |
verdict | spoofed or automation: a browser that hides what it is, or a script. |
The code
It calls the helper (sl_check_visitor and sl_user_ref), which sends the browser data from the form, the IP address, the headers and a hash of the email.
PHP
<?php
// sign-up through a referral link: decide how the referrer's bonus is paid
$r = sl_check_visitor(sl_user_ref($_POST['email']));
$deviceId = $r['device']['id'] ?? ''; // save it with every new account
$referrer = findAccountByReferralCode($_GET['ref']); // your lookup; it has the referrer's device_id
$sameDevice = $deviceId !== '' && $deviceId === $referrer['device_id'];
$doubtful = $r && (($r['seen']['accounts_on_device_30d'] ?? 1) >= 2
|| in_array($r['verdict'], ['spoofed', 'automation'], true));
$bonus = ($sameDevice || $doubtful) ? 'review' : 'on_first_payment';
// 'on_first_payment': credit the referrer when the new customer pays for the first time
// 'review': keep it pending until someone looks at both accounts Node.js
// sign-up through a referral link (Express): decide how the referrer's bonus is paid const r = await slCheckVisitor(req, slUserRef(req.body.email)); const deviceId = (r && r.device.id) || ''; // save it with every new account const referrer = await findAccountByReferralCode(req.query.ref); // your lookup; it has the referrer's deviceId const sameDevice = deviceId !== '' && deviceId === referrer.deviceId; const doubtful = !!r && (((r.seen && r.seen.accounts_on_device_30d) || 1) >= 2 || ['spoofed', 'automation'].includes(r.verdict)); const bonus = sameDevice || doubtful ? 'review' : 'on_first_payment'; // 'on_first_payment': credit the referrer when the new customer pays for the first time // 'review': keep it pending until someone looks at both accounts
Python
# sign-up through a referral link (Flask): decide how the referrer's bonus is paid
r = sl_check_visitor(request, sl_user_ref(request.form['email']))
device_id = r['device']['id'] if r else '' # save it with every new account
referrer = find_account_by_referral_code(request.args['ref']) # your lookup; it has the referrer's device_id
same_device = device_id != '' and device_id == referrer['device_id']
doubtful = bool(r) and ((r.get('seen') or {}).get('accounts_on_device_30d', 1) >= 2
or r.get('verdict') in ('spoofed', 'automation'))
bonus = 'review' if same_device or doubtful else 'on_first_payment'
# 'on_first_payment': credit the referrer when the new customer pays for the first time
# 'review': keep it pending until someone looks at both accounts Save device.id for every account, not only for invited ones: the comparison needs the referrer's ID from their own sign-up.
Soft steps instead of a ban
- Pay the bonus on the invited customer's first payment, not at sign-up.
- Look at review cases by hand: the two accounts, their emails, what they bought.
- When an account clearly invites itself again and again, close its referral link rather than the account.
Rules in your account
Set them in Rules and alerts: the result comes back as decision in every answer, so your code does not change when the rules do.
- Start with the default thresholds: review below 70, block below 30, automated browsers blocked.
- Turn on the webhook for review to get a message for each referral that needs a look.
- Put your own team's devices on the allow list, so testing the referral flow stays clean.
Where it can be wrong
- A couple on one laptop, or colleagues on one office computer, can be real referrals. That is why the same device leads to a review, not to an automatic no.
- Different devices do not prove different people. The recipe catches the lazy case; paying on a first payment catches most of the rest.
One line for your privacy policy
To prevent abuse of our referral program, we check technical characteristics of your browser with SpoofLens (spooflens.com) when you sign up.
Limits
- The device ID belongs to one browser profile: the same person in another browser looks like a new device.
- The account count covers 30 days; the device IDs you store have no such limit.
- SpoofLens does not see payments. Matching payment details between the two accounts is a strong extra check on your side.
Other recipes
- Free trial abuse: one trial per person, not per email
- Welcome coupons: a first-order discount for first orders only
- The API documentation
Get a free key 1,000 checks a month free, no card.