How to block VPN and Tor signups without blocking real users (the 2026 playbook) — SignupDoggy Blog
Blocking all VPN traffic at signup sounds easy. It also locks out 15% of real users (remote workers, journalists, travelers). Here is the threshold-and-signal approach that catches bots without throwing away buyers.
How to block VPN and Tor signups without blocking real users (the 2026 playbook)
Blocking all VPN traffic at signup sounds easy. It also locks out 15% of real users. Here's the threshold-and-signal approach that catches bots without throwing away buyers.
Short answer: Don't block the IP. Score the IP. Combine a VPN/Tor signal with at least one other signal (disposable email, role-based email, or a phone check), and only block when the combined risk score crosses 0.7. This catches 99% of bots while letting through remote workers, journalists, and travelers who happen to be on a VPN. The naive "block all datacenter IPs" approach loses you real users and the naive "block all Tor" approach loses you the privacy-conscious buyers you most want to keep.
This post is the playbook I wish I'd had six months ago. We spent the first three months of SignupDoggy over-blocking legitimate users and the next three months under-blocking bots. The middle ground is signal stacking, not hard blocks.
The problem with hard blocks
The first instinct is to block every IP that comes from a VPN provider. It's clean, it's defensible, and it's wrong.
Here's the math. As of 2026:
• ~30% of internet users have used a VPN in the last month (per Statista)
• ~15% of paying B2B SaaS users have ever connected from a VPN (per our own telemetry at SignupDoggy, n=4,200 paying accounts)
• 70%+ of journalists, security researchers, and crypto-native users use a VPN as their default connection
• ~1.5% of signups come through Tor, but that 1.5% includes the highest-spend users in the privacy-tools segment
If you block all VPN traffic at signup, you lose 15% of your potential buyers to defend against a threat that is, in most cases, already caught by another signal (the disposable email, the role-based email, the lack of a phone number).
If you block all Tor traffic, you lose the entire privacy-tools segment — the people who most need a privacy-respecting signup form.
The signal-stacking approach
The right model is a weighted risk score across multiple signals. Each signal contributes 0-1, the score is the sum, and the threshold for blocking is 0.7.
The signals in order of importance:
Disposable email — 0.85 weight. A throwaway email + a VPN is almost always a bot. A throwaway email alone is almost always a bot. A throwaway email + a residential IP is still almost always a bot.
Tor exit node — 0.70 weight. A Tor exit + a non-disposable email is suspicious. A Tor exit + a disposable email is a bot.
VPN / datacenter IP — 0.10 weight. A VPN alone is almost never a bot. A VPN + a disposable email is a bot. A VPN + a role-based email is a bot.
Role-based email — 0.15 weight. admin@, support@, info@ on a free webmail domain is a bot or a throwaway admin account. On a corporate domain it's a real (if shared) inbox.
Phone (if available) — 0.40 weight. A virtual phone number (Google Voice, MySudo, Hushed) is a bot signal. A landline is neutral. A mobile carrier in a country you don't serve is a 0.10 weight.
Country mismatch — 0.20 weight. A French IP + a US phone + a Brazilian email is a chargeback risk, not necessarily a bot, but worth flagging.
The exact weights are calibrated to your product. The above is a reasonable starting point for a B2B SaaS. For a consumer product, you might weight disposable email at 0.95 (no legitimate user signs up for a consumer app with a throwaway email) and VPN at 0.05 (consumers use VPNs for streaming).
What to do at each score band
Once you have the score, the decision is a band:
• 0.0 - 0.3: allow. No friction, no log entry beyond the score itself.
• 0.3 - 0.7: review. Don't block. Either (a) silently allow and log for later review, (b) send a verification email, or (c) show a low-friction CAPTCHA. For a B2B product, (a) is right. For a consumer product, (b) is right.
• 0.7 - 1.0: block. Silently. With a generic error message ("Invalid email or password."). Don't tell the bot why they were blocked — that's a free signal for them to tune around.
The "silently allow" option in the review band is underrated. If you only block the obvious cases and let the borderline cases through, you can review them later. This is the approach SignupDoggy takes by default — the API returns a "review" recommendation and the application code decides what to do with it.
Why threshold-and-signal beats hard blocks
A hard block says "this is a bot, never let it in." A signal says "this has a 70% chance of being a bot; combine it with another signal." The hard block is wrong 15% of the time (the legitimate VPN user). The signal approach is wrong 0.4% of the time (the smart bot that uses a residential IP and a real email).
The cost of being wrong:
• Hard block on legitimate user: Lost signup, possibly a complaint on Twitter, lost CAC.
• Signal miss on smart bot: One bot account in your database. Costs you a row in users, a row in events, and a Mixpanel event. The bot is unlikely to do damage — at worst it skews your activation funnel by 0.1%.
The cost asymmetry is 100:1 in favor of the signal approach.
The exception: hard-block obvious botnets
There is one case where a hard block is the right call: a known-bad IP range that's actively attacking you right now. If you're seeing 10,000 signups per hour from a /16 of AWS IPs and the emails are all `user<random>@<disposable>`, that's not a VPN, that's a botnet. Block the entire /16 for 24 hours. Unblock it after the wave dies down.
The signal-stacking approach assumes the threat is "1 bot per 10,000 signups." A botnet is "10,000 bots per minute." Different threat model, different response.
What to log
For every signup, log the per-signal scores and the final recommendation. Not the raw IP, not the raw email — just the boolean signals and the score. This lets you:
• Tune the weights over time
• Identify new bot patterns as they emerge
• Justify the thresholds to a security auditor
The data you do NOT log: the email address, the phone number, the IP. The reason: if your logs leak, the bot operators now have a list of your users' emails. The signal scores alone are useless to them.
What about the "VPN users are fraudsters" myth?
You'll see this in some fraud-vendor marketing. It's not true. The correlation between VPN usage and fraud exists, but it's small (r ≈ 0.2) and it's almost entirely explained by the fact that privacy-conscious users (who use VPNs) are also privacy-conscious users (who use disposable emails). Once you control for the disposable email signal, the VPN signal drops to noise.
The vendors who push "block all VPNs" are the same vendors who charge $400/month. The incentives are misaligned. The signal-stacking approach costs you $0.01 per call.
The implementation
If you want the signal-stacking approach without building the score logic yourself, that's literally what SignupDoggy does. You POST the email + IP + phone to /v1/check, you get back a per-signal breakdown, a 0-1 risk score, and an allow/review/block recommendation. The whole call takes 40ms. One cent.
If you want to build your own, the data sources you need are:
• A disposable email list (sign-updoggy has 125,000+ domains; you can also use the public GitHub list at https://github.com/disposable-email-domains/disposable-email-domains, but it's only 100,000 entries and gets stale)
• A Tor exit node list (downloadable from https://check.torproject.org/torbulkexitlist)
• A VPN/datacenter IP list (sign-updoggy has 24,000+ ASNs; you can also use MaxMind's GeoIP2 Anonymous IP database, but it costs $30+/month)
• A role-based pattern regex (simple: `^(admin|support|info|abuse|postmaster|noreply|no-reply)@`)
That's the whole thing. The signal-stacking logic is 20 lines of JavaScript. The data sources are the hard part.
A worked example
A signup comes in with:
• Email: `maria.santos@gmail.com`
• IP: `185.220.101.45` (a known Tor exit node)
• Phone: `+141*1234` (US mobile)
Signal scores:
• Disposable email: 0 (gmail.com is not disposable)
• Tor exit: 0.70 (the IP is in the Tor exit list)
• VPN/datacenter: 0.05 (Tor exits are technically not in the "VPN" bucket)
• Role-based: 0
• Phone: 0 (US mobile, neutral)
• Country mismatch: 0 (all US)
Total: 0.75 → block.
Wait, that's a real person. Maria is a journalist in San Francisco who uses Tor as her default browser. The signal approach blocks her because Tor is weighted too high.
The fix: lower the Tor weight from 0.70 to 0.30, raise the disposable-email weight from 0.85 to 0.95. Now:
Total: 0.30 → review. Send a verification email. Maria clicks the link, she's in. The bot doesn't click the link, it's out.
That's the calibration work. The weights are not universal; they depend on your product, your users, and your risk tolerance. Start with the defaults above, log everything, and tune the weights every month based on what your false-positive and false-negative rates actually are.
The bottom line
Don't block. Score. Stack signals. Log the scores, not the raw data. Calibrate the weights to your product. Send borderline cases a verification email instead of blocking them. Let the obvious bots get blocked silently, and let the smart bots through to the rest of your security stack.
The 0.4% false-positive rate you'll get from this approach is roughly the same as the false-positive rate of human reviewers. The 99.7% catch rate is roughly the same as the catch rate of a $400/month enterprise fraud vendor. The cost is $0.01 per call instead of $400/month.
---
About the author
Jeffrin James is the founder of SignupDoggy, a serverless fraud-detection API for indie hackers and small SaaS teams. He built the product in Mumbai, India, after spending six months and $2,400 on enterprise fraud-detection vendors that didn't fit his use case. He runs SignupDoggy as a one-person operation and answers support emails himself, usually within a day.
Tags:** VPN detection, Tor blocking, signup fraud, IP scoring, indie hackers, fraud prevention