Block datacenter and bot signups with one IP lookup

published · September 4, 2026

Scripted signups come from cloud boxes. How is_datacenter, hosting_provider and asn_type separate them from people, and the proxy mistake that hides it.

Most scripted signups do not come from someone's living room. They come from a virtual machine at a cloud provider, because that is where scripts run: cheap, disposable, and reachable from a shell. A person filling in your form from home arrives on a broadband or mobile network with an operator whose name says telecom, cable or wireless. That single difference, infrastructure versus eyeball network, is the highest-yield check you can run on a registration, and one IP lookup answers it.

This guide shows what to read in the response, which decision to attach to each field, and the one server misconfiguration that quietly turns the check into noise.

What the response says about infrastructure

Three fields carry the answer, from broad to specific.

is_datacenter is true when the address sits in a known hosting or cloud range. It is built from two kinds of source: the providers' own published range lists (Amazon Web Services publishes ip-ranges.json, Google Cloud cloud.json, Microsoft its weekly service-tags file, Oracle its public ranges, DigitalOcean, Linode and Vultr RFC 8805 geofeeds, Cloudflare and Fastly their edge ranges) and the open X4BNet list, which classifies whole autonomous systems as datacenter space. The flag is tri-state: false is a checked negative, null means no feed covered the address family, which today never happens for this signal, since the feeds carry IPv6.

hosting_provider names the cloud when the address is inside that provider's own feed: Amazon Web Services, Google Cloud, Microsoft Azure, Oracle Cloud, DigitalOcean, Linode, Vultr, Cloudflare or Fastly. It stays null when the flag came only from the aggregate list, so a null does not mean "not hosting"; it means "hosting, provider not named".

asn_type classifies the network operator: hosting, isp, education, government, or null when the operator's name settles nothing. It is hosting whenever is_datacenter is true, and it is derived from the operator name otherwise, conservatively. An unrecognised name answers null rather than a guess.

Together they let you write the policy in plain terms. A signup from is_datacenter: true with hosting_provider: "Amazon Web Services" and a free-mail address is a script until proven otherwise. A signup from asn_type: "isp" with is_datacenter: false is a person on a home line, whatever else you know about them.

Attach a decision, not a score

The risk_score adds 40 for a datacenter address, which lands in the medium band on its own. That is deliberate: hosting space is not proof of abuse. Plenty of legitimate traffic comes from servers, including your own customers' backends calling your API, corporate VPN concentrators hosted in a cloud, and developers testing from a workstation in a datacenter office. A score is the wrong tool for a decision that depends on what the visitor is doing.

Branch on the flag and the context instead:

  • Free trial signups. Require email confirmation before the trial starts when is_datacenter is true. A script that cannot read a mailbox stops here; a person is delayed by a minute.
  • Account creation with a payment method. Let it through. The card check is stronger evidence than the network.
  • Contact and lead forms. Tag the lead with hosting_provider and route datacenter submissions to a review queue rather than to sales. Reading the provider name in the queue is often enough to close the case: a burst of leads from one cloud region is not a campaign result.
  • API calls to your own service. Never block on this flag. Your customers' servers live in datacenters by definition.

The IP intelligence guide documents every field the policy can read, and the endpoint reference carries the full example response.

Run it where the signup happens

A server-side check is one request. Send the address the visitor connected from, not the one in a form field, and read the flags:

curl https://spaw.co/api/v1/ip/203.0.113.9 \
  -H "Authorization: Bearer sk_live_…"
{
  "success": true,
  "data": {
    "ip": "203.0.113.9",
    "asn": 16509,
    "org": "Amazon.com, Inc.",
    "asn_type": "hosting",
    "is_datacenter": true,
    "hosting_provider": "Amazon Web Services",
    "is_tor": false,
    "is_vpn": false,
    "is_relay": false,
    "is_anonymous": false,
    "risk_score": 40,
    "risk_level": "medium",
    "risk_signals": [
      { "signal": "datacenter", "weight": 40, "dataset": "datacenter-ranges" }
    ]
  },
  "meta": { "credits_used": 1, "credits_remaining": 9, "cache_hit": false }
}

A repeat of the same address inside seven days is free, so a visitor who reloads the form does not cost a second credit. If your policy forbids keeping even that marker, add ?privacy=1 and every call is a fresh, billable lookup with no trace kept.

For a form that should react before the submit, the browser endpoint runs the same lookup from the page with a publishable key locked to your domains. Leave the ip field out and the visitor's own address is looked up. Give the key a daily credit cap, because it sits in page source; once the cap is spent the endpoint answers 429 KEY_SPEND_CAP_REACHED until the next day, and free answers never count toward it.

Batch the backlog

Existing accounts deserve the same look. Export the registration addresses of the last quarter and send them to POST /api/v1/ip/batch, up to 1,000 per call, or queue up to 100,000 as a bulk run and download the CSV. The hosting_provider column groups cleanly in a spreadsheet: a spike of accounts from one cloud, created minutes apart, with sequential usernames, is a pattern you can act on without any scoring at all. Bulk runs are billed per fresh answer, and repeats inside the run are looked up once.

The misconfiguration that makes everyone Cloudflare

If your application sits behind Cloudflare, or any reverse proxy, and you pass the connecting address to the lookup, every visitor comes back as hosting_provider: "Cloudflare" with is_datacenter: true. Nothing is wrong with the data. The address you sent really is Cloudflare's, because the proxy connected to you on the visitor's behalf.

Cloudflare puts the visitor's address in the CF-Connecting-IP header and appends it to X-Forwarded-For (Cloudflare's header reference, checked 2026-09-04: https://developers.cloudflare.com/fundamentals/reference/http-headers/). Your framework needs to be told which proxies to trust before it reads those headers, otherwise a visitor could forge them. In Laravel that is the trusted-proxies middleware; in Django, SECURE_PROXY_SSL_HEADER and a middleware that reads the forwarded address; in Express, app.set('trust proxy', …) with the proxy's ranges. Trust exactly the proxy's published ranges, never every address, and read only the headers the proxy sets itself.

The tell in your data is unmistakable: a steady stream of Cloudflare or Fastly addresses at signup, one per visitor, spread across the day. Real traffic from a CDN edge does not look like that. Fix the proxy configuration first, then re-run the batch; the datacenter flags that remain are the ones worth reading.

What the flag cannot tell you

Open range lists know where clouds and hosting providers are. They do not know whether a specific address at a residential ISP is being rented out as a proxy. A residential proxy looks, by construction, like a person on a home line: asn_type: "isp", is_datacenter: false, a plausible city. No open dataset can tell the two apart, and this API does not pretend to. If residential proxies are your problem, treat the datacenter flag as the first filter, not the last, and look at behaviour on your side: velocity per address, reuse of the same address across accounts, mismatches between the located country and the billing country.

Sources for the range data are named in every response. AWS documents its range file at https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html, Google Cloud at https://cloud.google.com/compute/docs/faq#find_ip_range, and RFC 8805 (https://www.rfc-editor.org/rfc/rfc8805) defines the geofeed format DigitalOcean, Linode and Vultr publish. All were checked on 2026-09-04.

What to do next

Related

markdown version: /guides/block-datacenter-and-bot-signups-with-an-ip-lookup.md

Verify addresses the same way

The Spaw API runs every check described here on each lookup, with an SMTP handshake that never sends mail. 10 free lookups a month, no card required.

Get your API key

More guides