Prerequisites
- Python 3.8+ with
ip-api-ioinstalled - A free ip-api.io API key
Catch typed exceptions
Every exception extends IpApiError, which carries status_code and the raw response body. Catch the specific subclass you care about.
import os
from ipapi_io import (
IpApiClient,
IpApiError,
AuthenticationError,
RateLimitError,
InvalidRequestError,
ServerError,
)
client = IpApiClient(api_key=os.environ["IP_API_IO_KEY"])
try:
info = client.lookup("8.8.8.8")
print(info["location"]["country"])
except RateLimitError as e:
print(f"quota hit — resets at {e.reset}")
except AuthenticationError:
print("check your API key")
except InvalidRequestError as e:
print("bad request:", e)
except ServerError:
print("ip-api.io is having trouble, try later")
except IpApiError as e:
print(f"error {e.status_code}: {e}") urllib.error.URLError / socket.timeout, not an
IpApiError.
Handle rate limits with RateLimitError
On HTTP 429 the client raises RateLimitError, parsed from the x-ratelimit-* headers. Because the client never retries, reset tells you when to.
import time
try:
client.lookup("8.8.8.8")
except RateLimitError as e:
print(e.limit) # your quota for the window
print(e.remaining) # requests left (0 here)
print(e.reset) # unix timestamp when quota renews
wait = (e.reset or 0) - time.time()
# schedule a retry after `wait` seconds instead of hammering the API Check quota proactively with rate_limit
Read your current limits without triggering a 429, so you can throttle in advance.
rl = client.rate_limit()
print(rl["plan_name"])
print(rl["ip_api"]["remaining"], "/", rl["ip_api"]["limit"])
print(rl["email_api"]["usage_percent"], "% used")
print(rl["next_renewal_date"]) Account usage with usage_summary
Aggregate usage for the current period — handy for dashboards and internal alerts.
usage = client.usage_summary()
print(usage["totalRequests"], usage["successfulRequests"])
print(usage["rateLimitedRequests"], usage["quotaConsumed"])
print(usage["periodStart"], "->", usage["periodEnd"])