Guide · fake signups

How to detect fake signups: 7 signals and how to check each one

Many fake signups give themselves away in the email address, the network they come from or the speed they arrive. Here are the seven signals worth checking, a few lines of code for each, and which ones to block versus merely warn on.

By the Vetto team · Updated

Quick answer

A fake signup is any account that will never become a customer: a bot, a throwaway inbox, a mistyped address nobody can confirm, or the fifth free trial from the same person. They inflate your signup numbers, bounce your onboarding emails and burn free-tier resources.

To detect them, check seven signals at the moment of signup. The first four live in the email address, the last three in the request itself:

SignalExampleHow to checkFree check
Throwaway inboxx7@mailinator.comDomain on a disposable listDisposable email checker
Dead domainpat@oldstartup.exampleNo MX, null MX or NXDOMAINDisposable email checker
Typojane@gmial.comDomain one edit away from a popular oneEmail typo checker
Alias clusterj.a.n.e+7@googlemail.comSame inbox after normalizingGmail alias checker
Datacenter or VPN IPAS14061 · DigitalOceanIP belongs to a hosting networkASN lookup
Burst16 signups, 1 IP, 1 hourCount per IP per hourSQL count
BotHidden field filledHoneypot fieldFive lines of HTML

Try the email signals on any address right here. The checker reads public DNS and stores nothing:

Try:

Checks syntax, typos of big providers, Vetto's list of throwaway domains and learned throwaway mail servers, and live DNS (MX, null MX, NXDOMAIN). The address is not stored, and no email is ever sent to it.

The 7 signals of a fake signup

1. Disposable (throwaway) email domains

Services such as Mailinator and YOPmail hand out inboxes that work for minutes or hours. Someone who uses one wants your free tier, not a relationship. The check is a set lookup against a list of known throwaway domains. The public-domain disposable-email-domains project is a good start; Vetto ships 9,222 domains from it, and you can search or download them on the disposable email domains list.

is-disposable.js
// disposable-domains.txt: one domain per line (CC0 list)
import { readFileSync } from 'node:fs';
const LIST = new Set(readFileSync('disposable-domains.txt', 'utf8').split('\n').filter(Boolean));

export function isDisposable(email) {
  const domain = email.split('@').pop().trim().toLowerCase();
  // Check the domain and its parents, so x.mailinator.com matches too.
  const parts = domain.split('.');
  return parts.some((_, i) => LIST.has(parts.slice(i).join('.')));
}

Lists lag behind: new throwaway domains appear every week. A useful second check is the domain's mail server, because many new throwaway domains point their MX records at the same few hosts as the known ones.

2. Dead domains with no mail server

A domain that does not exist, or that cannot receive mail, will never confirm an account. Look it up in DNS: no domain at all (NXDOMAIN), a null MX record that refuses all mail (RFC 7505), or no MX and no A/AAAA fallback (RFC 5321, section 5.1). In Node, dns.promises.resolveMx does the work:

accepts-mail.js
import { promises as dns } from 'node:dns';

// true = the domain can receive mail, false = it cannot.
export async function acceptsMail(domain) {
  try {
    const mx = await dns.resolveMx(domain);
    // Null MX (RFC 7505): a single record with an empty host means "no mail".
    if (mx.length === 1 && (mx[0].exchange === '' || mx[0].exchange === '.')) return false;
    if (mx.length) return true;
  } catch (err) {
    if (err.code === 'ENOTFOUND') return false; // NXDOMAIN: no such domain
    if (err.code !== 'ENODATA') return true;    // timeout etc.: fail open
  }
  // No MX: mail falls back to the A/AAAA record (RFC 5321, implicit MX).
  const [a, aaaa] = await Promise.allSettled([dns.resolve4(domain), dns.resolve6(domain)]);
  return a.status === 'fulfilled' || aaaa.status === 'fulfilled';
}

Note the fail-open branch: if DNS times out, let the signup through. A slow resolver should never cost you a real customer.

3. Typos like gmial.com

Typos are not fake signups, but they look like them in your metrics: the account exists and nobody ever confirms it. One Discourse forum owner reported that almost 10% of new registrants typed their email wrong or left it out (one forum, no method given). Compare the domain against popular providers with an edit distance of one or two and offer a fix, never a block. The email typo checker shows the suggestions Vetto makes.

Watch for lookalike domains that do accept mail, such as gmai.com. They pass the MX check, but your welcome email goes to a stranger. Warn on them.

4. Alias clusters and repeat signups

Gmail ignores dots in the local part (Google), drops anything after a +, and treats googlemail.com as gmail.com. So j.a.n.e+trial7@googlemail.com reaches jane@gmail.com, yet a unique index on the raw string sees two customers. Store a normalized matching key next to each address and check it on signup. The Gmail alias checker groups a pasted list by inbox, and our free trial abuse playbook covers the full fix.

5. Datacenter, VPN and Tor IPs

Real customers browse from home, office and mobile networks. Signup scripts usually run on cloud servers. Look up the IP's autonomous system (ASN): if it belongs to a hosting provider, flag the signup. Many platforms hand you the ASN for free; Cloudflare Workers, for example, expose request.cf.asn and request.cf.asOrganization on every request (Cloudflare docs). Otherwise use an IP-to-ASN database.

A second clue: a browser time zone (Intl.DateTimeFormat().resolvedOptions().timeZone) that does not match the IP's location. Treat both as flags, not blocks. Plenty of privacy-minded customers and corporate staff use VPNs.

6. Signup bursts and velocity

A person signs up once. A script signs up 16 times in an hour from the same IP. Count recent signups per IP (and per network, for scripts that rotate addresses) and act when the count passes a limit you choose:

burst.sql
-- Signups from this IP in the last hour (PostgreSQL)
SELECT count(*) FROM signups
WHERE ip = $1 AND created_at > now() - interval '1 hour';
-- Over your limit (say 5)? Block or challenge the next one.

Keep the limit generous enough for an office or a university behind one shared IP, and alert yourself when it fires: a burst is often the first sign of a targeted attack.

7. Bots caught by a honeypot

Simple bots fill in every field they find. Add one that humans never see, and reject any submission that fills it. Move it off-screen rather than using display:none, which some bots skip, and keep it out of the tab order:

signup.html
<!-- Humans never see or fill this field. -->
<div style="position:absolute;left:-10000px" aria-hidden="true">
  <label>Leave this empty <input name="website" tabindex="-1" autocomplete="off"></label>
</div>

// Server: reject the signup if req.body.website is not empty.

A honeypot does nothing against bots that post straight to your API and skip the form. For those you need a server-side check, such as a signed token the form adds on submit, or a CAPTCHA.

Turn signals into decisions

Each signal has a different confidence, so each deserves a different response. Blocking a real customer costs more than letting one fake account in.

SignalConfidenceRecommended action
Honeypot filled, throwaway inbox, dead domainNear certainBlock with a clear message
Typo with a known fixHigh, but it is a real personSuggest the fix; never block
Alias of an existing accountMedium: could be a team or a forgotten trialWarn: “You already have an account. Sign in?”
Datacenter or VPN IPLow on its ownFlag for review, or require email confirmation
Burst over your hourly limitHigh in combinationBlock the excess, alert yourself

Tools to detect fake signups in SaaS

You can assemble the checks yourself or buy them. The main options, by category:

  • DIY: the snippets on this page. Free and fully under your control, but you maintain the lists, the DNS edge cases and the messages.
  • CAPTCHAs and bot challenges such as Cloudflare Turnstile or reCAPTCHA: good against scripts, blind to throwaway inboxes and aliases.
  • Email verification APIs such as Kickbox: verify that a mailbox exists over SMTP, built for list hygiene and deliverability. See Vetto vs Kickbox.
  • Fraud and device-fingerprinting platforms: deep signals for payments and account takeover, with integration work to match.
  • A signup gate like Vetto: the seven signals above behind one script tag.

Before you choose, measure. Export your users and run the free email list audit: it parses the CSV in your browser and tells you how many typos, throwaways, dead domains and alias clusters you already have.

Where Vetto fits

Vetto runs all seven checks on your existing form, with one script tag and no backend code:

index.html
<script src="https://usevetto.com/v.js" data-site="pk_your_public_key" defer></script>
  • Free (1 site, 1,000 checks a month): one-click typo fixes, throwaway and dead-domain blocking, privacy relays allowed and tagged, and a bot honeypot. The Pro signals run in shadow mode, so your stats show what you would catch.
  • Pro ($12/month or $99/year): lookalike domains, alias and repeat-signup detection, datacenter/VPN and burst signals, custom actions per signal, Slack and Discord alerts, and a signed vetto_token your backend checks with POST /v1/verify, so bots that skip the form get caught too.

If Vetto does not answer within 800 ms, the form submits as if it were not installed. What Vetto does not do: SMTP mailbox verification, device fingerprinting or payment fraud scoring. See pricing for the full plan comparison.

Frequently asked questions

What is the fastest way to detect fake signups?

Check the email domain first. A disposable-domain list plus a DNS lookup for mail servers catches throwaway and dead-domain signups in a few milliseconds, before an account exists. Add a honeypot field for simple bots and a per-IP hourly limit for bursts.

Should I block every suspicious signup?

No. Block only what is near certain: a filled honeypot, a throwaway inbox, a domain that cannot receive mail. Suggest a fix for typos, warn on repeats and flag datacenter IPs, because real customers trigger those too.

Does a CAPTCHA stop fake signups?

It stops many automated scripts, but not a person creating accounts by hand with a throwaway inbox or a Gmail alias. A CAPTCHA and email-quality checks solve different halves of the problem, and they work well together.

Can I detect fake signups without storing email addresses?

Yes. Domain checks need only the domain, and repeat detection works on a hash of the normalized address. Vetto keeps salted hashes for 90 days, then purges them, and shows only masked addresses in its log.

How do I check the users who already signed up?

Export them to CSV and run the free email list audit. It parses the file in your browser, sends only domain names for DNS checks, and reports typos, throwaways, dead domains and alias clusters.

Give your signup form sharp eyes.

Free on one site. One line of HTML. Remove it any time and your form works exactly as before.

Founding offer: Pro for life for $69 once, first 100 buyers, until Nov 27.