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, each with a new email, a new cookie, often a private window and a rotated IP, and claiming the same bonus from each one. They look like several new players, but the accounts trace back to one Device ID 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 ties each bonus claim to the account behind it and to the devices, visitors and IPs that account is linked to. The Device ID holds through cleared cookies, incognito mode and IP changes, so a hunter who clears cookies, opens a private window and rotates VPN exits between accounts still lands on one Device ID with many linked accounts. Counting cookies or public IPs lets the farm right through; the Device ID holds steady underneath and shows how many “new” players actually share one machine. Each claim is also one identification with a Risk Score from 0 to 100. When a hunter masks the connection, the risk signals fire, and the Local IP (local_ip), the address the browser itself reports, can differ from the public IP behind a VPN or proxy and expose the network behind the exits they rotate. When the two addresses differ, detection_flags.ip_mismatch is true (informational: it does not change the Risk Score, and it can be benign on mobile networks). Across accounts, ShieldLabs detects Multi-accounting on your users directly: several accounts run by one person, linked through the devices and network they share. Each detection carries Medium or High confidence, depending on the combination of evidence, on its own axis next to the Risk Score, so an account can be Trusted on every identification and still be multi-accounting. High-Risk Events are available in the analytics dashboard, the API and webhooks, and need the hashed User HID you pass with checkAuthenticatedUser. When a Multi-accounting event arrives for an account through the API or webhooks, or when you review it in the analytics dashboard, record it against the account in your own system so its next claim goes to verification. On Overview, the Users and High-Risk Events panels count the users with each event at Medium and High confidence for the selected period, and each event tile opens Analytics with that event as a filter; switch to the Users tab to list the users who have it. Investigate a risky user walks through the review.
The Users and High-Risk Events panels of the analytics dashboard: 1,240 users split into 1,090 Trusted, 104 Risky users and 46 High-Risk Event users; Multi-accounting 22 users (14 Medium, 8 High confidence), Account sharing 12 (8 Medium, 4 High), Impossible travel 7 (5 Medium, 2 High) and Account takeover 5 (3 Medium, 2 High).The Users and High-Risk Events panels of the analytics dashboard in the dark theme: 1,240 users split into 1,090 Trusted, 104 Risky users and 46 High-Risk Event users; Multi-accounting 22 users (14 Medium, 8 High confidence), Account sharing 12 (8 Medium, 4 High), Impossible travel 7 (5 Medium, 2 High) and Account takeover 5 (3 Medium, 2 High).

Users and High-Risk Events on the Overview screen of the analytics dashboard, counted for the users active in the selected period.

Stop bonus abuse

The claim policy, wired up in the steps below: read the account, the claim’s risk_score and named signals, and the number of distinct accounts behind the Device ID (History API) and behind the Local IP (your own webhook store). Then:
  • Credit the bonus when the claim and the account are clean and the device is fresh.
  • Hold it for verification when the claim carries strong risk signals, when the device crosses your per-customer cap, or when the account has a Multi-accounting event.
The outcome: a hunter who clears cookies, opens a private window and rotates VPN exits still resolves to one Device ID and often one Local IP, so the bonus pauses for review instead of paying out, while a genuine new player goes through. ShieldLabs stops bonus abuse by linking the accounts and scoring each claim.

Build it

1

Create a ShieldLabs account and get your keys

Start Free with 5,000 identifications, one time, no credit card, or log in. In the analytics dashboard, add the domain you want to protect under Integration > Domains, then open Integration > API keys and copy its keys with the copy button next to each. The Public Key loads the snippet in the browser. Keep the server credentials on your backend: the Private API Key reads the History API, and each webhook endpoint has its own whsec_… signing secret. See API keys and Integration.
2

Identify the claim

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. Pass a hashed User HID with checkAuthenticatedUser on every signed-in page. Users, account-level risk and all four High-Risk Events are built on it. Within one visit (while a page of your site stays open in the browser, across route changes in a single-page app and across open tabs), checkAnonymous and checkAuthenticatedUser run at most one identification every five minutes for the same user. A call inside that window posts nothing, counts nothing, and its onInitialized handler receives { status: "not_initialized" }. On a multi-page site, a full page load in the only open tab can start a new visit with its own identification. So for the claim itself, call forceCheckAuthenticatedUser when the user starts filling the claim form (its first focus), or when the page opens if the claim is a single button: it runs an identification every time, keeps the current Session ID and restarts the five-minute window, so you always get a request ID for the claim (see Identify signed-in users). onInitialized fires when the check starts, before the snippet has sent the identification, so do not navigate away inside it: store the request ID and let the form submit normally. Pass the account’s hashed id, never a raw email.
claim-bonus.html
3

Read the scored result on your server

The Risk 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, which falls back to a History API read by request_id. The fields that matter are user_hid, device_id, risk_score, signals, detection_flags, and the two IPs: public_ip and local_ip, the address the browser reports:
The webhook data your handler caches
4

Read the account behind the claim

The claim is one identification. The account behind it has a history. The shared accountView helper reads the account’s earlier identifications from the History API by user_hid: the worst band across them shows how risky the account has been, and its distinct Device IDs and public IPs are the devices and networks it is linked to. An account whose worst band is Dangerous goes to verification before the bonus, and so does an account with a Multi-accounting event, recorded in your own system when it arrives through the API or webhooks or when you review it in the analytics dashboard. The handler in the next step reads both.In the analytics dashboard, the account’s card shows the same view: its band for the selected period, its High-Risk Events, each pill coloured by its confidence, and each linked device, visitor and IP with the band of the identifications it shares with the account. User, device, visitor and IP cards describes each part.
5

Count the accounts behind the device and decide

This is where you choose the action. For a live check, link the related accounts on the durable device_id: the shared accountsBehindDevice helper reads the History API by device_id and counts the distinct accounts it has touched, leaving out "anonymous". Combine that count with the claim’s Risk Score and the account, then decide grant, verify or deny.
api/claim-bonus.js
accountsBehindDevice wraps the History API read keyed by device_id. The underlying call:
Read a device's claim history
A person using several separate browsers shows up as several devices: another browser is another Device ID. The Multi-accounting High-Risk Event closes that gap: it links accounts run by one person through the devices and network they share. When the event arrives for an account through the API or webhooks, or when you review it in the analytics dashboard, act on the account (you choose the action for each case); reserve live device_id reads for the borderline, high-value claims. For the network shape at claim time, keep your own count of accounts per local_ip.ip from the webhook, since the History API has no Local IP search. History API reads never count against your included identifications.The analytics dashboard shows the same count: open a Device ID from Analytics, and Linked accounts lists every account that claimed from it, each with the band of its identifications on that device.
The device card for Device ID d290f1ee-6c54-4b01-90e6-d701748f0851 in the analytics dashboard: band Dangerous, 14 identifications, and Linked accounts open with 6 accounts: 3 Dangerous, 1 Suspicious and 2 Trusted.The device card for Device ID d290f1ee-6c54-4b01-90e6-d701748f0851 in the analytics dashboard in the dark theme: band Dangerous, 14 identifications, and Linked accounts open with 6 accounts: 3 Dangerous, 1 Suspicious and 2 Trusted.

One Device ID in the analytics dashboard, with every account linked to it.

6

Decide and tune

Verify rather than deny on the Risk 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 your limits.

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 or open a private window, 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-account count on that device climbs with each claim, which is exactly the count your handler gates on. A second browser gets its own Device ID; the network the accounts share can still link them. Toggling a VPN or switching networks adds the matching risk signals to the claim without changing the Device ID. Then search Analytics in the analytics dashboard for that Device ID and open it: Linked accounts lists every account you used in the test, each with the band of its identifications on that device. A guide, not a rule. Layer the Risk Score with the account and the device 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 Device ID.

New Account Fraud

Thin the farm at registration before it ever reaches the bonus, by joining each new account to its Device ID.
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 Device ID holds through a cookie clear, Risk signals lists every risk signal that can ride on a masked claim, Risk Scoring defines the 0-100 Risk Score and its bands, High-Risk Events covers Multi-accounting and the other events detected on your users. Webhooks gives the exact payload your handler reads.