IP Reputation API: Threat Score and VPN, Proxy, Tor and Abuse Flags for Any IP

Updated

Short answer

Send the IP address to GET https://api.iplookupapi.com/v1/info and read the security object: it flags VPN, proxy, Tor, data center, anonymous, bot, abuser, known attacker, spam and iCloud Private Relay addresses and adds a proxy type and a threat score from 0 (no known threat) to 100. The batch endpoint returns the same object for up to 1,000 addresses per request. Security data is part of the Professional plan and up, from $34.99 per month for 650,000 requests.

On this page

An IP reputation API tells you what is known about an address before you trust a request. iplookupapi returns this IP intelligence as the security object of the regular lookup: ten yes/no flags, a proxy type and a threat score, next to network and abuse-contact data. Below are the request, each field, code with an example allow, challenge or review policy, false positives, privacy and plans.

Check an IP’s reputation with one request

Send the address in ip and your key in the apikey header. fields limits the response to the security object, four network fields and the ASN and organization:

Shell
curl -H "apikey: YOUR_API_KEY" \
  "https://api.iplookupapi.com/v1/info?ip=80.110.0.1&fields=ip,security,network.is_hosting,network.is_mobile,network.is_cgnat,network.as_type,connection.asn,connection.organization"

The response below is trimmed from the official sample on the info endpoint documentation. The address belongs to an Austrian ISP, so every flag is false and the threat score is 0:

JSON
{
  "data": {
    "ip": "80.110.0.1",
    "connection": {
      "asn": 8412,
      "organization": "Magenta Telekom GmbH"
    },
    "network": {
      "is_hosting": false,
      "is_mobile": false,
      "is_cgnat": false,
      "as_type": "isp"
    },
    "security": {
      "is_anonymous": false,
      "is_datacenter": false,
      "is_vpn": false,
      "is_bot": false,
      "is_abuser": false,
      "is_known_attacker": false,
      "is_proxy": false,
      "is_spam": false,
      "is_tor": false,
      "proxy_type": "",
      "is_icloud_relay": false,
      "threat_score": 0
    }
  }
}

Keep the key in the header, because query strings end up in access logs. Always pass the visitor’s address: without ip, the API answers for your server. Behind a load balancer or CDN, find the real client IP and only trust an X-Forwarded-For header that your own proxy set.

Security fields: what each flag means

FieldMeaning (from the docs)Typical useCaution
is_anonymousTor exit, VPN, open proxy or privacy relayOne check for “traffic is hidden”Includes privacy relays used by ordinary consumers
is_datacenterData center, cloud, hosting or CDN addressScripted signups, scraping, API abuseAlso matches your own servers and partners
is_vpnServer of a commercial or consumer VPNContext for geo checks, step-up at loginMany people use a VPN for privacy or work
is_proxyPublic or open HTTP or SOCKS proxyChallenge or reviewThe address can pass to a new user after the proxy shuts down
is_torTor exit nodeChallenge or review on sensitive actionsMany Tor users need it for safety
is_botVerified crawler or monitor published by its operator, or an internet-wide research scannerSkip analytics, separate bot trafficNot a “bad bot” flag
is_abuserRecently reported for abuse by blocklistsRaise friction“Recently” means the label can expire
is_known_attackerRecently seen attacking (brute force, exploitation, botnets) in threat feeds, or part of a hijacked netblockReview, protect login and admin areasInfected home devices share the owner’s IP
is_spamKnown spam senderComment and form spam filtersShared mail and hosting ranges
is_icloud_relayiCloud Private Relay egress addressTreat as privacy relay, not as a VPNUsed by ordinary Apple customers
proxy_typetor, vpn, proxy or relay, empty if not anonymous; the first in that order winsLogging, simple routingOne value only, even if several apply
threat_score0 (no known threat) to 100 in steps of 10Tiered decisionsRanks evidence; not a fraud probability

On plans with security data, the docs list further keys. reasons holds one short sentence per flag that is set, and last_seen the last day any list saw the address; both help support explain a decision. is_known_good_bot marks addresses that a bot’s operator publishes for its crawlers, monitors or webhook senders. The vpn, proxy, tor and known_attacker objects add a confidence from 0.05 to 1 that says how strongly the lists back the flag. It is not a calibrated probability.

How the threat score is built

The documentation describes threat_score as evidence-based: it combines the anonymity type (Tor exit, open proxy, VPN, relay), internet scanners, data center hosting and threat feeds, weighted by how reliable a feed is and how recently it saw the address. Verified crawlers and allowlisted infrastructure such as public DNS resolvers score 0. The documented examples:

Situationthreat_score
Data center address, nothing else known10
VPN server30
VPN server in a data center40
Tor exit node60
Tor exit also reported for attacks90

Use it as an IP risk score for tiered decisions. It is not an IP fraud score in the sense of a probability that an order is fraudulent.

Network, company and abuse data for risk decisions

The network, company and abuse objects come with every paid plan from Basic and keep you from overreacting to a flag.

FieldWhat it tells youWhy it matters
network.is_hostingData center, cloud, hosting or CDN network (same data as security.is_datacenter)A first bot filter from Basic
network.is_cdnCDN edge addressTraffic from a CDN edge is the CDN, not the end user
network.is_mobileThe announcing AS carries only a mobile networkMany users share each address
network.is_cgnatCarrier-grade NAT space shared by subscribersOne bad user can taint an address for many
network.is_relayPrivacy relay egress, with relay.providerUsually many ordinary users behind it
network.as_typeisp, hosting, business, education or governmentResidential and business traffic look different
company.typeSame classes, for the holder of the address blockOffice network or rented server
abuse.email, abuse.networkAbuse contact of the registered blockReport attacks to the right network

Bot verification and coarse locations

Scrapers often claim to be a search engine crawler. Pass the visitor’s User-Agent header (up to 512 characters) in the user_agent parameter, and on plans with security data security.bot.spoofed says whether the address belongs to the operator of the claimed bot: true for a fake, false for a match, null when it cannot be decided. For many addresses, send user_agent in the batch request body, not the query string.

coarse_location=omit removes the city for anycast addresses and for coarse ones, such as mobile, carrier-grade NAT, satellite or relay networks, so you do not store a likely wrong city next to the risk result. It applies to paid plans with the network object.

Use cases: decide in tiers, not on one flag

Combine signals and choose between allow, challenge (CAPTCHA, one-time code, second factor) and review (a person checks the account or order).

  • Signup and free-trial abuse. Many trials from is_datacenter or is_proxy addresses point to scripts. Ask for email or phone verification.
  • Login risk. A login from a Tor exit or a known attacker address on an account that usually signs in from a home ISP justifies step-up verification, not a lockout.
  • Checkout fraud. Compare the IP country from the IP to country API with the billing country. A VPN plus a country mismatch plus a high order value goes to review; one of them alone usually does not.
  • Comment and form spam. is_spam and is_abuser are good reasons to queue a post for moderation.
  • Rate limiting. Give data center and proxy addresses a lower request budget.
  • Logs and SIEM enrichment. Run log addresses through the batch IP lookup API and store flags, score and abuse contact with each event.
  • Admin panels. An allowlist is safer; reputation data adds an alert when someone tries from a Tor exit or attacker address.

Code: look up the security object and decide

All examples run on the server, read the key from IPLOOKUPAPI_KEY, give up after 2 seconds and return no data instead of throwing. decide is an example policy; tune the thresholds on your own traffic.

Warning

Never put the API key in browser JavaScript or a mobile app bundle. The browser calls your backend, and your backend calls the API.

Decide up front what happens when the lookup fails. Fail open (allow) suits signups, comments and most logins, so an outage does not stop customers. Fail closed (challenge, not block) suits payouts, password changes and admin logins. On plans without security data, all security fields are null, and the examples treat that like a failed lookup.

Node.js (fetch)

JavaScript
// Node.js 18+ (built-in fetch). Server-side only: never ship the key to the browser.
const API_KEY = process.env.IPLOOKUPAPI_KEY;

async function getSecurity(ip) {
  const params = new URLSearchParams({ ip, fields: 'ip,security' });
  try {
    const res = await fetch(`https://api.iplookupapi.com/v1/info?${params}`, {
      headers: { apikey: API_KEY },
      signal: AbortSignal.timeout(2000), // a slow lookup must not block the signup
    });
    if (!res.ok) return null; // e.g. 403 plan, 404 no data, 429 rate limit or quota
    const { data } = await res.json();
    return data.security;
  } catch {
    return null; // timeout or network error
  }
}

// Example policy, not a recommendation: tune the thresholds on your own traffic.
function decide(security, { failClosed = false } = {}) {
  if (!security || security.threat_score === null) {
    return failClosed ? 'challenge' : 'allow'; // no data: fail closed or fail open
  }
  if (security.is_known_attacker || security.threat_score >= 70) return 'review';
  if (security.is_tor || security.is_proxy || security.threat_score >= 40) return 'challenge';
  return 'allow';
}

async function main() {
  const ip = '80.110.0.1'; // in a request handler: the client IP from your trusted proxy setup
  const security = await getSecurity(ip);
  console.log(ip, decide(security)); // 80.110.0.1 allow
}

main();

For a payout or an admin login, call decide(security, { failClosed: true }).

Python (requests)

Python
import os

import requests

API_KEY = os.environ["IPLOOKUPAPI_KEY"]


def get_security(ip):
    """Return the security object, or None if the lookup fails."""
    try:
        response = requests.get(
            "https://api.iplookupapi.com/v1/info",
            params={"ip": ip, "fields": "ip,security"},
            headers={"apikey": API_KEY},
            timeout=2,
        )
        response.raise_for_status()
        return response.json()["data"]["security"]
    except (requests.RequestException, KeyError, ValueError):
        return None  # timeout, network error, 4xx/5xx or unexpected body


def decide(security, fail_closed=False):
    """Example policy: returns 'allow', 'challenge' or 'review'."""
    if not security or security.get("threat_score") is None:
        return "challenge" if fail_closed else "allow"
    if security["is_known_attacker"] or security["threat_score"] >= 70:
        return "review"
    if security["is_tor"] or security["is_proxy"] or security["threat_score"] >= 40:
        return "challenge"
    return "allow"


print(decide(get_security("80.110.0.1")))  # allow

PHP (cURL)

PHP
<?php
function getSecurity(string $ip): ?array
{
    $query = http_build_query(['ip' => $ip, 'fields' => 'ip,security']);
    $ch = curl_init('https://api.iplookupapi.com/v1/info?' . $query);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['apikey: ' . getenv('IPLOOKUPAPI_KEY')],
        CURLOPT_CONNECTTIMEOUT => 1,
        CURLOPT_TIMEOUT => 2,
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

    if ($body === false || $status !== 200) {
        return null; // timeout, network error, 403, 404, 429 and so on
    }
    return json_decode($body, true)['data']['security'] ?? null;
}

// Example policy: returns 'allow', 'challenge' or 'review'
function decide(?array $security, bool $failClosed = false): string
{
    if ($security === null || $security['threat_score'] === null) {
        return $failClosed ? 'challenge' : 'allow';
    }
    if ($security['is_known_attacker'] || $security['threat_score'] >= 70) {
        return 'review';
    }
    if ($security['is_tor'] || $security['is_proxy'] || $security['threat_score'] >= 40) {
        return 'challenge';
    }
    return 'allow';
}

// In a web request, pass the client address you trust, e.g. $_SERVER['REMOTE_ADDR']
echo decide(getSecurity('80.110.0.1')) . PHP_EOL; // allow

The official SDKs wrap the same endpoint if you prefer a client library.

False positives and fair use of IP reputation

IP reputation describes an address, and one address can stand for one person or thousands.

  • Shared addresses. Carrier-grade NAT, mobile networks, universities and offices put many users behind one IP, and one infected device gets it reported for all. Check network.is_cgnat, network.is_mobile and network.as_type before acting on is_abuser.
  • Legitimate anonymity. Corporate VPNs, iCloud Private Relay and Tor protect ordinary users. Use the flags for context, not punishment.
  • Change over time. Abuse and attacker flags describe recent activity, and addresses get reassigned. Cache results for hours, not weeks.
  • Unknown is not clean. A new proxy is not on any list yet. false means “not known”, and threat_score: 0 means “no known threat”.
  • A way through. Never block on IP alone. Offer an alternative to every challenge and a support contact for every review, and log the reason so you can reverse a decision.

See what an IP address tells you about a person, and what it does not.

Privacy: IP addresses are personal data under the GDPR

The GDPR names internet protocol addresses as online identifiers in Recital 30, so treat them as personal data. Recital 49 recognizes processing that is strictly necessary and proportionate for network and information security as a legitimate interest. Mention the check in your privacy notice, store the decision and flags rather than full results, set a retention period, and ask your counsel which rules apply.

Plans: which plan includes IP reputation data

PlanPrice per monthRequests per monthData included
Free$0150 (10 per minute)Location, connection, time zone, currency
Basic$9.9965,000Adds network, company and abuse contact
Professional$34.99650,000Adds security data: flags and threat score
Enterprise$74.992,500,000Same data as Professional

Yearly billing gives you two months free. Use the Free plan to test the request format; the security fields stay null below Professional. A 429 means rate limit or monthly quota, and GET /v1/status shows your remaining quota without counting against it. Compare plans on the pricing page, or register for a free key and run the curl command above.

Frequently asked questions

What is an IP reputation API?

An IP reputation API tells you what is known about an IP address from a risk point of view: whether it belongs to a VPN, proxy, Tor exit or data center, and whether threat feeds and blocklists have recently reported it for attacks, abuse or spam. iplookupapi returns this in the security object of GET /v1/info, together with a threat score from 0 to 100. It describes the address, not the person behind it.

How is an IP's threat score used?

The threat_score in the security object runs from 0 (no known threat) to 100 in steps of 10 and combines anonymity type, scanner activity, data center hosting and threat feeds. Use it to pick a response tier, such as allow, ask for an extra verification step, or hold for manual review, and tune the thresholds on your own traffic. A score of 0 means nothing is known against the address, not that the visitor is trustworthy.

Can an IP reputation API detect VPNs and proxies?

It can flag addresses that are known to belong to them. The security object has is_vpn for commercial or consumer VPN servers, is_proxy for public or open HTTP and SOCKS proxies, is_tor for Tor exit nodes and is_icloud_relay for iCloud Private Relay, plus proxy_type with the main type. An address that no list knows yet is not flagged, so treat a false value as “not known” rather than “not a VPN”.

Should I block traffic based on IP reputation?

Rarely on the IP alone. Shared addresses, carrier-grade NAT, corporate VPNs and privacy relays put many legitimate users behind one IP, so a hard block also stops real customers. Use the flags and the threat score to add friction, such as a CAPTCHA or a one-time code, or to queue a review, and give people a way to reach support.

Is IP reputation data available on the free plan?

No. The security object is part of the Professional plan ($34.99 per month, 650,000 requests) and up. On other plans the object is still in the response, but all its fields are null. The Free plan (150 requests per month) covers location, connection, time zone and currency, and Basic adds network, company and abuse-contact data. See pricing for all plans.

Can I check many IP addresses for reputation at once?

Yes. POST /v1/batch accepts 1 to 1,000 IPv4 and IPv6 addresses in one request and returns the security object for each address on plans with security data. Each valid address counts as one request, duplicates are billed once, and invalid items are listed in errors without being billed. See the batch IP lookup API.

Look up IP addresses in your code

iplookupapi returns the location, provider, time zone and security flags of any IP address as JSON. The free plan includes 150 requests a month.

curl "https://api.iplookupapi.com/v1/info?ip=8.8.8.8" \
  -H "apikey: YOUR_API_KEY"