IP Geolocation — Country, City, ISP, CSV, No API Key, Bulk avatar

IP Geolocation — Country, City, ISP, CSV, No API Key, Bulk

Pricing

Pay per usage

Go to Apify Store
IP Geolocation — Country, City, ISP, CSV, No API Key, Bulk

IP Geolocation — Country, City, ISP, CSV, No API Key, Bulk

20 runs. IP intel as CSV/JSON — country, region, city, ISP, ASN, timezone, lat/lon, isMobile/isProxy flags. Accepts IPs + domains. Backed by 951-run Trustpilot flagship + 31-actor portfolio. For fraud + ad-targeting + GDPR audits. spinov001@gmail.com · blog.spinov.online · t.me/scraping_ai

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Alex

Alex

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

0

Monthly active users

3 days ago

Last modified

Share

IP Geolocation Lookup — Bulk IP & Domain → Country, ISP, ASN

Resolve a list of IPv4 addresses (and/or domain names) to country / region / city / ISP / ASN / mobile / proxy / hosting flags using the public ip-api.com JSON API. Domain inputs are first resolved to A records via Google DNS, then each resolved IP is looked up.

Verified against src/main.js — every output field below is what the actor actually pushes.


What you get per IP (24 fields)

FieldTypeExampleSource
ipstring8.8.8.8ip-api query
continentstringNorth Americaip-api continent
continentCodestringNAip-api continentCode
countrystringUnited Statesip-api country
countryCodestringUSip-api countryCode
regionstringCaliforniaip-api regionName (full name)
regionCodestringCAip-api region (code)
citystringMountain Viewip-api city
zipstring94043ip-api zip
latitudenumber37.386ip-api lat
longitudenumber-122.084ip-api lon
timezonestringAmerica/Los_Angelesip-api timezone
utcOffsetnumber-25200ip-api offset (seconds)
currencystringUSDip-api currency
ispstringGoogle LLCip-api isp
organizationstringGoogle Public DNSip-api org
asnstringAS15169 Google LLCip-api as
asnNamestringGOOGLEip-api asname
reverseDnsstringdns.googleip-api reverse
isMobilebooleanfalseip-api mobile
isProxybooleanfalseip-api proxy (commercial proxy / VPN / Tor exit)
isHostingbooleantrueip-api hosting (datacenter ASN)
inputDomainstring | nullexample.comfirst domain in input (when domains supplied)
scrapedAtISO string2026-04-29T10:30:00Zactor capture time

Inputs

ParameterTypeDefaultDescription
ipAddressesstring[][]IPv4 addresses (e.g. ["8.8.8.8", "1.1.1.1"])
domainsstring[][]Domain names — resolved to A records via Google DNS, then each A record is looked up

If both are empty the actor pushes { error: 'No IPs or domains provided' }.


Rate limits and capacity (corrected math)

  • ip-api.com free tier: 45 requests / minute, HTTP only (HTTPS requires paid plan — see security note below)
  • The actor enforces 1500 ms delay between lookups + a 60 s pause after every 40 lookups
  • Sustained throughput ≈ 20 IPs/min: 40 lookups × 1.5 s = 60 s, then 60 s pause = 120 s per batch of 40 → 40/120 s = 20/min
  • Practical capacity per 10-min run: ~200 IPs (NOT 400 — earlier README overstated this)
  • For larger lists: split across runs, or request a custom build with ip-api Pro key (no rate-limit, HTTPS)

Use cases

  • Security / SOC — enrich IPs from SIEM/WAF logs with country + ISP + ASN signals
  • Fraud prevention — flag sign-ups whose declared country mismatches countryCode
  • Ops mapping — segment events by asn / country to spot unusual traffic patterns
  • Analytics — append country + region + city to event data for dashboards
  • Datacenter detectionisHosting: true indicates the IP belongs to a hosting/cloud provider ASN

Quick start

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("knotless_cadence/ip-geolocation-lookup").call(
run_input={
"ipAddresses": ["8.8.8.8", "1.1.1.1"],
"domains": ["example.com", "github.com"],
}
)
for r in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"{r['ip']:18} {r['countryCode']} {r['city']:20} {r.get('asn','')}")
if r.get('isHosting'):
print(f" ↳ hosting/datacenter")
if r.get('isProxy'):
print(f" ↳ proxy/VPN/Tor exit (ip-api flag)")

Bash one-liner

curl -s "https://api.apify.com/v2/acts/knotless_cadence~ip-geolocation-lookup/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ipAddresses":["8.8.8.8","1.1.1.1"]}' \
| jq '.[] | {ip, countryCode, city, asn, isHosting, isProxy}'

How it works

  1. Build the IP queue: ipAddresses + DNS-resolved A records from domains
  2. For each IP: call http://ip-api.com/json/<ip>?fields=... with the 24-field bitmask
  3. Push the normalized record to the dataset with inputDomain (first input domain) + scrapedAt
  4. 1.5s delay between calls; 60s pause every 40 calls

The isProxy flag aggregates ip-api's commercial-proxy / VPN / Tor-exit detection — it does not distinguish between those categories. For higher-fidelity Tor detection, cross-reference against the public Tor relay list separately.


  • SSL Certificate Checker — cert chain, expiry, fingerprint → apify.com/knotless_cadence/ssl-certificate-checker
  • Whois Domain Lookup — RDAP-backed domain registration data → apify.com/knotless_cadence/whois-domain-lookup
  • Website Tech-Stack Detector — frameworks, CDN, analytics → apify.com/knotless_cadence/website-tech-stack-detector
  • PageSpeed Insights Scraper — Core Web Vitals → apify.com/knotless_cadence/pagespeed-insights-scraper

Need a custom build?

Apify-as-a-Service tiers:

  • Pilot — $97: 1 actor, basic config, 7-day support
  • Standard — $297: custom actor + Slack/email alerts, 30-day support
  • Premium — $797: custom actor + dashboard + 90-day support + 1 modification round

Common custom builds for IP enrichment: SIEM webhook integration, multi-source aggregation (paid ip-api + IPinfo + MaxMind), high-throughput async pipelines bypassing the 45/min free-tier cap.

Email: spinov001@gmail.com Blog (case studies): https://blog.spinov.online Telegram channel (scraping & data engineering): https://t.me/scraping_ai


Honest disclosure / limitations

  • HTTP not HTTPS — ip-api.com's free tier is HTTP-only (HTTPS requires paid plan). Geolocation responses traverse the public network in cleartext; on hostile WiFi / shared infrastructure they are MITM-tamperable. For tamper-resistant enrichment, use ip-api Pro (paid) or MaxMind GeoIP2 (offline DB). Custom build available.
  • inputDomain is ALWAYS the FIRST domain in input — even when:
    • the IP came from ipAddresses (no domain associated at all → still tagged with domains[0] when domains.length > 0)
    • the IP came from a DIFFERENT domain than domains[0] in a multi-domain run (the actor doesn't track per-IP origin domain) → If you need accurate IP↔domain join, run one domain per call, or request a custom build that tracks origin per record.
  • Single-attempt fetch per IP — no retry on transient 5xx / network errors. Failed lookups are logged and skipped (no record pushed for that IP).
  • Sequential DNS resolutiondomains are resolved one-by-one against dns.google/resolve with no parallelism or retry; a slow DNS response delays the whole queue.
  • Single data source: ip-api.com public tier. The actor does NOT aggregate MaxMind, IP2Location, or IPinfo. For multi-source fallback / higher accuracy / no rate-limit, use the paid ip-api Pro tier or a separate enrichment service (custom build).
  • No standalone VPN/Tor/datacenter detection — only ip-api's own proxy (commercial proxy / VPN / Tor exit, aggregated) and hosting (datacenter ASN) flags. Heuristic, not exhaustive. For Tor-specific detection, cross-reference against the public Tor relay list separately.
  • 45 req/min upstream ceiling — actor sustains ~20/min after pauses. Practical capacity per 10-min Apify run = ~200 IPs (corrected from earlier "~400" overstatement).
  • IPv4 only via current code pathdns.google/resolve?type=A resolves to A records only; the actor does not request AAAA records, so domains inputs only return IPv4-mapped lookups. Direct IPv6 strings in ipAddresses are forwarded to ip-api which has its own IPv6 support.
  • zip and currency may be empty strings — ip-api does not return them for every IP (small-population regions, datacenter IPs).
  • Both ipAddresses = [] AND domains = [] → actor pushes a single { error: 'No IPs or domains provided' } record and exits.
  • Independent project — not affiliated with ip-api.com or Google.