Esta es una guía práctica para detectar tráfico VPN desde un backend de Node.js. Consultaremos la IP del visitante en una API de detección de VPN, leeremos el veredicto y la puntuación de confianza, y la usaremos para condicionar un registro. El mismo patrón funciona para inicios de sesión y pagos.
Antes de empezar
Necesitarás una clave API (el plan gratuito es suficiente para probar) y Node 18+ para que el
fetch global esté disponible. Guarda la clave en una variable de entorno, nunca en código de
cliente.
Prueba primero la búsqueda con cualquier IP
Paso 1: obtener la IP real del cliente
Detrás de un proxy o balanceador de carga, req.socket.remoteAddress es tu infraestructura, no
el usuario. Lee la cabecera forwarded que establece tu proxy de confianza:
function getClientIp(req) {
const xff = req.headers['x-forwarded-for'];
if (xff) return xff.split(',')[0].trim(); // left-most = original client
return req.socket.remoteAddress;
}
Confía en X-Forwarded-For solo si la establece un proxy que controlas; de lo contrario, un
cliente podría falsificarla.
Paso 2: llamar a la API de detección
Envuelve la búsqueda en una pequeña función auxiliar. Devuelve el veredicto y la puntuación, y falla de forma abierta (permite el acceso) ante errores de red, para que un fallo en la detección nunca bloquee a tus usuarios:
const API_BASE = 'https://ipscanner.io';
async function checkVpn(ip) {
try {
const res = await fetch(`${API_BASE}/v1/vpn/${ip}`, {
headers: { Authorization: `Bearer ${process.env.IPSCANNER_API_KEY}` }
});
if (!res.ok) throw new Error(`lookup failed: ${res.status}`);
const data = await res.json();
return { isVpn: Boolean(data.vpn), score: data.score ?? 0 };
} catch (err) {
console.error('vpn check error', err);
return { isVpn: false, score: 0 }; // fail open
}
}
Paso 3: condicionar un registro al resultado
Ahora usa la puntuación para decidir. Por debajo de un umbral, permite; en el rango medio, exige verificación adicional; alto, bloquea:
app.post('/signup', async (req, res) => {
const ip = getClientIp(req);
const { isVpn, score } = await checkVpn(ip);
if (score >= 70) {
return res.status(403).json({ error: 'Signups from this network need verification.' });
}
if (isVpn || score >= 30) {
req.session.requireEmailVerification = true; // add friction, don't block
}
// ...create the account...
res.json({ ok: true });
});
Observa que en la banda intermedia pedimos verificación en lugar de bloquear. Consulta cómo bloquear usuarios de VPN de forma inteligente para entender por qué importa.
Paso 4: usar caché para ahorrar búsquedas
La misma IP suele repetirse con frecuencia. Una caché de corta duración reduce las llamadas a la API sin arriesgar datos obsoletos:
const cache = new Map(); // ip -> { value, expires }
async function checkVpnCached(ip, ttlMs = 10 * 60 * 1000) {
const hit = cache.get(ip);
if (hit && hit.expires > Date.now()) return hit.value;
const value = await checkVpn(ip);
cache.set(ip, { value, expires: Date.now() + ttlMs });
return value;
}
Mantén el TTL corto (minutos, no días), porque el riesgo de una IP cambia. Consulta qué es la reputación de IP.
Para ir más allá
- Añade detección de proxy al mismo flujo para detectar no solo VPN, sino también proxies y Tor.
- Consolida las señales en una única puntuación de fraude por IP y condiciona tus decisiones a ese único número.
- Aplica el mismo patrón a inicio de sesión y pago, ajustando los umbrales según la acción.
En resumen
Detectar una VPN en Node.js se reduce a una sola llamada API del lado del servidor: resolver la IP real del cliente, consultarla y actuar según el veredicto y la puntuación. Falla de forma abierta ante errores, usa caché brevemente, y exige verificación en la banda de riesgo intermedia en lugar de bloquear directamente.
FAQ