JavaScript SDK

ip-api.io JavaScript SDK
npm install ip-api-io

ip-api-io is the official, zero-dependency client for Node.js and TypeScript. One typed client wraps IP geolocation, VPN/proxy/Tor detection, email validation, and fraud risk scoring — with built-in error classes and batch helpers, so you write the call, not the plumbing.

What you'll build

  • Install and initialize the typed client
  • Look up any IP — or the caller's IP — with one call
  • Detect VPN, proxy, Tor, and threats; batch up to 100 IPs
  • Handle rate limits and errors the production-ready way
Location
Mountain View, US
Threat signals
No VPN or proxy
TypeScript
Fully typed
await client.lookup("8.8.8.8")
{
"ip": "8.8.8.8",
"isp": "Google LLC",
"location": {
"country": "United States",
"city": "Mountain View",
"timezone": "America/Los_Angeles"
},
"suspicious_factors": {
"is_vpn": false,
"is_datacenter": true
}
}
Trusted by thousands of businesses
Fast JSON API responses
Real-time validation
Simple integration, SDKs & examples

Prerequisites

  • Node.js 18 or higher (the SDK uses the native fetch)
  • An ip-api.io API key — get one free
  • TypeScript is optional — types ship with the package
1

Install the package

Add the official ip-api-io package to your project. It has zero dependencies, ships both ESM and CommonJS builds, and includes TypeScript types — nothing else to install.

npm install ip-api-io
# or: pnpm add ip-api-io  /  yarn add ip-api-io
2

Initialize the client

Import IpApiClient and create one instance with your API key. Read the key from an environment variable — never hardcode it. The API rejects keyless requests with 401.

import { IpApiClient } from "ip-api-io";

const client = new IpApiClient({
  apiKey: process.env.IP_API_IO_KEY,
  // baseUrl and timeoutMs are optional:
  timeoutMs: 10000, // per-request timeout (default 10s)
});

Using CommonJS instead of ES modules? The package supports both:

const { IpApiClient } = require("ip-api-io");
3

Look up an IP address

Call lookup(ip) for any IPv4 or IPv6 address, or lookup() with no argument to resolve the caller's own IP. Every response includes a location object and a suspicious_factors object.

const info = await client.lookup("8.8.8.8");

console.log(info.ip);                       // "8.8.8.8"
console.log(info.isp);                       // "Google LLC"
console.log(info.location.country);          // "United States"
console.log(info.location.city);             // "Mountain View"
console.log(info.location.latitude,
            info.location.longitude);        // 37.4056 -122.0775
console.log(info.location.timezone);         // "America/Los_Angeles"

// Resolve the caller's own IP (no argument):
const me = await client.lookup();
console.log(me.ip, me.location.country);
TypeScript: lookup() returns a typed IpInfo object, so info.location.city and info.suspicious_factors.is_vpn autocomplete and type-check out of the box.
4

Detect VPN, proxy, Tor & batch lookups

The suspicious_factors object carries seven boolean flags on every lookup — this is what sets ip-api.io apart from plain geolocation APIs. You get security intelligence in the same call, at no extra cost.

const info = await client.lookup("185.220.101.45"); // example Tor exit node
const sf = info.suspicious_factors;

if (sf.is_vpn || sf.is_proxy || sf.is_tor_node) {
  console.log("Anonymized traffic — consider a CAPTCHA or block");
}
if (sf.is_datacenter) console.log("Cloud/datacenter IP — likely automated");
if (sf.is_threat)     console.log("Active threat signal — block this request");

const isRisky = sf.is_vpn || sf.is_proxy || sf.is_tor_node || sf.is_threat;

Need to check many IPs at once? lookupBatch takes up to 100 addresses in a single request (the SDK validates the limit before any network call):

const batch = await client.lookupBatch(["8.8.8.8", "1.1.1.1", "9.9.9.9"]);

console.log(batch.total_processed, batch.successful_lookups);

for (const [ip, result] of Object.entries(batch.results)) {
  console.log(ip, result.location.country, result.suspicious_factors.is_vpn);
}
Tip: want a single block / review / allow decision instead of raw flags? Use client.riskScore(ip) for a combined fraud risk score from 0.0 to 1.0.
5

Production-ready error handling

The client throws typed errors so you can react to each failure precisely. It never retries on its own — on a rate limit, RateLimitError tells you exactly when to try again.

import {
  IpApiClient,
  RateLimitError,
  AuthenticationError,
  InvalidRequestError,
  ServerError,
} from "ip-api-io";

const client = new IpApiClient({ apiKey: process.env.IP_API_IO_KEY });

try {
  const info = await client.lookup("8.8.8.8");
  // ... use info
} catch (err) {
  if (err instanceof RateLimitError) {
    // HTTP 429 — quota exhausted
    const waitMs = (err.reset ?? 0) * 1000 - Date.now();
    console.warn(`Rate limited. Remaining: ${err.remaining}. Retry in ${waitMs}ms`);
  } else if (err instanceof AuthenticationError) {
    console.error("Invalid or missing API key — get one free at https://ip-api.io");
  } else if (err instanceof InvalidRequestError) {
    console.error("Bad request:", err.message);
  } else if (err instanceof ServerError) {
    console.error("ip-api.io is having issues — try again later");
  } else {
    throw err; // network / timeout error from fetch
  }
}
No automatic retries: wrap calls in your own retry/backoff logic and use RateLimitError.reset (a Unix timestamp) to schedule the next attempt instead of hammering the API.

In an Express app, run the lookup server-side and pass the real client IP from the X-Forwarded-For header:

import express from "express";
import { IpApiClient } from "ip-api-io";

const app = express();
app.set("trust proxy", 1);
const client = new IpApiClient({ apiKey: process.env.IP_API_IO_KEY });

app.get("/check", async (req, res) => {
  const xff = req.headers["x-forwarded-for"];
  const clientIp = (Array.isArray(xff) ? xff[0] : xff?.split(",")[0])?.trim() || req.ip;

  try {
    const info = await client.lookup(clientIp);
    res.json({
      ip: info.ip,
      country: info.location.country,
      is_vpn: info.suspicious_factors.is_vpn,
      is_threat: info.suspicious_factors.is_threat,
    });
  } catch (err) {
    // Treat ip-api.io as a non-critical dependency
    res.status(200).json({ ip: clientIp, country: null });
  }
});
Reference

Response & method reference

lookup() resolves to a typed IpInfo object with three parts: the top-level ip/isp/asn, a suspicious_factors object, and a location object. Location fields are nullable for private ranges or unrecognized addresses.

await client.lookup("78.55.53.58")
{
  "ip": "78.55.53.58",
  "isp": "Deutsche Telekom AG",
  "asn": "AS3320",
  "suspicious_factors": {
    "is_proxy":      false,
    "is_tor_node":   false,
    "is_spam":       false,
    "is_crawler":    false,
    "is_datacenter": false,
    "is_vpn":        false,
    "is_threat":     false
  },
  "location": {
    "country":           "Germany",
    "country_code":      "DE",
    "city":              "Berlin",
    "latitude":          52.5694,
    "longitude":         13.3753,
    "zip":               "13409",
    "timezone":          "Europe/Berlin",
    "local_time":        "2024-05-20T22:16:52+02:00",
    "local_time_unix":   1716236212,
    "is_daylight_savings": true
  }
}

suspicious_factors — security signals (all boolean)

FieldDescription
is_vpnVPN service, corporate gateway, or self-hosted VPN detected
is_proxyHTTP, HTTPS, or SOCKS proxy (~99.5% accuracy)
is_tor_nodeTor exit node, relay, or bridge (updated in real time)
is_datacenterCloud provider (AWS, GCP, Azure), VPS, or hosting facility
is_threatActive security threat — malware C&C, botnet, or DDoS source
is_spamAssociated with spam, phishing, or malware email campaigns
is_crawlerKnown web crawler, scraper, or bot

location — geographic and timezone data

FieldTypeDescription
countrystringFull country name in English (ISO 3166-1)
country_codestringISO 3166-1 alpha-2 code (e.g. "DE", "US")
citystringCity or municipality name (85–95% accuracy)
latitudenumberDecimal degrees, WGS84 — ~50 km median accuracy radius
longitudenumberDecimal degrees, WGS84 — ~50 km median accuracy radius
zipstringPostal or ZIP code in country-specific format
timezonestringIANA timezone identifier (e.g. "America/Los_Angeles")
local_timestringCurrent local time in ISO 8601 with UTC offset
local_time_unixnumberUnix timestamp (seconds) in local timezone
is_daylight_savingsbooleanTrue if currently observing DST; null if not applicable

Client methods

MethodReturnsWhat it does
lookup(ip?)IpInfoGeolocate one IP, or the caller's IP if omitted
lookupBatch(ips)BatchIpLookupResponseGeolocate up to 100 IPs in one call
riskScore(ip?)RiskScoreFraud risk score (0.0–1.0) for an IP
torCheck(ip)TorDetectionCheck whether an IP is a Tor node
emailInfo(email)EmailInfoBasic email validation (syntax, MX, disposable)
validateEmail(email)AdvancedEmailValidationFull validation incl. SMTP deliverability
asn(ip)AsnLookupAutonomous System Number lookup
whois(domain)WhoisWHOIS domain registration info
domainAge(domain)DomainAgeDomain registration date and age in days
rateLimit()RateLimitInfoRemaining quota and plan limits
Full surface: the client also exposes validateEmailBatch, emailRiskScore, ipReputation, reverseDns, forwardDns, mxRecords, domainAgeBatch, and usageSummary. See the README and per-feature guides.
FAQ

Frequently asked questions

Common questions about the ip-api.io JavaScript SDK.

Is the ip-api-io npm package official?

Yes. ip-api-io is the official JavaScript/TypeScript client for ip-api.io, maintained by the ip-api.io team and published to npm from github.com/ip-api-io/ipapi-js. It is MIT licensed and not affiliated with ip-api.com or ipapi.com.

What is the npm package name for the ip-api.io SDK?

The package is named ip-api-io. Install and import it like this:

// npm install ip-api-io
import { IpApiClient } from "ip-api-io";
const client = new IpApiClient({ apiKey: process.env.IP_API_IO_KEY });

It ships both ESM and CommonJS builds, with TypeScript types included.

Can I use the SDK in the browser?

No. Calling ip-api.io from the browser would expose your API key in the network tab. Use the SDK server-side in Node.js (18+). Your frontend calls your own backend endpoint, which uses the SDK to call ip-api.io — the key never leaves your server.

Does the SDK support TypeScript?

Yes. The package is written in TypeScript and ships full type definitions. lookup() returns a typed IpInfo with nested location and suspicious_factors, and errors are typed classes such as RateLimitError and AuthenticationError.

How do I handle rate limits?

On HTTP 429 the SDK throws a RateLimitError exposing limit, remaining, and reset parsed from the response headers. The client never retries automatically — catch the error and schedule your retry after the reset timestamp.

What's the difference between the SDK and using fetch directly?

Both call the same ip-api.io API. The SDK adds a typed client, batch validation, typed error classes, and automatic URL encoding so you write less boilerplate. If you'd rather call the API with raw fetch and no dependency, follow the JavaScript IP geolocation tutorial.

Pricing

Pricing

Start using IP-API.io to make your website safer and more user-friendly. Keep out unwanted bots, show visitors content that's relevant to where they are, and spot risky IP addresses quickly. It's perfect for making online shopping more personal and keeping your site secure. Get started today with one of the plans!

Small
€10 /mo
100,000 geo ip requests
10,000 advanced email validation requests
Location data
Email validation
Risk score calculation
Currency data
Time zone data
Threat data
Unlimited support
HTTPS encryption
Create Account to Subscribe
Medium
€20 /mo
300,000 geo ip requests
25,000 advanced email validation requests
Location data
Email validation
Risk score calculation
Currency data
Time zone data
Threat data
Unlimited support
HTTPS encryption
Create Account to Subscribe

Need support?

Explore how IP-API.io can enhance your security, provide robust bot protection, and improve IP geolocation accuracy for your applications.

Contact Support

Found a bug in the SDK?

The ip-api-io package is open source. Open an issue or pull request on GitHub and we'll take a look.

Open on GitHub