Anti-fraud
signals, limits, review.
3.1 adds device reports, an accounts-per-device limit, a points-per-hour velocity rule and a manual review queue. They are on top of the 3.0 protection: server-only crediting, signed callbacks, caps, rate limits and App Check. They flag accounts for you to review and decide nothing on their own, with one exception for emulators.
01What protects the points
- Since 3.0: every credit is written by the server, rewarded ads only after the network's signed callback, with daily caps, cooldowns, per-user rate limits, App Check and fraud flags for callback mismatches (Built-in protection).
- New in 3.1: the device report, the device limit, the velocity rule, offerwall holds and the Review queue, all below.
02Device report signals and their limits
On every sign-in, and whenever the push token changes, the app calls reportDevice (app/lib/core/device_signals_io.dart, firebase/functions/src/callables/device.ts). The server stores users/{uid}/devices/{hash} and the list of accounts per device in devices/{hash}.
| Signal | How the app gets it | Limits |
|---|---|---|
| Device id hash | SHA-256 of the iOS identifierForVendor. On Android and web: SHA-256 of a random id created on first launch and stored on the device. | The raw id never leaves the device. On Android, clearing app data or reinstalling creates a new id, so the device limit can be bypassed that way. On iOS the id changes after all apps of the vendor are removed. |
| Emulator | isPhysicalDevice from device_info_plus | Reliable for standard emulators and simulators. A modified emulator can claim to be physical. |
| Root / jailbreak | Android: su binaries in known paths or test-keys build tags. iOS: known jailbreak paths. | A heuristic. Root-hiding tools defeat it, and custom ROMs can trigger it without bad intent. |
| VPN | connectivity_plus reports a VPN interface | Many honest users run a VPN or a privacy app. Treat it as context, not as fraud. |
| App Check | Whether the app obtained an App Check token | Stored with the device for your information. It opens no review item. Callables already refuse calls without App Check in production. |
A modified app can send any values. Use the signals to decide what to look at in the review queue, not as proof. The server-side rules (signed callbacks, caps, App Check, velocity) are what really protect the points.
03Anti-fraud settings
Console → Anti-fraud (config/public.fraud).
| Setting | Default | Allowed | What happens |
|---|---|---|---|
| Accounts per device (most) | 3 | 1 to 50 | Each new account beyond this on one device is flagged: a fraud flag (device_limit) and a review item of kind device. |
| Points per hour that open a review | 2000 | 10 to 1000000 | The first time a user's earned points in one UTC hour exceed this, the user is flagged: a fraud flag (velocity) and a review item of kind velocity. Credits are not blocked. |
| Refuse rewarded ads on emulators | off | An emulator report always opens a review item of kind emulator, whether this is on or off. On: devices that report an emulator also cannot start rewarded-ad or rewarded-interstitial sessions (reason emulator_blocked). Other credits (games, check-in, offerwalls and the rest) are not refused. | |
| Flag users on a VPN | on | A VPN report opens a review item of kind vpn. It does not flag the user. | |
| Hold offerwall conversions above (points) | 5000 | 0 to 1000000 | Bigger conversions wait for your approval. 0 = holding is off: every conversion is credited. Conversions of flagged users are always held (details). |
A rooted or jailbroken report always opens a review item of kind root. Each review kind is queued once per user and device.
What "flagged" does
A flagged user keeps earning, but every offerwall and survey conversion of a flagged user is held for review, whatever its size. The Users page shows the "flagged" status. A user stays flagged until you clear their open fraud flags on the Fraud flags page. Approving a review item does not remove the flag.
04Review queue workflow
Console → Review queue. Tabs: Open, Approved, Rejected. Each row shows when, the kind, the uid, the points held (offerwall holds) and the provider or detail.
- Look at the userOpen the uid on the Users page: the ledger shows where the points came from. Many accounts from one device, many points within minutes, or offerwall conversions right after sign-up deserve a closer look.
- ApproveFor an
offerwall_hold, approving makes the Functions triggeronReviewDecisioncredit the held points exactly once, usually within a minute. The ledger row idreview_<id>is the idempotency key. For every other kind, approving just closes the item as fine. - RejectCloses the item, and nothing is credited. Tick ban on reject to ban the user as well. A banned user is refused by every function except account deletion.
- Write a noteThe note goes to the audit log with your decision.
- Clear the flagIf the user is fine, clear their fraud flags on the Fraud flags page so their next offerwall conversions are no longer held.
The console only records the decision (status, note, who, when). The backend pays approved holds. A retried trigger or a lost write cannot pay twice (docs/CONTRACT-3.1.md §10, tests in firebase/functions/test and admin/test/emulator.test.ts).
05Reversal shortfalls
When an offerwall provider reverses a conversion after the user spent the points, the backend debits what is left (never below 0) and opens a fraud flag offerwall_reversal_shortfall with the missing amount. Review those users on the Fraud flags page.