Skip to main content

IPyAPI

Tests Code Quality PyPI version Python versions License: MIT

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 IPyAPI and AsyncIPyAPI clients
  • Typed returnsReturnType.OBJECT (dataclass), ReturnType.DICT, or ReturnType.PYDANTIC
  • Optional Pydantic v2 — install with ipyapi[pydantic] to get validated Pydantic models
  • Batch lookupsget_batch() for multiple IPs (async uses asyncio.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@overload signatures 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

Release files for ipyapi 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ipyapi 0.2.0
File Size Uploaded
ipyapi-0.2.0.tar.gz 52.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ipyapi 0.2.0
File Interpreter ABI Platform
ipyapi-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 65.4 kB

Release files / ipyapi-0.2.0.tar.gz

Download URL ipyapi-0.2.0.tar.gz
Size 52.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c800199d4be2fa0dce0e40a24a6ef3eb4dc52543a2c3f78d8ba71e50464ac667
BLAKE2b-256 checksum
How to use checksums
c3d4b9a119fb4221410cc9558429f3e7d0d440351c53a16622c7d16641968912
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / ipyapi-0.2.0-py3-none-any.whl

Download URL ipyapi-0.2.0-py3-none-any.whl
Size 13.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ec407452dd1f5304a96106df2afdb924d60755a2eeef5bd2f331f75272b35120
BLAKE2b-256 checksum
How to use checksums
4f73ae3748659179c4451e52b814956c12ef088d3f4cf090a016c0d8c591fb48
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page