Prerequisites
- Node.js 18+ with
ip-api-ioinstalled - A free ip-api.io API key
Catch typed errors
Every error extends IpApiError, which carries statusCode and the raw response body. Catch the specific subclass you care about.
import {
IpApiClient,
IpApiError,
AuthenticationError,
RateLimitError,
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");
console.log(info.location.country);
} catch (error) {
if (error instanceof RateLimitError) {
console.log(`quota hit — resets at ${error.reset}`);
} else if (error instanceof AuthenticationError) {
console.log("check your API key");
} else if (error instanceof InvalidRequestError) {
console.log("bad request:", error.message);
} else if (error instanceof ServerError) {
console.log("ip-api.io is having trouble, try later");
} else if (error instanceof IpApiError) {
console.log(`error ${error.statusCode}: ${error.message}`);
} else {
throw error; // network / timeout — native fetch error
}
} fetch error — e.g. an AbortError once timeoutMs
elapses — not an IpApiError.
Handle rate limits with RateLimitError
On HTTP 429 the client throws RateLimitError, parsed from the x-ratelimit-* headers. Because the client never retries, reset tells you when to.
try {
await client.lookup("8.8.8.8");
} catch (error) {
if (error instanceof RateLimitError) {
console.log(error.limit); // your quota for the window
console.log(error.remaining); // requests left (0 here)
console.log(error.reset); // unix timestamp when quota renews
const waitMs = (error.reset ?? 0) * 1000 - Date.now();
// schedule a retry after `waitMs` instead of hammering the API
}
} Check quota proactively with rateLimit
Read your current limits without triggering a 429, so you can throttle in advance.
const rl = await client.rateLimit();
console.log(rl.plan_name);
console.log(rl.ip_api.remaining, "/", rl.ip_api.limit);
console.log(rl.email_api.usage_percent, "% used");
console.log(rl.next_renewal_date); Account usage with usageSummary
Aggregate usage for the current period — handy for dashboards and internal alerts.
const usage = await client.usageSummary();
console.log(usage.totalRequests, usage.successfulRequests);
console.log(usage.rateLimitedRequests, usage.quotaConsumed);
console.log(usage.periodStart, "→", usage.periodEnd);