Stop Bot Signups, Disposable Emails & Fake Account Creation
Bot-registered accounts, throwaway inboxes and proxy-masked registrations fill your funnel with users who never existed. Maskbreak checks each registration, on the form and in the OAuth callback, with one server-side call before the user row exists. Real visitors see no challenge.
What you're up against
Bot-registered accounts at scale
Scripted signups run headless browsers through your registration form, pass email verification, and land in your database looking like users. Every one skews activation metrics and burns onboarding email sends.
Disposable emails that pass validation
New burner mailbox domains keep appearing, and a blocklist you maintain by hand falls behind. The addresses are syntactically valid, receive the verification mail, and click the link.
Proxy-masked registrations
Each fake signup arrives from a fresh residential IP, so per-IP rate limits and geo rules never fire. The registrations look geographically diverse when they are one operator behind a proxy pool.
Poisoned funnel metrics
Fake accounts inflate signup counts, deflate activation rate, and mislead every growth experiment you run. By the time the anomaly is obvious, weeks of A/B test data are already contaminated.
What Maskbreak does for you
- Block headless and scripted browsers (
automation_detected) and fake browsers (antidetect_browser) by default - Read the network behind each registration: a proxy or Tor exit blocks by default, residential proxies included; a VPN alone is flagged for review; a cloud-server address alone stays allow with
datacenter_asnlisted - Flag throwaway inbox domains with
disposable_emailwhen you send the address; it raises an allow to review and never blocks on its own - Send the new account's ID as
accountIdanddevice.linked_accountscounts how many of your accounts that device has been seen with - Get the answer before the verification email is queued, so once you enforce, a blocked bot never costs you a send or puts a mail in someone else's inbox, the trick behind email bombing
Choosing between tools? Eight of them, Maskbreak included, are compared from their own pages in fake account prevention software compared: what each checks at signup, its free plan, its price and where each beats Maskbreak.
behind many new accounts within days of a signup bonus is the tell. A worked model of a fintech launch, the signals that show it and the response plan. Illustrative scenario, not a customer result.
Read the PlaybookWhere the check goes
Two call sites cover registration fraud: signup (before you write the user row or queue the verification email) and the OAuth callback (a Google identity says nothing about the device that just presented it). The client snippet rides along in your registration page; the server asks Maskbreak for a verdict before the account exists. The example starts in watch mode: it logs each verdict, lets every request through and fails open if Maskbreak is unreachable. After a few days, compare the log with the Events in your dashboard, then uncomment the enforce line; the integration guide has the full enforce checks. The example also sends the signup email so a throwaway domain is flagged; the address is checked and not stored.
// Score the signup before you create the account or send verification email // Watch mode first: log the verdict, always continue, fail open const body = req.body || {}; // sentinel.js adds monocle + sentinel_fp to your form let risk = null; try { const verdictRes = await fetch('https://maskbreak.com/v1/evaluate', { method: 'POST', signal: AbortSignal.timeout(5000), headers: { 'Authorization': 'Bearer ' + process.env.MASKBREAK_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ token: body.token || body.monocle, // network evidence fingerprintEventId: body.fingerprintEventId || body.sentinel_fp, // device evidence tz: body.tz || body.sentinel_tz, email: body.email // optional: flags throwaway domains }) }); if (verdictRes.ok) risk = await verdictRes.json(); } catch {} // unreachable or timed out: your handler still runs console.log('[maskbreak]', JSON.stringify({ decision: risk?.decision ?? null, reasons: risk?.reasons ?? null, risk_score: risk?.risk_score ?? null, degraded: risk ? !!risk.degraded : null })); // Enforce later: if (risk?.decision === 'block') return res.status(403).json({ error: 'Request rejected' });
What a scripted signup gets back
A headless browser behind a residential proxy, registering with a throwaway inbox. The proxy and the automation each block by default; the disposable domain adds its reason, though on its own it would only have raised an allow to review. Example response, trimmed:
{
"decision": "block",
"risk_score": 100,
"reasons": ["proxy_detected", "automation_detected", "disposable_email"],
"network": { "vpn": false, "proxy": true, "datacenter": false, "tor": false, "residential": false, "service": null },
"device": { "automation": true, "antidetect": false, "tampering_score": 0 },
"email": { "disposable": true }
}The same throwaway inbox from a plain home connection and a clean browser gets review, with ["disposable_email"] and a risk_score of 15 when nothing else adds to it. A cloud-server address with nothing else flagged gets allow, with datacenter_asn listed. network.service names the proxy or VPN operator when known and is null otherwise.
Run the live check on the homepage to see the network and browser checks on your own visit, no key needed. The free IP lookup tool takes any address, but a bare IP only shows Tor exits and published cloud ranges; VPN and proxy verdicts need a live visit. The disposable-email flag and multi-account linking come with the API.
The signals that matter here
Throwaway inboxes, without a list to maintain. Send the signup email as the optional email field and Maskbreak checks its domain, subdomains included, against a disposable-mail list it refreshes every day. A match adds disposable_email and raises an allow to review. It never blocks on its own: a burner inbox is a reason to look closer, not proof of a bot. If a refresh fails, the previous list stays in use. The address is checked in memory and not stored.
Automation a form can't see. Scripted registrations run headless Chrome with stealth patches, or fake (antidetect) browsers with a made-up fingerprint per profile. Maskbreak's device check returns automation_detected or antidetect_browser, and either one blocks by default. virtual_machine is listed too; on its own it asks for review, never a block: plenty of real people work inside a VM.
One person, many accounts. Throwaway inboxes and proxy rotation make each fake signup look new. Send the ID you are giving the new account as accountId: device.linked_accounts counts how many of your accounts that device has been seen with, and above one the response lists multi_account_device. It changes nothing by default, so read it in your handler (more in preventing multi-accounting). If you set a Rules-tab action for it instead, that rule decides for the shared device only: a proxy or fake browser on the same signup still blocks. Links are per customer, stored as one-way hashes, and never cross to another customer. device.times_seen is different: all sightings of the device across Maskbreak, useful as "brand-new device or not", never a count of your signups. For a fake browser that invents a new device per profile, the signal to read is antidetect_browser, not the link count.
OAuth signups are still signups. A Google or GitHub identity proves someone controls a mailbox, not that the device behind it is clean, and bulk-created OAuth accounts pass checks that only watch the password form. Run the same check in the OAuth callback so network.proxy, network.vpn and the device signals cover every registration path, not just one.
Common questions
email field. Maskbreak checks its domain, and the parent domain, against a disposable-mail list it refreshes every day, so you do not maintain one. A match adds disposable_email and raises an allow to review; it never blocks on its own. If a refresh fails, the previous list stays in use. The address is checked in memory and not stored.review with vpn_detected, never block, and the response carries network.vpn and network.service (the operator's name when known). Your code decides what review means: let the account in and watch it, or ask for one more verification step. Proxies, Tor exits, automation, emulators and fake browsers are what block by default.allow, with datacenter_asn in the reasons and network.datacenter true, because offices, CI runners and corporate gateways use them too. If the same signup also shows automation, a proxy or a fake browser, it is blocked because of those signals.Sentinel.collect() before sending the visitor to Google and keep them in the session for the callback. A Google identity proves control of a mailbox, not that the device behind it is clean.degraded: true was answered without part of its evidence, so treat its allow the same way. Each response reports its own processing time in evaluated_in_ms, so you can set the timeout from your own traffic.Keep fake accounts out of your database
Free plan: 10,000 visitor checks a month, no card. Paid plans from €29 a month. Flags proxies (residential ones included), fake browsers and scripted signups.