A modern Python client library for ipapi.co IP geolocation API
Project description
IPyAPI
A modern Python client library for the ipapi.co IP geolocation API. Built with httpx, full async support, automatic retries, and optional Pydantic v2 models.
Features
- Sync & Async — both
IPyAPIandAsyncIPyAPIclients - Typed returns —
ReturnType.OBJECT(dataclass),ReturnType.DICT, orReturnType.PYDANTIC - Optional Pydantic v2 — install with
ipyapi[pydantic]to get validated Pydantic models - Batch lookups —
get_batch()for multiple IPs (async usesasyncio.gather) - Auto retry — exponential backoff on 429 rate limit responses
- IP validation — client-side check before any network request
- Complete API coverage — all fields, all response formats (JSON, XML, CSV, YAML, JSONP)
- Full type hints —
@overloadsignatures for precise IDE inference - Python 3.10+
Installation
pip install ipyapi
# or
uv add ipyapi
With optional Pydantic support:
pip install 'ipyapi[pydantic]'
# or
uv add 'ipyapi[pydantic]'
Quick Start
Synchronous
from ipyapi import IPyAPI
with IPyAPI() as client:
location = client.get_location("8.8.8.8")
print(f"{location.city}, {location.country_name}")
# Mountain View, United States
Asynchronous
import asyncio
from ipyapi import AsyncIPyAPI
async def main():
async with AsyncIPyAPI() as client:
location = await client.get_location("8.8.8.8")
print(f"{location.city}, {location.country_name}")
asyncio.run(main())
Usage Examples
Return Types
from ipyapi import IPyAPI, ReturnType
with IPyAPI() as client:
# Default — returns IPLocation dataclass
location = client.get_location("8.8.8.8")
print(location.country_name)
# As dict
data = client.get_location("8.8.8.8", return_type=ReturnType.DICT)
print(data["country_name"])
# As Pydantic model (requires ipyapi[pydantic])
model = client.get_location("8.8.8.8", return_type=ReturnType.PYDANTIC)
print(model.country_name)
Batch Lookup
with IPyAPI() as client:
results = client.get_batch(["8.8.8.8", "1.1.1.1"])
for r in results:
print(f"{r.ip} — {r.org}")
Async batch runs concurrently via asyncio.gather:
async with AsyncIPyAPI() as client:
results = await client.get_batch(["8.8.8.8", "1.1.1.1"])
Retry Configuration
# Retry up to 5 times on 429, with 2s base backoff (sleeps 2, 4, 8, 16, 32s)
with IPyAPI(max_retries=5, retry_backoff=2.0) as client:
location = client.get_location("8.8.8.8")
Single Fields
with IPyAPI() as client:
print(client.get_ip())
print(client.get_city("8.8.8.8"))
print(client.get_country("8.8.8.8"))
print(client.get_country_name("8.8.8.8"))
print(client.get_timezone("8.8.8.8"))
print(client.get_currency("8.8.8.8"))
print(client.get_asn("8.8.8.8"))
print(client.get_org("8.8.8.8"))
# Any field by name
postal = client.get_field("postal", "8.8.8.8")
Raw Response Formats
with IPyAPI() as client:
json_data = client.get_location_raw("8.8.8.8", format="json")
xml_data = client.get_location_raw("8.8.8.8", format="xml")
csv_data = client.get_location_raw("8.8.8.8", format="csv")
yaml_data = client.get_location_raw("8.8.8.8", format="yaml")
Error Handling
from ipyapi import IPyAPI
from ipyapi.exceptions import InvalidIPAddressError, RateLimitError, IPyAPIError
with IPyAPI() as client:
try:
location = client.get_location("not-an-ip")
except InvalidIPAddressError:
print("Invalid IP address")
except RateLimitError:
print("Rate limited — retries exhausted")
except IPyAPIError as e:
print(f"API error {e.status_code}: {e.message}")
API Reference
Client constructors
IPyAPI(
api_key=None, # API key for paid plans
base_url="https://ipapi.co",
timeout=10.0, # seconds
max_retries=3, # retries on 429
retry_backoff=1.0, # base backoff in seconds (sleeps backoff * 2^attempt)
)
AsyncIPyAPI accepts the same parameters.
Methods
| Method | Returns |
|---|---|
get_location(ip=None, return_type=ReturnType.OBJECT) |
IPLocation / dict / PydanticIPLocation |
get_batch(ips, return_type=ReturnType.OBJECT) |
list[IPLocation] / list[dict] / list[PydanticIPLocation] |
get_field(field, ip=None) |
str |
get_location_raw(ip=None, format="json") |
str |
get_ip() |
str |
get_city(ip=None) |
str |
get_country(ip=None) |
str |
get_country_name(ip=None) |
str |
get_timezone(ip=None) |
str |
get_currency(ip=None) |
str |
get_asn(ip=None) |
str |
get_org(ip=None) |
str |
IPLocation fields
ip, network, version, city, region, region_code, country, country_name, country_code, country_code_iso3, country_capital, country_tld, continent_code, in_eu, postal, latitude, longitude, timezone, utc_offset, country_calling_code, currency, currency_name, languages, country_area, country_population, asn, org, hostname, latlong
Exceptions
All inherit from IPyAPIError:
| Exception | Trigger |
|---|---|
InvalidIPAddressError |
Invalid IP format (raised client-side) |
ReservedIPAddressError |
Reserved/private IP (raised by API) |
BadRequestError |
400 |
ForbiddenError |
403 |
NotFoundError |
404 |
MethodNotAllowedError |
405 |
RateLimitError |
429 after all retries exhausted |
Development
git clone https://github.com/wihlarkop/ipyapi.git
cd ipyapi
uv sync --all-extras
uv run pytest # run tests
uv run pytest --cov=ipyapi --cov-report=html # with coverage
uv run ruff check ipyapi/ tests/ # lint
uv run ruff format ipyapi/ tests/ # format
Rate Limits
- Free tier: 1,000 requests/day, 30 requests/minute
- For higher limits see ipapi.co pricing
License
MIT — see LICENSE for details.
Links
- API docs: ipapi.co/api
- PyPI: pypi.org/project/ipyapi
- Source: github.com/wihlarkop/ipyapi
- Issues: github.com/wihlarkop/ipyapi/issues
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ipyapi-0.2.0.tar.gz.
File metadata
- Download URL: ipyapi-0.2.0.tar.gz
- Upload date:
- Size: 52.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c800199d4be2fa0dce0e40a24a6ef3eb4dc52543a2c3f78d8ba71e50464ac667
|
|
| MD5 |
3bbb23f7c3b10ed2454fc606d2e1fad2
|
|
| BLAKE2b-256 |
c3d4b9a119fb4221410cc9558429f3e7d0d440351c53a16622c7d16641968912
|
File details
Details for the file ipyapi-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ipyapi-0.2.0-py3-none-any.whl
- Upload date:
- Size: 13.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec407452dd1f5304a96106df2afdb924d60755a2eeef5bd2f331f75272b35120
|
|
| MD5 |
92a42b99e542b08e584db609de13eeee
|
|
| BLAKE2b-256 |
4f73ae3748659179c4451e52b814956c12ef088d3f4cf090a016c0d8c591fb48
|