How to stop multi-accounting
Also called: multiaccounting · account farming · duplicate accounts · sockpuppet accounts · one person many accounts
What it costs you
- trending_downWhatever the extra accounts unlock. A free tier claimed twice, a referral bonus paid twice, a first-order discount used twice, extra votes, extra entries.
- trending_downReferral programmes especially. When someone refers themselves, your growth budget becomes a direct payment to one person.
- trending_downYour numbers. User count, retention and conversion are all measuring people who do not exist.
- trending_downFairness. That sounds soft until your real users notice and start posting about it.
How the attack runs
- 01
Work out what a second account is worth
People do this whenever account two gets something account one cannot: a free tier that resets, a referral bonus, a one-per-customer discount, a usage limit, a competition entry.
- 02
Change the things you check
Whatever field you look at, they change. New email, new name, new card if they have to. They are aiming at the checks they know about, which is why publishing your rules makes them cheaper to beat.
- 03
Reuse everything you do not check
Nobody changes what they do not have to. Same computer, same browser, same time zone, same payout account, same daily rhythm. That reuse is where the link lives.
- 04
Run the accounts side by side
Referral abuse needs both accounts alive at the same time. That produces overlapping sessions and near-simultaneous actions that one person genuinely cannot produce.
What does not work
These are the defences most teams try first. They are listed here because trying them and watching them fail is expensive.
One email, one phone, one card per account
Each one costs cents to get around, and each one has innocent collisions. Households share cards. Families share phones. You catch the lazy and annoy the real.
Banning everyone on the same device fingerprint
This is the most common way to hurt innocent users. Shared computers are normal: families, flatmates, libraries, internet cafes, and entire markets where one machine serves a household. Phone fingerprints in particular collide often enough to make a hard ban indefensible.
Banning everyone on the same IP
Mobile carriers put thousands of unrelated people behind one address. Universities and offices do the same. This punishes where somebody lives, not what they did.
One account per household
You cannot see a household, so you cannot enforce this. And two adults at one address are entitled to two accounts on almost any service.
Making people upload ID
It works, and it is a sledgehammer. Signups drop, you are now responsible for storing identity documents, and the legal exposure you just bought is bigger than the abuse you were stopping.
The signals that do
These are the signals that carry weight on multi-accounting, and why each one is the signal rather than the obvious alternative. Not all of them are ours: the ones marked you build this genuinely work and Kaidn does not check them, so you would be wiring them up yourself. Listing those unlabelled would read as a claim we cannot support.
What accounts share, not what they say
Kaidn checks thisTwo accounts with different emails can still share a phone, a device, a payout account, or whoever referred them. Linking on anything shared finds groups that a one-field uniqueness check never will, because the abuser only changed the fields they expected you to check.
The shape of your referral tree
you build thisSelf-referral looks distinctive: short chains, people referring each other back and forth, and referred accounts that go quiet the moment the bonus pays. A referral tree is a network, and abuse looks wrong in the network long before any single account looks wrong.
Two accounts active at the same moment
you build thisOne person can own ten accounts. One person cannot actively use three of them in the same minute on the same device. This is one of the few signals here that is close to unambiguous.
Email addresses that are really one inbox
Kaidn checks thisA plus tag, an extra dot on a provider that ignores dots, or a run of numbered addresses on a domain nobody else uses. Different strings, same mailbox.
Device matches, weighted honestly
Kaidn checks thisDevice reuse is a real signal and it is not proof. Browser fingerprints collide, especially on phones where a default setup is genuinely common. It belongs in the score with a weight, never as a standalone rule that bans people.
Multi-accounting is the abuse most likely to make you punish a real customer. The honest version of the situation is that you usually cannot prove it.
You can show that two accounts are strongly connected. Whether one person controls both, or two flatmates share a laptop, is a judgement call. Any approach that forgets that will eventually ban somebody's mother.
Different fields, same person#
The pattern is always the same. They change the identifiers they think you check, and reuse everything else, because changing things is work and nobody does work they do not have to.
So the accounts have different emails and the same payout account. Different names and the same computer. Different cards and the same person who referred them.
The link is never in the field you made unique. It is in the field you did not think to look at. That is why one-field uniqueness rules fail in a predictable way. They teach the abuser exactly which field to change, and it costs them an afternoon.
Link on what is shared, and weigh it#
Stop asking "is this account a duplicate". Start asking "what is this account connected to, and how strongly".
Not all connections are worth the same:
- A shared payout account is heavy evidence.
- A shared device is moderate evidence and needs context.
- A shared IP on a mobile network is close to no evidence at all.
When several of them point at the same group of accounts at once, the case stops being marginal.
That weighting is the whole difference between a system that finds rings and one that generates false accusations. It is also why every verdict comes back with the checks and what each one counted for. When you disagree with an outcome, you need to see which signal caused it.
What "the same device" should actually mean#
Device is the signal everyone reaches for first, and the one most likely to be wrong. What is usually being compared is a browser fingerprint, and browser fingerprints collide.
On our own production traffic, one iOS Safari fingerprint covers 2.30 different people. A default iPhone really is identical to another default iPhone. The hash is not lying. It just is not an identity.
So we turn that hash into something defensible before scoring it, and carry the uncertainty with it. Three levels:
- A token you handed back. Your server stores the
device_tokenwe return as a first-party cookie and sends it back next visit. Nothing is guessed, we are reading an id we issued. Risk of two people sharing it: 0.01, not zero, because households share browsers. - The fingerprint plus the network it came from. With no token, the identity becomes
h(device_id, asn). We tested what actually separates two strangers holding identical phones, and it is the network. Across 132 colliding fingerprints, splitting by network took them from 5.23 people per key down to 1.45. Splitting by TLS fingerprint fixed one of them. Time zone fixed none. - Neither available. You get a random id that links nothing, instead of a shared key invented from one weak input. An honest blank beats a confident guess.
The level then decides how hard the device signal is allowed to hit. A token you replayed carries full weight on its own. A fingerprint match only carries full weight once three or more accounts agree on the same network, because two unrelated people share a network about ten percent of the time on mobile-heavy traffic. Accounts sharing a fingerprint on different networks stay light, since that is more often a collision than a person. Neither path can reach a block by itself.
That is the difference between a device signal you can defend to an angry user and one you cannot. Full mechanics are in the device identity docs.
Resolve an identity, do not compare a field#
The whole argument above, in one call. What matters is not that the fields differ. It is what they resolve to:
const r = await kaidn.score({ event: "signup", user_id: user.id, ip: req.ip, email: user.email, // r.i.n.g+promo@gmail.com device_id: body.kaidn_device_id, });
{
"verdict": "review",
"score": 58,
"reasons": ["email_reuse", "aliased_address", "device_reuse"],
"checks": [
{
"check": "emailReuse",
"weight": 25,
"reason": "email_reuse",
"message": "This mailbox is behind 4 accounts",
"evidence": { "accountCount": 4 }
},
{
"check": "deviceReuse",
"weight": 18,
"reason": "device_reuse",
"message": "This device is linked to 4 accounts, on different networks",
"evidence": { "accountCount": 4, "sameAsnAccountCount": 1 }
}
],
"device": {
"resolved_id": "d2c1f0a7b93e4d5681ca07f4e2b91d38",
"resolution": "probabilistic",
"resolution_rung": 2,
"collision_risk": 0.21,
"account_count": 4,
"account_count_same_network": 1
}
}Four addresses, one mailbox. That is the finding, and it did not come from comparing strings.
Check the collision risk before you act on a device match#
This is the part most integrations skip and then regret.
collision_risk is the measured chance that one resolved device covers more than one real person.
On iOS Safari with no device token it sits at 0.21. Banning on a bare device match at that
confidence bans ordinary iPhone users:
const deviceOnly = r.reasons.length === 1 && r.reasons[0] === "device_reuse"; const shaky = (r.device?.collision_risk ?? 0) > 0.15; const corroborated = (r.device?.account_count_same_network ?? 0) > 1; if (deviceOnly && shaky && !corroborated) return allowWithFlag(r.event_id); if (r.verdict === "block") return deny(r.reason_text); if (r.verdict === "review") return queueForReview(user.id, r.reasons);
Remember the device and the guessing mostly stops#
The highest-value change here is not a better fingerprint. It is not needing one.
Store the opaque device_token from an earlier response as a first-party cookie and send it back on
the next event. Now the identity is remembered rather than guessed, and collision risk drops to
about 0.01:
// cookie handling is opt-in, because storing a first-party cookie is your // decision to make rather than ours const kaidn = new Kaidn({ apiKey: process.env.KAIDN_API_KEY, cookie: {} }); const r = await kaidn.scoreWithCookie( { event: "signup", user_id: user.id, ip: req.ip, email: user.email, device_id: body.kaidn_device_id }, { cookies: req.headers.cookie, setCookie: (h) => res.append("Set-Cookie", h) } ); // on the return visit: r.device.resolution === "deterministic", resolution_rung === 1
Review beats banning, more often than you would think#
For most services the right answer to a probable duplicate is not a ban. It is to withhold the thing that made the second account worth creating.
Do not pay the referral bonus. Do not grant the second free trial. Do not count the second entry. Let the account use the product normally.
If you are wrong, a real user notices nothing. If you are right, you removed the reward without creating an appeals queue.
Save banning for groups where the evidence is heavy and consistent. Even then, a review step pays for itself the first time it catches a family.
Something to check before you buy anything#
Take your referral programme and look for two things: pairs who referred each other, and accounts that went quiet within a day of a bonus paying out.
That query takes an hour, and it tells you whether you have a multi-accounting problem worth spending money on. That is a better basis for a decision than any vendor demo, ours included.
Frequently asked questions
How do I detect multiple accounts from one person?
Work out what the fields resolve to instead of comparing them. Strip the dots and plus tags off the email and count the real mailbox. Resolve the browser to a device and count the accounts on it. Then check how many of those accounts sit on the same network. Comparing raw values fails straight away, because every field the user controls is free for them to change.
Is device fingerprinting enough on its own?
No, and treating it as proof is the expensive mistake. A browser fingerprint is a hash of settings, and identical phones produce identical hashes. On our own production traffic, one iOS Safari fingerprint covers 2.30 different people. That is why a score returns collision_risk and account_count_same_network next to the count, and why a device match on its own is a reason to look, not a reason to ban.
Why is blocking by IP address a bad idea?
Mobile carriers put thousands of unrelated customers behind a single address, and universities, offices and whole countries do the same. Blocking on IP punishes geography rather than behaviour, and the users it costs you are mostly mobile users in exactly the markets where this is universal. Meanwhile the abuser buys a residential proxy for about a dollar.
Can Kaidn tell a shared household from a fraud ring?
Not for certain, and it does not pretend to. The engine caps device reuse below the block threshold on its own, and reports account_count_same_network so you can tell a real cluster from a shared laptop on a home connection. Two accounts on one inbox is worth a human look, not an automatic refusal.
What about referral trees and overlapping sessions?
Both are strong signals here and neither is a Kaidn check. Self-referral has a distinctive shape, and two sessions on one device at the same moment is close to conclusive. But you hold the referral table and the session table, not us. They are marked as yours on this page.
Score your own traffic for this
10,000 events a month free, no card. Every verdict comes back with the checks that fired and their weights, so you can see which signal caught it rather than trusting a number.