Skip to main content
A signup or deposit bonus is meant to be claimed once per real person. Bonus hunters get around that by spinning up a string of fresh accounts — new email, new cookie, often a private window and a rotated IP — and claiming the same bonus from each one. On the wire that looks like several “different” customers, but the bonus-claim sessions trace back to one DeviceID you have seen before.

What is bonus abuse?

Bonus abuse is the repeated claiming of a per-customer promotion — a signup bonus, a deposit-match, or free credit — through duplicate accounts that pretend to be new players. It is common in iGaming and rewards programs, where the bonus has direct cash value and one person can profitably farm dozens of accounts.

How ShieldLabs surfaces it

ShieldLabs resolves each claim to a set of identifiers: the per-claim RequestID, the cookie-scoped VisitorID, your hashed UserHID for the account, and the durable, server-derived DeviceID that survives a cookie clear, incognito, and IP rotation. A hunter clears cookies, opens a private window, and rotates VPN IPs between accounts precisely so each claim looks new, so counting cookies or public IPs lets the farm right through. The DeviceID holds steady underneath and lets your code see how many “new” players actually share one machine. ShieldLabs also returns a per-request Risk Score (0–100). When a hunter masks the connection, the anonymity signals fire, and the real network IP (local_ip.ip) can reveal the network behind the public public_ip.ip they rotate. When their countries disagree, detection_flags.ip_mismatch is set to true (informational only, surfaced for your code; it does not change the score, and can be benign on mobile networks). The durable tell is the constant local_ip itself, the Local IP the patterns correlate on, so a farm rotating VPN exits still collapses to one local_ip. The dashboard grades the relationship over time with the Many Accounts on One Device and Many Accounts on One Local IP patterns; your claim code enforces your per-customer policy.

Stop bonus abuse

The rule your code applies, wired up in ## Build it below: read the claim session’s score and its signals breakdown for masking, and read the durable DeviceID plus the real network IP (local_ip.ip) to count how many distinct UserHID accounts have already claimed off that one machine or local network. Then:
  • Credit the bonus when the score is low and the device is fresh.
  • Hold it for verification when the claim is masked, when the Many Accounts on One Device or Many Accounts on One Local IP pattern flags the entity, or when the live account count crosses your per-customer cap.
The outcome: a hunter who clears cookies, opens a private window, and rotates VPN exits still resolves to one DeviceID and one local_ip, so the bonus pauses for review instead of paying out, while a genuine new player goes through.

Build it

1

Create a ShieldLabs account and get your keys

Sign up for free and get 5,000 identifications, or log in if you already have an account. Register the domain you want to identify visitors on, then open the Keys page. Use the Public Key to initialize the snippet in the browser, and keep your server-side credentials on your backend: the Private API Key authenticates the History API, and each webhook endpoint has its own whsec_… signing secret. See Keys.
2

Identify the claim session

Add the snippet to the page where the bonus is claimed — the “claim bonus” button, the deposit form with a bonus code, the welcome-offer screen. Re-identify on the action so you score the session that is actually claiming, not a stale page load. Pass the account’s hashed id, never a raw email. Use forceCheckAuthenticatedUser here (not checkAuthenticatedUser): a bonus claim is a sensitive, value-bearing action, so resetting the visit session first gives you a fresh score keyed to a requestID you can act on, per the snippet methods.
claim-bonus.html
3

Read the scored result on your server

The score arrives on the webhook. Verify the X-Shield-Signature HMAC, then cache it by request_id. Your claim endpoint reads it back with the shared waitForScore helper from the Use Case Tutorials, or falls back to a History API read by request_id. The fields that matter are device_id, user_hid, score, signals, detection_flags, and the two IPs — public_ip (public, VPN-fakeable) and local_ip (the live equivalent of the Local IP behind the Many Accounts on One Local IP pattern):
the webhook your handler caches
4

Count the accounts behind the device and decide

This is where your code owns the verdict. Link the related accounts on the durable device_id: read the History API by device_id and count the distinct user_hid values it has touched — that count is the number of accounts behind the machine. Combine it with the session score, then decide grant, verify, or deny.
api/claim-bonus.js
shieldlabsHistory is the shared History API read from the Use Case Tutorials, here keyed by device_id. The underlying call:
Read a device's claim history
A determined hunter using several genuinely separate browsers shows up as several devices, since the DeviceID is browser-bound. The Many Accounts on One Local IP pattern closes that gap: ten accounts claiming through one local IP is a strong shape even when each reports a different device. Use the pre-computed pattern export as a fast denylist; reserve live device_id reads for the borderline, high-value claims.
5

Decide and tune

Verify, do not hard-deny on the score alone — a real new player on a corporate VPN, a privacy browser, or a shared household network can score high or share a device with a relative. Holding a suspicious claim for a quick verification step keeps the genuine player in while still stopping the farm. Start in logging-only mode, watch how real claims distribute, then tune against your own traffic before you tighten thresholds.

Test it

You do not need a real farm to see this hold. Claim the bonus once in your normal browser and note the device_id on the webhook. Then play the hunter: clear cookies, open a private/incognito window, or switch to a second browser profile, and claim again as a different account. The cookie_id and visitor_id change on each run, but the same device_id returns, and the distinct-user_hid count off that device climbs with each claim — which is exactly the count your handler gates on. Toggling a VPN or switching networks should also light up the anonymity signals on the claiming session without changing the durable DeviceID. A guide, not a rule. Layer the score with the account count and tune against your own traffic.

Next

Promo Abuse

The sibling reward gate: coupons, referral credit, and trial resets claimed once per customer, counted off the same durable DeviceID.

New Account Fraud

Thin the farm at registration before it ever reaches the bonus, by joining each new account to its DeviceID.
Wire the signup tutorial for the create-account moment and treat this page as the bonus-time gate on top of it. For the mechanics underneath: Identifiers explains why the DeviceID survives a cookie clear, Anonymity signals lists every signal that can ride on a masked claim, Risk Scoring defines the 0-100 score and its bands, Patterns covers the dashboard relationship grading, and Webhooks gives the exact payload your handler reads.