Server-side middleware / VERSION 1.0.0

Node.js & Express Proxy Detection Middleware

Integrate proxy and VPN checks in Node.js or Express. Download a server-side client with IPv6 support, bounded caching, timeouts and network policies.

Source and setup instructions included · Published October 28, 2026

A server-side client and Express middleware

The package includes a dependency-free ES module for Node.js 22+ and middleware for Express. It supports IPv4/IPv6, bounded caching, duplicate-request coalescing, exact IP rules and an explicit unknown state. Keep the module and your key on the server.

Make a lookup

Extract the ZIP and import the module from your backend. Set the key through your deployment’s secret manager or environment.

import { createClient } from './proxyradar.mjs';
const radar = createClient({ apiKey: process.env.PROXYRADAR_API_KEY });
const outcome = await radar.check('8.8.8.8');
// state: 'positive', 'negative', or 'unknown'
if (outcome.state === 'unknown') {
  // Apply your unavailable-result policy; do not classify as clean.
}

Use a route-level policy

Mount the middleware after your application’s rate limiter and before the action you want to protect. The following example monitors signups without blocking.

import { proxyRadarMiddleware } from './proxyradar.mjs';
const checkNetwork = proxyRadarMiddleware({
  apiKey: process.env.PROXYRADAR_API_KEY,
  mode: 'monitor',
  blockOn: 'overall',
  onUnknown: 'allow'
});
app.post('/signup', signupRateLimiter, checkNetwork, signupHandler);
// Your handler can read req.proxyRadar.wouldBlock and .outcome.

signupRateLimiter and signupHandler are your existing application handlers. Change mode to block to return 403 on a match. Use blockOn: ['vpn','tor'] for category-only checks. With onUnknown: 'reject', block mode returns 503 on unavailable detection. Monitor mode always continues.

Configure client IP trust explicitly

By default, the middleware uses the socket address and ignores forwarded headers. If Express is behind a reverse proxy, configure trust proxy for the exact proxy addresses or subnets you control, make sure it overwrites forwarded headers, then pass getIP: req => req.ip. Do not use unrestricted trust proxy = true on an origin reachable directly from the internet.

IP rules, cache and quotas

Pass allow and deny arrays of exact IPs; allow wins and local rules skip the API. Mapped IPv6 addresses normalize to IPv4. Successful lookups cache for 60 seconds when positive and 30 seconds when negative, with at most 1,000 entries by default. Set cacheSize: 0 to disable caching. At most eight distinct lookups run simultaneously per client instance; additional ones return unknown/client_busy.

The timeout defaults to 15 seconds. There are no automatic retries. HTTP 401, 422, 429 and 503, malformed responses and mismatched IPs all produce unknown. Use a single client or middleware instance per application process so caches and concurrency limits are shared. Application-wide rate limiting remains your responsibility.

Start with a real lookup.

Create an account, get your API key and test the integration on your staging site. Your account includes 1,000 free queries per day.

Create free account ↗

All integrations · API reference · Coverage and limitations · Account support