# How to Prevent Referral Fraud in a Mobile App

> Prevent referral fraud in a mobile app: self-referral on one device, reinstall farming, and coupon-site sharing, and the reward design that stops each.

_Last updated: 2026-10-26_

Prevent referral fraud by paying on evidence instead of installs: reward exact matches only, hold estimated ones, allow one credit per installer, delay the reward until the new user does something real, and cap what any inviter can collect. This guide lists the abuse patterns first, then the design that answers each.

The goal is to make the abuse cost more than the reward, while honest users never notice a check. For the webhook-side checks themselves, such as signature and duplicate events, see [verify a referral before you grant the reward](https://warplink.app/blog/verify-referral-before-reward). This post is about the shape of the program around those checks.

## The four abuse patterns

### 1. Self-referral on the same device

A user taps their own invite link, installs, and claims the reward as two accounts. The cheap version uses the same phone: delete the app, tap the link, reinstall, sign up with a second email.

### 2. Reinstall farming

One person reinstalls many times, or creates account after account on one device, each one claiming a credit for a friend's link.

### 3. Emulators and device farms

Scripts install the app on virtual or rented devices at volume and walk through sign-up. They go through the normal install path, so the defense is in the reward design.

### 4. Link sharing on coupon and deal sites

An inviter posts the link on a deal forum or a social feed. Real strangers install and sign up. These are real people, but they came for the reward, not from a friend, and they leave after it pays.

The patterns differ in intent but share a trait: each one needs a reward worth more than the effort. Most of your defense is the reward design.

## What we give you

Know these signals before you design around them.

**We record the evidence for each credit.** A referral carries `match.method` (`install_token`, `android_referrer`, `device_id`, `link_open`, or `probabilistic`), whether it was `exact`, a `confidence`, the link that brought it, the installer id, and any `flags`. The first four methods are exact. A `probabilistic` match is an estimate.

**We enforce one credit per installer.** The first valid claim for an app and an installer id wins. The same installer claimed again answers `ignored`, with `duplicate_of` naming the referral that holds the credit, and no second webhook is sent.

**We apply a credit window.** You choose 24 hours, 7 days (the default), or 30 days from the tap. A claim after the window is recorded as `flagged` with `outside_window`, and is not a normal credit.

**We do not count taps from devices that already have the app**, unless you turn on **Count people who already have the app** for the app. It is off by default.

**The decision to pay is yours.** For emulator and device-farm volume, your defenses are the delayed reward, the caps, and the review of the evidence below.

## Defense 1: reward exact matches, hold estimates

The strongest signal is the match method. An install token, a Play install referrer, a device id, or a link open ties the install to the link directly. A probabilistic match is a good guess. Pay the first, queue the second.

```ts
function rewardDecision(event: ReferralEvent): 'pay' | 'hold' | 'skip' {
  const { match, flags } = event.data;
  if (flags.includes('outside_window')) return 'skip';
  return match.exact ? 'pay' : 'hold';
}
```

A held referral costs the inviter a short wait and costs you a few minutes of review a week. If the estimate is upgraded later, a `referral.updated` event arrives with reason `exact_match`; pay the inviter it names. See [exact vs estimated referral attribution](https://warplink.app/blog/referral-attribution-exact-vs-estimated) for how the methods differ.

## Defense 2: one claim per installer, a real installer id

The installer id is the identity of the new user in your system. Make it a dedicated random id stored with the account, not an email and not a primary key. Two things follow.

- A repeated claim for the same installer is `ignored`, so one new user pays out once.
- A new account on the same phone gets a new id, so the id alone does not stop reinstall farming. That is why the next two defenses exist.

Send the claim from your backend after your own sign-up checks, so a user cannot call your reward path directly. The [Referrals API](https://warplink.app/docs/api/referrals) takes the claim as `POST /v1/referrals/claims`.

## Defense 3: block the obvious self-referral

Two checks catch most casual self-referral and cost one line each.

- Keep **Count people who already have the app** off. The same phone, with the app still installed, is then not a referral.
- In your reward handler, refuse a referral whose inviter and new user are the same account, or share a verified phone number or payment method.

```ts
async function isSelfReferral(inviterId: string, newUserId: string) {
  if (inviterId === newUserId) return true;
  return db.users.shareVerifiedIdentity(inviterId, newUserId);
}
```

The second check is yours, because only your backend knows what identities your users verified.

## Defense 4: delay the reward until a real action

This is the most effective control, and it works against all four patterns. Do not pay on install or on sign-up. Pay when the new user does something that costs a fake account real effort: a first purchase, a completed profile and a first week of use, or a paid subscription month.

```ts
async function onClaimed(event: ReferralEvent) {
  const { referral_id } = event.data;
  await db.pendingRewards.upsert({ referralId: referral_id, state: 'waiting' });
}

// called when your product sees the qualifying action
async function onQualified(newUserId: string) {
  const pending = await db.pendingRewards.forInvitee(newUserId);
  if (pending?.state === 'waiting') await grantOnce(pending.referralId);
}
```

Delay turns coupon-site traffic into a measured cost too. If many installs from one link never qualify, that is a pattern you can see before you pay anything.

## Defense 5: cap what one inviter can collect

A cap bounds the damage from any pattern you missed. Ten rewards per inviter per year is generous for friends and tight for a farm. Count and insert in one transaction, or use a unique constraint on the reward row, so two events at once cannot both pass the cap.

Pair the cap with a higher bar for large rewards. A free week needs less review than a free year.

## Defense 6: shut a leaking link down

When a link shows up on a coupon site, pause or end it. An invitation expires when its link is paused or ended, so the leak stops without code changes. Give the inviter a new link, and the rest of their audience keeps working. If one inviter leaks repeatedly, remove their reward, not the program.

## Watch the data

Fraud shows in aggregates before it shows in single rows. In the Referrals report, look for:

- One link with many credits and almost no qualifying actions.
- A spike of `probabilistic` matches against a normal base of exact ones.
- Many `flagged` rows with `outside_window` on one inviter.
- Installs clustered in a few minutes from one link.

The same list is `GET /v1/referrals` and the MCP tool `list_referrals`, so a weekly script can alert you. For the payload fields, see [the referral reward webhook in Node.js](https://warplink.app/blog/referral-reward-webhook-node).

## A short policy to publish

State the rules in your referral terms. Say rewards are paid after the new user completes a qualifying action, that one reward applies per new user, that rewards are capped, and that you can withhold a reward for abuse. A clear rule lets you withhold a reward without an argument.

## Frequently Asked Questions

### How do I prevent referral fraud in a mobile app?

Pay on evidence, not on installs. Reward only exact matches, hold estimated ones, allow one credit per installer, delay the reward until the new user does something real, and cap rewards per inviter. Design the reward so abuse costs more than it pays.

### Can someone refer themselves on the same phone?

A tap on a phone that still has the app is not counted by default. A delete, tap and reinstall can earn an exact match, and credit is one per installer id. Tie the reward to a real action and grant one reward per account, with a backend check that the inviter and the new user are different people.

### How do I limit emulator and device-farm abuse?

Make fake installs unprofitable. Delay the reward until a real action, cap rewards per inviter, and watch the Referrals report for links with many credits and few qualifying actions. Each credit carries its match method, `tapped_at`, `claimed_at`, `outside_window` flag, and installer id to support that review.

### What happens when the same installer is claimed twice?

The second claim returns ignored with a duplicate_of field naming the referral that holds the credit. No second webhook is sent, so one installer pays out once.

### What is the best single defense against referral abuse?

Delay the reward until the new user completes a real action, such as a first purchase or a week of use. Fake accounts rarely survive a meaningful action, and the delay costs honest users almost nothing.

## Related Guides

- **Reference:** [Referrals](https://warplink.app/docs/guides/referrals) and [rewards recipes](https://warplink.app/docs/guides/referrals/rewards).
- **Webhook checks:** [Verify a referral before you grant the reward](https://warplink.app/blog/verify-referral-before-reward).
- **Rules:** [App Store and Google Play referral reward rules](https://warplink.app/blog/app-store-referral-rewards-rules).
- **Build it:** [Build an invite friends feature](https://warplink.app/blog/invite-friends-feature-mobile-app) and [subscription app referral reward](https://warplink.app/blog/subscription-app-referral-reward).
- **Use cases:** [App referral programs](https://warplink.app/use-cases/app-referral-programs).

## How WarpLink Helps

We hand you the facts a reward decision needs: the match method, whether it was exact, the credit window, a single credit per installer, and a signed event your backend can trust. The decision stays in your code, where your product knowledge lives.

One workflow, three pillars. Deep linking carries the invitation, install attribution credits the link that produced the new user, and real-time analytics shows referrals beside every other link. Sub-10ms redirects on the way in, one SDK on the way out.

[Create a free WarpLink account](https://dash.warplink.app/auth/signup) and get deep linking, install attribution, and real-time analytics in one SDK, with 10,000 clicks a month on the free plan.
