---
title: "Affiliate Fraud in Mobile Apps: What Actually Stops It"
description: "Affiliate fraud in mobile apps is a race against the reversal. What a 14 day hold stops, what it misses, and the contract clauses that let you act."
canonical: https://www.myappaffiliate.com/blog/affiliate-fraud-subscription-apps
published: 2026-09-15
author: "Cuma Ali Kesici"
category: "Attribution"
tags: [iOS, Android, RevenueCat, Payouts]
source: MyAppAffiliate
---

# Affiliate Fraud in Mobile Apps: What Actually Stops It

Affiliate fraud in mobile apps is a timing attack. Subscription revenue arrives over months and can be taken back at any point in them, so the attacker's whole job is to get a commission paid before the reversal catches up. Self-referral, trial farming and refund cycling are the same move at different speeds. What defeats them is rarely detection. It is the hold period, the commission basis, and a contract that lets you stop.

Below: what each pattern looks like in a ledger, a refund cycle worked against a 14 day hold, a table of what stops what, and the clauses without which you can do nothing. We ship no fraud detection, and this is specific about where that leaves you.

## Key takeaways

- Subscription fraud is a race between your payout date and the customer's refund.
- A hold period stops reversals that land inside it, and nothing else.
- Self-referral is the common pattern and the one first-party matching cannot see.
- Pay on money received and trial farming earns the attacker nothing.
- We ship no fraud detection: no self-referral check, no velocity rule, no blocklist.

## Why a subscription program is defrauded differently

A one-off purchase pays a commission once, against money that has settled. A subscription pays repeatedly, against money that three clocks can still take back. Every pattern here lives in the gap between the clock that pays your creator and the one that reverses the charge.

**The attribution window** decides whether a click may earn at all. Ours defaults to 30 days and is checked against every commissionable event, so a renewal on day 45 of a 30 day window earns nothing. An attacker cares least about this one.

**The hold period** decides when an earned commission becomes payable. In our schema it is `holdPeriodDays` on the app, it defaults to 14, and a commission sits `pending` until it matures. Only matured rows export to a payout. Both are compared in [how attribution windows work](/blog/how-attribution-windows-work).

**The reversal window** decides how long the money can come back, and nobody sets it but the stores. Apple's refund page tells a customer to "Wait 24 to 48 hours for an update on your request" and publishes no deadline for making one ([Apple Support](https://support.apple.com/en-us/118223), verified 2026-09-14).

Google tells a buyer to contact the developer once "it's been more than 48 hours since you made the purchase", and to report unauthorized charges "within 120 days of the transaction" ([Google Play Help](https://support.google.com/googleplay/answer/15574897), verified 2026-09-14). Stripe documents that card networks normally allow a dispute within 120 days of payment ([disputes](https://docs.stripe.com/disputes/how-disputes-work), verified 2026-09-14).

![Timeline showing a commission maturing at 14 days against refund windows that stay open far longer](https://www.myappaffiliate.com/blog-images/affiliate-fraud-subscription-apps/affiliate-fraud-subscription-apps-timing.webp "The payout clock is short and the reversal clock is long. Everything else follows from that.")

**The attacker's target is the space between maturity and reversal, and on the App Store that space has no published end.** We default the hold to 14 days and would raise it to 30 on an app with real refund pressure, which is a judgement about creator patience rather than a measurement. No creator signs a hold long enough to cover a dispute.

## Self-referral produces the cleanest funnel in your dashboard

Self-referral is a creator subscribing through their own link, or arranging for a friend to. In the data it does not look broken. It looks excellent: clicks and installs nearly equal, installs identifying instantly, a purchase minutes after the click. Everything a real audience produces slowly, at once.

It is the most common pattern because it costs the least. No audience, no traffic, no tooling, no second party who might talk. One link and one payment method is the whole setup, which is why it turns up in programs too small for anyone to bother attacking.

Here is the part most vendors will not say. Our matching is first-party and deterministic by design: a hashed IP on the click, a generated device id on the attribution, and an iOS SDK documented as having "No IDFA, no fingerprinting, no cross-app tracking". That is a privacy property we sell, and also a limit on exactly this pattern. Two devices belonging to one person look like two people to us.

What raises the cost is the stores. Apple states that "Customers can redeem one introductory offer per subscription group" ([App Store subscriptions](https://developer.apple.com/app-store/subscriptions/), verified 2026-09-14), and Google Play's offer eligibility criteria include "Never had this subscription" and "Never had any subscription" ([Play Console Help](https://support.google.com/googleplay/android-developer/answer/140504), verified 2026-09-14). Each repeat needs a fresh store account, which is where it gets expensive.

The control that works is written, not computed. Amazon's Associates programme policies say an associate "will not directly or indirectly purchase any Product(s) or take a Bounty Event action through Special Links", for their own use or anyone else's ([programme policies](https://affiliate-program.amazon.com/help/operating/policies), verified 2026-09-14). Copy the structure. We would write the clause before building any check, because a check produces a suspicion and a clause produces a remedy.

## Trial farming only pays if you signed a bounty

Trial farming is volume on trial starts that were never going to convert. Under a conversion-only deal it earns the attacker nothing, because a trial start is a $0 transaction and a percentage of zero is zero. It exists only in programs that agreed to pay per trial, which makes it the one attack you authorise yourself.

RevenueCat delivers a trial as `INITIAL_PURCHASE` with `period_type` of `TRIAL` at a price of 0, and the paid conversion later as a `RENEWAL` carrying `is_trial_conversion`, defined as "Whether the previous period was a free trial" ([event types and fields](https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields), verified 2026-09-14). Our normalizer records the trial as a `trial_start` at zero cents.

Our engine cannot compute a per-trial bounty at all. Commission is `round(amount_usd_cents * rate_bps / 10000)`, so a zero amount returns before a row is written. A bounty here is a manual adjustment on the payout run, which means the exposure is a number a human types. The break-even arithmetic for a capped bounty is in [do affiliates get paid on free trials](/blog/affiliate-commission-free-trials-renewals).

The tell, once you have signed one, is a per-affiliate trial-to-paid rate far below your app median. The commission list carries the event type and affiliate id on every row, so the ratio is computable, and our dashboard does not put it in front of you.

## Refund cycling, worked against a 14 day hold

Refund cycling is buying through your own link, collecting the commission, then having the purchase refunded. The hold decides the outcome. A refund inside it costs nothing, because nothing left your account. A refund after it costs the full commission in cash against zero revenue.

The arithmetic, on a $9.99 monthly plan at 20 percent with a 14 day hold and payouts on the 15th. Each commission is 999 × 2000 / 10000, or 199.8 cents, rounded by our engine to 200. Ten subscriptions open on 1 March.

![A batch of commissions split by whether the refund arrived before or after the hold period expired](https://www.myappaffiliate.com/blog-images/affiliate-fraud-subscription-apps/affiliate-fraud-subscription-apps-hold-window.webp "Six reversals cost nothing and four cost the full commission, decided only by the date.")

| Date | Event | Rows affected | Commission | Cash out |
| --- | --- | --- | --- | --- |
| 1 Mar | 10 × `INITIAL_PURCHASE` at $9.99 | 10 created `pending`, maturing 15 Mar | +$20.00 | $0.00 |
| 8 Mar | 6 refunds, inside the hold | 6 reversed while `pending` | -$12.00 | $0.00 |
| 15 Mar | 4 rows mature, payout runs | 4 exported and marked `paid` | None | $8.00 |
| 10 Apr | 4 refunds, 40 days after purchase | 4 reversed after payment | -$8.00 | $8.00, gone |
| 15 Apr | Next payout run | Balance carries at -$8.00 | None | $0.00 |

*Ten commissions at 200 cents each is $20.00 gross. The hold cancelled $12.00 of it for free. The remaining $8.00 was paid on 15 March and reversed on 10 April, against subscription revenue that refunds returned to $0.00.*

The punchline is the last column. After the refunds the app earned nothing from these ten subscribers, and the only money that actually moved was yours. Netting the $8.00 off a future payout works while the creator is still earning, and otherwise it is a write-off, which is [the clawback policy](/blog/affiliate-clawback-policy-subscription-apps).

Two details make the after-hold half worse than it looks. RevenueCat states that for subscription refunds "this event fires only when the latest subscription period is refunded", so a subscriber refunded across three months may produce one webhook. And our engine header is explicit that there is no clawback in the MVP: the `clawed_back` state exists, the automatic transition into it does not.

## Incentivised traffic is a disclosure problem before it is a payout problem

Incentivised traffic is real people, paid or rewarded to install and subscribe. Nothing in the billing data is fake, which is why no detection rule finds it. The tell is retention: the cohort converts normally and leaves at the first renewal, and renewals are the half a subscription program is buying.

Measure it by counting renewal commissions against first-payment commissions for one affiliate, over a period long enough that a renewal could have happened. Our commission list returns the event type per row, so the ratio is one API query. The dashboard does not break out renewals per affiliate, so this one is yours to run.

The second exposure is not financial. The FTC tells influencers to disclose a material connection and is blunt about placement: a disclosure should be "hard to miss" and "placed with the endorsement message itself" ([Disclosures 101 for Social Media Influencers](https://www.ftc.gov/business-guidance/resources/disclosures-101-social-media-influencers), verified 2026-09-14). An affiliate buying installs is also an endorser not disclosing, and the advertiser is you.

Write that requirement into the agreement with an example of acceptable wording, because "comply with applicable law" is not an instruction a creator can act on. The commission basis does the rest: paying on renewals makes a cohort that churns at month two worth what it deserves.

## A leaked code is attribution theft, and the match method is the tell

A creator's code on a coupon aggregator is not fraud. It is a real code, used by real customers, collecting credit for people who were already going to subscribe. The cost is identical to fraud and the remedy is different: this one is fixed with attribution rules and code hygiene.

Last click inside the window is our default, documented as attributing an event to the most recent referral within the attribution window ([webhook reference](https://docs.myappaffiliate.com/webhooks), verified 2026-09-14). A coupon page that captures the last touch takes the commission, and has broken no rule unless your terms say so.

Every attribution row carries a `matchMethod`, one of `claim_token`, `code`, `play_referrer` or `deferred_ip`. A `code` attribution means someone typed a creator's code; a `claim_token` means a link click carried the token into the app. A creator whose `code` share climbs with no campaign behind it has a code circulating somewhere they are not, which is the earliest signal in our data. The honest limit: `matchMethod` appears in neither the dashboard, the commission list nor the payout CSV, so reading that ratio means querying the database.

Cookie stuffing is the web-side version, and Amazon's definition of a Redirecting Link describes it exactly: a link taking a visitor "indirectly to an Amazon Site via an intermediate site, without requiring the customer to click on a link or take some other affirmative action". Our mobile path has no cookie to stuff, because a claim token arrives through a Universal Link the user tapped. The web half of a hybrid product is exposed like any web program. We record `referrer` and `userAgent` on every click and enforce nothing with either, so a referrer allowlist is a query you write rather than a rule we apply.

## What each control actually stops

**Only one row in this table is stopped by something a platform can do for you, and it is the hold.** Everything else is a commission basis, a contract, or a decision.

| Pattern | What it looks like in the data | What actually stops it |
| --- | --- | --- |
| Self-referral | One affiliate, clicks close to installs, purchase minutes after the click | A written clause and deactivated links. The hold helps only if the refund lands inside it |
| Trial farming | Trial starts far above your median, trial-to-paid far below it | Paying on conversion. A per-trial bounty is the only thing that makes it profitable |
| Refund cycling inside the hold | `pending` commissions reversed before `maturesAt` | The hold, completely. No money left the account |
| Refund cycling after the hold | Refunds clustered on one affiliate's cohort, weeks after a payout | Nothing automatic. A clawback clause plus a future balance to net against |
| Chargeback cycling on web billing | Disputes arriving up to 120 days after payment | No hold you would offer a creator. The clawback policy and the dispute response |
| Incentivised traffic | Normal first payments, renewal rate far below your median | A renewal-weighted commission and a written rule. Detection finds nothing |
| Leaked code on a coupon site | `matchMethod` of `code` rising with no campaign behind it | Per-placement codes, expiry, and not printing a code where a scraper reads it |
| Last-click hijack on the web half | Clicks with no plausible referrer, seconds before a purchase | Referrer rules you write yourself. We store `referrer` and act on none of it |

*Store and network timings checked against Apple, Google Play and Stripe documentation on 2026-09-14. Field names are from our own schema.*

Read the right-hand column as a build order. A conversion-only basis, a 14 day hold and a self-referral clause close more of this table than a detection module and a bounty.

## The three clauses without which you cannot act

An affiliate agreement is the only enforcement tool you own outright. Three clauses carry the weight: what counts as a qualifying referral, that a self-referral is not one, and that you may pause a payout while you review it. Without the third, withholding money is your breach rather than theirs.

> **Warning:** Starting text for your lawyer, not legal advice. Nobody has reviewed it, it makes no allowance for your jurisdiction, and the review period is a default to change.

```
Qualifying referrals and review

1. A qualifying referral is a paid subscription started by a customer who
   reached the app through your link or code, inside the attribution window,
   and who was not induced to subscribe by any payment, reward, sweepstake
   entry or other consideration offered by you.

2. You may not earn commission on a subscription purchased by you, by a
   member of your household, or by anyone acting at your request. Purchases
   that breach this clause earn no commission and may be reversed at any
   time, including after payment.

3. We may hold a payout for up to 14 days while we review the traffic behind
   it, and we will tell you in writing on the day we do, with the figures we
   are reviewing. If we do not reach a decision in that time, the payout is
   released.
```

Clause 3 is the one founders leave out and then need at three in the morning. Clause 1 is where you name incentivised traffic, and being concrete beats "fraudulent or artificial traffic", which describes nothing a creator can check themselves against. Payout mechanics sit in [the commissions and payouts guide](/blog/affiliate-commissions-payouts-subscriptions).

## What to do when a signal fires

Nothing in our product fires a signal for you, so this begins with you noticing. A creator whose numbers do not match their audience is the usual entry point. Run these in order, stopping as soon as the ratios come back ordinary.

1. Pull the affiliate's funnel and compare three ratios to your app median: clicks to installs, installs to first payment, first payments to renewals.
2. List their commissions by event type over 90 days and count refunds against purchases in the same cohort.
3. Check the match method mix on their attributions, which today means a database query rather than a page.
4. Check the timing: clicks and purchases inside the same minute, repeatedly, is a person rather than a campaign.
5. Deactivate the links rather than the creator. `Link.active` is what our click path checks, and an `Affiliate.status` of `paused` is a label the money path never reads, so pausing the creator alone changes nothing.
6. Skip that affiliate's payout run. Our export pays every matured commission for an affiliate with no partial withhold, so declining to run it is the only action available.
7. Write to the creator with the figures and a date by which you will decide. Send the numbers, not the accusation.

Step 5 is a gap you should hear here rather than discover. Payout mechanics are in [affiliate payout automation](/blog/affiliate-payout-automation).

## What we would not build

The tempting build order puts a detection module first. We would put it last, and parts of it never, because every item below spends something certain on something speculative.

Not fingerprinting or an advertising id to link accounts. It contradicts what our SDKs document, drags the ATT prompt into a product that does not need one, and the store offer-eligibility rules already tax the repeat trials it would catch.

Not a velocity threshold before you have your own distribution. A rule calibrated on somebody else's number fires on your best creator's launch day, and those two errors do not cost the same.

Not a 120 day hold to cover chargebacks. It covers them and loses every creator who can read a calendar.

Not an automatic ban. A wrong reversal ends a partnership; a late one costs a commission. Keep the decision with a person while the volume allows.

## Where MyAppAffiliate fits

MyAppAffiliate is an affiliate and creator attribution platform for subscription mobile apps and SaaS. On this subject the honest statement is short: we do not ship fraud detection. No self-referral check, no velocity rule, no blocklist, no risk score, in the engine or the schema. A `fraudModule` flag exists in our entitlement types and our pricing table deliberately leaves the row out, because a feature nobody can buy should not sit on a price list.

What ships: a per-app hold period, an attribution window checked against every commissionable event, a `matchMethod` on every attribution, refund normalization from five billing providers into a `clawed_back` commission state, per-affiliate funnel counts, and CSV payout export on every plan including Free. Attribution is first-party with no advertising id, and pricing is flat rather than [a percentage of your revenue](/blog/why-flat-pricing-no-revenue-share). The reversal itself is out of band today.

## Write the self-referral clause this week

Open your affiliate terms and add clause 2 above, in your own words, before the program is large enough to be worth attacking. Then run one query: the refund rate on each affiliate's cohort over the last 90 days, next to your app median. With those two in place the rest of this post is reading rather than a plan. Starting from nothing, the setup order is in [how to start an affiliate program for an iOS app](/blog/start-affiliate-program-ios-app).

## FAQ

### How do you detect affiliate fraud in a mobile app?

Mostly by ratio, not by rule. Compare one affiliate's clicks to installs, installs to first payment, and first payments to renewals against your app median, then look at the refund rate on their cohort. A number far outside your own distribution is the signal. Nothing automatic fires it for you.

### Does a hold period stop affiliate fraud?

It stops one thing completely: a reversal that arrives before the commission matures, which costs you nothing because no money left. It does nothing about a refund after payout, a chargeback up to 120 days later, or incentivised traffic that never refunds at all. Treat it as timing, not detection.

### How do you catch self-referral without device fingerprinting?

You mostly do not, and that is the honest trade. First-party matching with no advertising id cannot tell two devices belonging to one person from two people. What you get instead is a contract clause, the store limit of one introductory offer per subscription group, and the refund rate on that affiliate's cohort.

### Should you pay affiliates per install or per subscription?

Per subscription. An install bounty and a trial bounty both pay before any money exists, which is the only condition under which farming volume is profitable. Paying a percentage of what the store actually charged means a fake customer earns the attacker nothing, and a refunded one reverses.

### Can you withhold an affiliate payout you believe is fraudulent?

Only if the agreement says so before the balance exists. Write a clause giving you a stated number of days to review a payout and a right to reverse commissions on traffic that breaches the terms. Without it, holding money is your breach rather than theirs.
