What is loyalty fraud?
Loyalty fraud is the gaming of a rewards or membership program — farming points, tiers, or member perks through multiple linked identities rather than real activity. One person runs several accounts to multiply signup bonuses, stack referral credit between their own profiles, or push a single identity into a higher reward tier than its genuine activity earns.How ShieldLabs surfaces it
ShieldLabs resolves each session to a set of identifiers and grades how many accounts cluster on one device or network. Four layers answer four different questions:| Layer | What it answers | Where you read it | Latency |
|---|---|---|---|
| Identification | ”Is this the same device, even after cleared cookies, incognito, or a new IP?” | The durable device_id on the webhook / History API | About a second |
| Anonymity detection | ”Is this earning or redemption masked or anonymous right now?” | The signals array on the webhook / History API | About a second |
| Risk Score | ”How risky is the visit overall, as one 0-100 number?” | risk_score on the webhook / History API | About a second |
| Patterns | ”How many members already cluster on this device or local IP?” | Dashboard Patterns + export | Background (~10 min) |
local_ip) still exposes the local network behind the mask, so accounts that rotate their public IP still group on one Local IP.
Prevent loyalty fraud
The rule your code applies: read the durabledevice_id and your own user_hid on every earning and redemption action, and read local_ip.ip for the local-network case. Count the distinct user_hid values behind one device_id (and behind one local_ip.ip), and when that count crosses your per-program limit, hold the perk for verification or deny it instead of paying the reward again. Weigh in the session Risk Score (0–100) and the detection_flags: a masked session reusing one device is the farm tell, while a clean, single-account device earns and redeems with no friction. When a farm masks its public IP, public_ip and local_ip disagree, so detection_flags.ip_mismatch is set to true (surfaced for your code; it does not change the score). ShieldLabs surfaces the count and the score; your earning and redemption handlers own the verdict. The steps below wire it up.
Build it
Identify on the action
Add the snippet to the page where points are earned or a perk is claimed, and re-identify on the action itself so you score the live session. Pass the member’s hashed account id (UserHID), never a raw email.
claim-reward.html
Read the scored result on the server
The scored result arrives by webhook —
request_id, device_id, visitor_id, user_hid, score, signals, detection_flags, scored_at. Cache it by request_id and read it back with the shared waitForScore helper, or fall back to a History API read by request_id. Because the durable device_id is the grouping key, you also read the account’s neighbours: how many distinct accounts that one device has already touched.The accounts behind one device
Count the accounts behind the device and decide
The verdict combines the session’s anonymity with the account count behind the device. A masked session alone can be a real member on a corporate VPN; many accounts redeeming from one durable DeviceID is the farm shape no single genuine member ever shows.
api/loyalty/redeem.js
See the spread over time
The per-session check catches a redemption right now. The standing view is Patterns, graded server-side over a rolling window and exported as CSV or JSON.
Many Accounts on One Device
Many Accounts on One Device
One device linked to many distinct accounts: the core farming shape. The grouping identity is the durable DeviceID. It grades Suspicious, then Dangerous, as the account count climbs.
Many Accounts on One Local IP
Many Accounts on One Local IP
Many accounts earning or redeeming through the same local network, even when each rotates its public IP. Catches a person spread across several browsers behind one router.
Many Devices on One Account
Many Devices on One Account
One member worked from a string of machines — the tier or status-abuse shape, where a single identity is pushed up by activity across many devices.
History reads through
account.shieldlabs.ai are free. For high-volume earning flows, use the Patterns export as your denylist of farm devices and local IPs, and reserve live device_id reads for the perks that are expensive to give away by mistake.Tune to your program
Start in logging-only mode, watch how real members distribute, then set your limits and raise friction as conditions stack. A real member on a corporate proxy or privacy browser can land in the High band, so decide on the score plus the
detection_flags plus the account count plus your own context, never the number alone.Test it
You do not need a real farm to see this work. Redeem a perk once in your normal browser and note thedevice_id on the webhook. Then play the farmer: clear cookies, open a private window, or switch to a second browser profile, and redeem again as a different member. The cookie_id and visitor_id change each time, but the same device_id returns, and the distinct-user_hid count off that device climbs with each run. Toggling a VPN lights up the anonymity signals and flips the matching detection_flags, all without changing the durable DeviceID.
Recommended starting policy
A guide, not a rule. Layer the conditions: a loyalty farm trips more than one, and friction should rise as they stack.| Signal at earning or redemption | Suggested action |
|---|---|
| Clean / Low score, one account on the device | Award the reward |
| Medium score, one account on the device | Award, but log and watch the device |
| High score | Require verification before granting |
| Many accounts on the device or local IP (over your limit) | Require verification, regardless of session score |
| Device or local IP flagged Suspicious in the Patterns export | Require verification |
| Device or local IP flagged Dangerous | Deny the perk and route to review |
| All-zero DeviceID, JavaScript-disabled visit (score 90+) | Decide on the score alone, skip the account count |
| All-zero DeviceID, snippet blocked (no score reached the server) | Fall back to the History API, treat as unverifiable, route to review |
Next
Stop Multi-Accounting
Loyalty farming is a special case of one person running many accounts.
Promo Abuse
The reward-time gate for one-per-customer signup bonuses, coupons, and credits.
Referral Abuse via Sybils
When the linked identities exist to farm referral credit between each other.
Patterns
The dashboard view that grades many-accounts-on-one-device across all members.