What is multi-accounting?
Multi-accounting is the practice of one individual creating and operating several accounts on a service that intends one account per person, usually to claim a per-customer reward more than once, evade a limit, or coordinate activity that should come from separate users. The accounts look independent on the surface but share underlying hardware or network signals.How ShieldLabs surfaces it
ShieldLabs derives a durable DeviceID for every session — server-derived from the browser environment rather than stored, so it cannot be reset by clearing cookies, opening incognito, or rotating IPs. Every naive identifier a person can reset, they do reset: a cleared cookie mints a freshcookie_id and visitor_id, a VPN or proxy hands them a new public IP, an incognito window looks like a first-time visitor. Counting on any of those just counts the disguises; the DeviceID holds steady underneath, so the account-linking below rests on it.
Multi-accounting works across two timescales, so it uses both halves of the product:
- Per session, the Risk Score (0–100) and its signals tell you whether this one session is masked. The tells that ride along with farming are the anonymity and consistency signals — VPN, Proxy, Tor, Privacy Relay, Browser VPN/Proxy, Datacenter IP, Abuser Flag, plus OS Mismatch, Timezone Mismatch, and environment tells like Anti-detect Browser and JavaScript Disabled. Each can be innocent in isolation, so treat them as weight, not proof.
- Across sessions, the dashboard Patterns count the relationships the score cannot see in a single request: Many Accounts on One Device (the classic shape, keyed on the durable DeviceID), Many Accounts on One Local IP (the farm behind one router or NAT, even when each session uses a fresh cookie and a different public IP), and Changing IDs on One Account (a person cycling devices and visitor IDs to look fresh).
Patterns are a dashboard-only feature, graded Suspicious then Dangerous over a rolling window. They are not part of the webhook payload or any API field; you read them on the dashboard Patterns tab or its CSV/JSON export. An entity below the Suspicious threshold is the unflagged baseline and is never recorded.
Prevent multi-accounting
Read two things on the action that matters (signup, the reward or trial claim, a withdrawal): the durable DeviceID, and the count of distinctuser_hid values already seen on it. The rule your code applies is a threshold on that count — when one device carries more accounts than your policy allows, hold the action for verification, and escalate further when the session is also masked. The outcome is that the “different” customers a person spins up collapse back to the one machine behind them. ShieldLabs surfaces the durable id and the per-session Risk Score; your code owns the count, the threshold, and the verdict.
Build it
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.Identify the session
Add the snippet to the authenticated actions where multi-accounting pays off: account creation, the reward or trial claim, a withdrawal, a vote. Re-identify on the action so you score the live session, and pass the account’s hashed id, never a raw email.
account-action.html
Read the scored webhook on your server
ShieldLabs scores the identification and posts the result to your endpoint — the canonical fields are
request_id, device_id, visitor_id, user_hid, public_ip, local_ip, score, signals, and detection_flags (full schema in the webhook reference). Verify X-Shield-Signature on the raw body, respond fast, and cache the result by request_id with the shared waitForScore helper. If a webhook is ever missed, that helper falls back to a History API read by request_id.A multi-accounting-shaped webhook
Link accounts by the durable DeviceID
None of the signals say “multi-accounting” — they tell you a single session is masked. The account-linking is yours: count the distinct
user_hid values that have appeared on one device_id across History, and use the per-session score only to escalate a session that is both masked and on an already-crowded device.api/account-action.js
Read the device's account history
A single History read returns at most 100 rows (the
limit cap), newest first, so a one-page read can undercount a heavily farmed device. For high-traffic devices, paginate with offset, or — cleaner — upsert the user_hid into a per-device set in your own datastore as each webhook arrives. The dashboard Many Accounts on One Device Pattern counts over the full rolling window server-side and is the complement when you do not want to paginate. History reads through account.shieldlabs.ai are free.Catch what spans browsers: link on the local network
A person using several genuinely separate browsers shows up as several devices. The Many Accounts on One Local IP Pattern catches what shares a network but not a browser. The webhook carries two IPs:
public_ip is the public IP a VPN or proxy fakes freely, while local_ip is the visitor’s real local network address behind the mask. When their countries disagree, detection_flags.ip_mismatch is set to true — informational only, surfaced for your code, and it does not change the Risk Score (a raw difference can be benign, since mobile networks often route over different paths). The durable link here is the constant local_ip.ip, not the flag: for the farm behind one router or NAT, the public IP rotates every session but local_ip.ip stays constant, so you can correlate accounts on it straight from the webhook.Tune to your product
A high score or a shared device is not a fraud verdict on its own — a family on one shared laptop, a shared office network, or a privacy browser can all produce these shapes. Decide on the account count plus the score plus your own context, start in a logging-only mode, and raise friction only where the data justifies it.
Test it
You do not need a real farm to confirm the link holds. Create or sign in to one account in your normal browser and note thedevice_id on the webhook. Then act as a fraudster would: clear cookies, open a private/incognito window, or switch to a second browser profile, and act again as a different account. The cookie_id and visitor_id change every time, but the same device_id returns, and the distinct-user_hid count off that device climbs with each run — exactly the count step 4 gates on. Toggling a VPN or proxy adds the matching anonymity signals to the session score without changing the durable DeviceID.
Recommended starting policy
A guide, not a rule. Layer the conditions: real multi-accounting trips more than one, and friction should rise as they stack.| Signal at the action | Suggested action |
|---|---|
| One account on the DeviceID, Clean / Low score | Allow |
| One account on the DeviceID, Medium score | Allow, log and watch the device |
| One account on the DeviceID, High score | Require verification before continuing |
| Device or local IP flagged Suspicious (Many Accounts on One Device / Local IP) | Require verification, regardless of the session score |
| Device or local IP flagged Dangerous | Hold and route to review |
| All-zero DeviceID (JS-disabled or blocked, score 90+) | Decide on the score alone, skip the link count |
Next
New Account Fraud
The create-time gate: join accounts to the DeviceID at registration to thin the farm before it acts.
Promo Abuse
The reward-time gate: count accounts behind one device at redemption to stop bonus and free-trial farming.
Bonus Abuse
Repeat signup and deposit bonuses claimed through duplicate accounts on one device.
Loyalty Fraud
Points and tier rewards farmed across many linked identities instead of genuine activity.