How to detect users creating multiple accounts
To detect users creating multiple accounts, compare each new signup with your existing ones on several signals at once: a normalized email address, the phone number, the IP address and network, and the timing of the signup. No single signal proves it. Two or three that match together usually do.
This guide covers the signals that work, how to store them without keeping more personal data than you need, and how to react without punishing real users.
Why people create multiple accounts
- To get the free part again: a new trial, another batch of free credits, a second referral bonus.
- To get around limits: usage caps, rate limits or a ban on the first account.
- To fake activity: votes, reviews or referrals from accounts that are all the same person or script.
The first is the most common for products with a free plan, and it is also the one that costs the most when a script does it at scale. If you want to put a price on it, the fake signup cost calculator takes about five minutes.
The signals that link accounts
1. A normalized email address
Gmail ignores dots and everything after a +, so anna+2@gmail.com and a.nna@gmail.com reach the same inbox. Store a normalized version next to the address the user typed and check it for duplicates. Our guide on stopping free trial abuse has a short function for this.
2. The same phone number
If you ask for a phone number, it is one of the strongest links, because a new number costs more than a new email address. Bring every number into one format first (international, with country code), otherwise 079 123 45 67 and +41 79 123 45 67 look different.
import { parsePhoneNumberFromString } from "libphonenumber-js";
// "079 123 45 67" with country CH becomes "+41791234567"
function phoneKey(phone, country) {
return parsePhoneNumberFromString(phone, country)?.number ?? null;
}
Virtual numbers from online services are cheap and widely available, so a reused number is a strong sign, but a new number is not proof of a new person.
3. The same IP address or network, close in time
Several signups from one IP within a few minutes rarely come from different people. Count recent signups per IP and per network (the first three blocks of an IPv4 address). Look at short time windows only: over a week, a busy office or a mobile network produces many unrelated signups from one address.
4. Address series and company domains
Scripts often use numbered addresses like max1@, max2@, max3@, or create many addresses on one small domain they own. A burst of either within an hour is a strong sign of one actor behind many accounts.
5. The same card
If accounts add a payment method, your payment provider can tell you whether two accounts use the same card without showing you the card number. Stripe, for example, returns a fingerprint for each card. It is a very reliable link, but only for accounts that get that far.
6. Behavior after signup
Accounts that use every free credit within minutes and never come back, or that perform the exact same steps in the same order, are often linked even when their details differ. This one is easier to check after the fact than at signup.
Store links, not personal data
You do not need to keep raw emails, phone numbers and IPs forever to find duplicates. Store a keyed hash of the normalized value instead, and compare hashes. Use a secret key so the hashes cannot be reversed by trying common values.
import { createHmac } from "node:crypto";
function linkKey(value) {
return createHmac("sha256", process.env.LINK_SECRET).update(value).digest("hex");
}
// at signup: save linkKey(emailKey), linkKey(phoneKey) with the account,
// then count other accounts with the same keys
Keep IP addresses only as long as you need them for the short time windows above, and mention all of this in your privacy policy.
What to do when accounts match
- One weak match (only a shared IP): let the signup in as usual.
- One strong or two weak matches (same phone, or same network plus an address series): give a smaller trial or fewer free credits until you have looked at it.
- Many matches at once (a wave of numbered addresses from one server): block, with a neutral message.
This keeps families, colleagues and people with a second account in, while making each extra account worth very little to someone farming them.
Common mistakes
- Banning on a shared IP. Offices, schools and mobile carriers put thousands of people behind a few addresses.
- Comparing raw emails. Without normalization,
anna+2@gmail.comslips through every duplicate check. - Telling abusers which rule they hit. A neutral message gives a real user a way forward and a script nothing to adapt to.
- Keeping everything forever. More stored personal data means more risk, and old IPs say little about new signups.
Doing it with one API call
SignupVet compares every new signup with your recent ones and adds the matching reason to the result, together with the email, phone and IP checks:
| Signal | Reason code | Time window |
|---|---|---|
| Same phone number with a different email | phone_reused | 24 hours |
| Numbered address series, including +tags and dots | email_series_pattern | 1 hour |
| Several signups from one IP | signup_velocity_ip | 10 minutes |
| Many signups from one network | signup_velocity_network | 10 minutes |
| Many signups on one company domain | signup_velocity_domain | 10 minutes |
const res = await fetch("https://www.signupvet.com/score", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.SIGNUPVET_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ email, phone, ip: req.ip }),
});
const { recommendation, reason_codes } = await res.json();
What it does not do: it has no device fingerprinting, and it only looks back over the time windows above. For a person who returns weeks later with a new trial, keep your own duplicate check on a normalized email or phone, as shown above. The documentation lists every reason code.
Frequently asked questions
Is it legal to detect multiple accounts?
Checking signups for fraud is a common and generally accepted purpose, but you still need to follow the privacy rules that apply to you: say in your privacy policy what you check, keep only what you need, and prefer hashed or masked values over raw emails, phone numbers and IPs.
Should I ban someone who has two accounts?
Usually not at first. Families, colleagues and people with a work and a private account are common. Limit what the second account gets, such as free credits or a trial, and ban only clear abuse like dozens of accounts from one script.
Is a shared IP address enough to link two accounts?
No. Offices, universities, mobile networks and VPNs put many people behind one address. Treat a shared IP as one signal among several, and only when many signups arrive from it within minutes.
What about device fingerprinting?
It can link accounts across emails and networks, but it needs code in the browser, can be blocked or spoofed, and raises extra privacy questions. For most small products, email, phone, IP and timing signals catch the bulk of multi-accounting with less effort.
Spot the second, third and tenth account
SignupVet checks the email, phone number and IP address of every new signup and compares it with your recent ones. It is free for 250 signups a month, no card needed.