IPGeolocation Python SDK
Overview
Typed Python SDK for the IPGeolocation.io IP Location API.
- Single lookup (
/v3/ipgeo) and bulk lookup (/v3/ipgeo-bulk) - Sync client built on
requestsand async client built onhttpx - Typed response models plus raw JSON/XML methods
- Python 3.8+
Install
pip install ipgeolocationioPyPI package: ipgeolocationio
Package page: https://pypi.org/project/ipgeolocationio/
Import: ipgeolocation
Quick Start
from ipgeolocation import (
IpGeolocationClient,
IpGeolocationClientConfig,
LookupIpGeolocationRequest,
)
config = IpGeolocationClientConfig(api_key="YOUR_API_KEY")
with IpGeolocationClient(config) as client:
response = client.lookup_ip_geolocation(
LookupIpGeolocationRequest(ip="8.8.8.8")
)
print(response.data.ip)
if response.data.location is not None:
print(response.data.location.country_name)
print(response.data.location.city)
if response.data.time_zone is not None:
print(response.data.time_zone.name)1. Async
import asyncio
from ipgeolocation import (
AsyncIpGeolocationClient,
IpGeolocationClientConfig,
LookupIpGeolocationRequest,
)
async def main() -> None:
config = IpGeolocationClientConfig(api_key="YOUR_API_KEY")
async with AsyncIpGeolocationClient(config) as client:
response = await client.lookup_ip_geolocation(
LookupIpGeolocationRequest(ip="8.8.8.8")
)
print(response.data.ip)
if response.data.location is not None:
print(response.data.location.country_name)
asyncio.run(main())The async client exposes the same methods as coroutines. Use async with for cleanup, or call await client.aclose() manually.
Authentication
API key: Works on all plans for single lookup and bulk lookup.
config = IpGeolocationClientConfig(api_key="YOUR_API_KEY")Request-origin auth: Paid plans only, and only for single lookup. If your origin is allowlisted in the IPGeolocation dashboard, the SDK sends it in the Origin header.
config = IpGeolocationClientConfig(request_origin="https://app.example.com") request_origin must be an absolute http or https URL with no path, query string, or fragment. Bulk lookups always require api_key , even if request_origin is set. You can set both on the same config. Single lookups require at least one of them.
1. Client Config
| Field | Use |
|---|---|
api_key | API key auth for single lookup and bulk lookup |
request_origin | Paid request-origin auth for single lookup |
base_url | Override the API base URL |
connect_timeout | Time to wait for the connection in seconds |
read_timeout | Time to wait for the response body in seconds |
Notes
- Typed methods require JSON. For XML output, use the
_rawmethods withoutput=ResponseFormat.XML. - Optional modules need
include. Fields likesecurity,abuse,user_agent,hostname,geo_accuracy, anddma_codeonly appear in the response when you pass the matchingincludevalue. Without it, those fields will beNone. -
fieldsandexcludesonly filter the response. They do not enable optional modules or unlock paid data. - Domain lookup is paid only. Passing a domain as
ip="google.com"works on paid plans. Free plans get a 401. - The SDK does not retry. Timeouts, server errors, and rate limits raise exceptions directly. Implement your own retry logic if you need it.
- Do not reuse a closed client. After
close(),aclose(), or leaving awithorasync withblock, further requests raiseValidationException.
Plan Behavior
Responses vary by plan.
1. Capabilities
| Capability | Free | Paid |
|---|---|---|
| Single IPv4/IPv6 lookup | ||
| Domain lookup | ||
Bulk lookup ( /v3/ipgeo-bulk ) | ||
Non-English lang | ||
| Request-origin auth | ||
Optional modules via include | ||
include=["*"] | Base response only | All plan-available modules |
2. Default Response Sections
Default single-lookup response:
| Section | Free | Paid |
|---|---|---|
location | ||
country_metadata | ||
currency | ||
asn (basic: as_number , organization , country ) | ||
asn (full: adds type , domain , date_allocated , rir ) | ||
time_zone | ||
network | ||
company |
Examples
The examples below assume you already have a configured client in scope. See Quick Start for setup.
1. Caller IP
Omit the ip parameter to look up the IP of the machine making the request:
response = client.lookup_ip_geolocation(LookupIpGeolocationRequest())
print(response.data.ip) # your public IP2. Domain Lookup (Paid)
When you look up a domain, the response includes the resolved IP and the original domain name:
response = client.lookup_ip_geolocation(
LookupIpGeolocationRequest(ip="google.com")
)
print(response.data.ip) # resolved IP address
print(response.data.domain) # "google.com"3. Security and Abuse
response = client.lookup_ip_geolocation(
LookupIpGeolocationRequest(
ip="9.9.9.9",
include=["security", "abuse"],
)
)
if response.data.security is not None:
print(response.data.security.threat_score)
if response.data.abuse is not None and response.data.abuse.emails:
print(response.data.abuse.emails[0])4. User-Agent Parsing
To parse a visitor's user-agent string, pass include=["user_agent"] and send the visitor string in the request User-Agent header:
visitor_ua = (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) "
"AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9"
)
response = client.lookup_ip_geolocation(
LookupIpGeolocationRequest(
ip="115.240.90.163",
include=["user_agent"],
headers={"User-Agent": visitor_ua},
)
)
if response.data.user_agent is not None:
print(response.data.user_agent.name)
print(response.data.user_agent.operating_system)5. Filtered Response
Use fields to keep specific fields, or excludes to remove them:
response = client.lookup_ip_geolocation(
LookupIpGeolocationRequest(
ip="8.8.8.8",
include=["security"],
fields=["location.country_name", "security.threat_score", "security.is_vpn"],
excludes=["currency"],
)
)
if response.data.location is not None:
print(response.data.location.country_name)
if response.data.security is not None:
print(response.data.security.threat_score)
print(response.data.security.is_vpn)6. Raw XML
Typed methods only support JSON. For XML, use a raw method:
from ipgeolocation import ResponseFormat
response = client.lookup_ip_geolocation_raw(
LookupIpGeolocationRequest(ip="8.8.8.8", output=ResponseFormat.XML)
)
print(response.data) # raw XML string7. Bulk Lookup (Paid)
Bulk lookup uses POST and accepts up to 50,000 IPs or domains. Each item in the response is either BulkLookupSuccess or BulkLookupError :
from ipgeolocation import (
BulkLookupError,
BulkLookupIpGeolocationRequest,
BulkLookupSuccess,
)
response = client.bulk_lookup_ip_geolocation(
BulkLookupIpGeolocationRequest(
ips=["8.8.8.8", "invalid-ip", "1.1.1.1"],
include=["security"],
)
)
for result in response.data:
if isinstance(result, BulkLookupSuccess):
print(result.data.ip, result.data.security) # 8.8.8.8 Security(...)
elif isinstance(result, BulkLookupError):
print(result.error.message) # 'invalid-ip' is not a valid IP address.Request Options
1. Single Lookup
| Field | Type | Notes |
|---|---|---|
ip | str or None | IPv4, IPv6, or domain (domain is paid only). Omit for caller IP lookup. |
lang | Language , str , or None | Response language. Non-English requires a paid plan. |
include | sequence of strings | Optional modules to enable. See include values. |
fields | sequence of strings | Response field filter. Does not unlock data. |
excludes | sequence of strings | Response field filter. Does not unlock data. |
output | ResponseFormat or str | "json" (default) or "xml" . Typed methods require JSON. |
user_agent | str or None | Overrides the outbound User-Agent header. Takes precedence over headers["User-Agent"] . |
headers | mapping of strings | Custom request headers. Accept is always SDK-managed. Sequence values are sent as one comma-joined header line. |
2. Bulk Lookup
Bulk lookup accepts the same fields as single lookup, plus:
| Field | Type | Notes |
|---|---|---|
ips | sequence of strings | Required. Up to 50,000 IPs or domains. |
Differences from single lookup: Content-Type: application/json is always set by the SDK. Bulk lookup always requires api_key in the config, even if request_origin is also set.
3. include Values
| Value | What it adds |
|---|---|
security | security object (threat score, VPN/proxy/Tor detection, bot detection) |
abuse | abuse object (abuse contact info, emails, phone numbers) |
user_agent | user_agent object (browser, device, OS parsed from the request User-Agent header) |
hostname | hostname field (reverse DNS lookup) |
liveHostname | hostname field (live DNS) |
hostnameFallbackLive | hostname field (fallback to live DNS) |
geo_accuracy | location.locality , location.accuracy_radius , location.confidence |
dma_code | location.dma_code |
* | All optional modules available on your plan |
Supported lang values: en , de , ru , ja , fr , cn , es , cs , it , ko , fa , pt
Response Metadata
Every SDK method returns ApiResponse(data=..., metadata=...) .
- Typed single lookup returns
IpGeolocationResponse - Typed bulk lookup returns a list of
BulkLookupResult - Raw methods return the response body as a string
| Field | Type | Description |
|---|---|---|
status_code | int | HTTP status code |
duration_ms | int | Wall-clock request time in milliseconds, measured by the SDK |
credits_charged | int or None | Parsed from the X-Credits-Charged response header |
successful_records | int or None | Parsed from the X-Successful-Record response header |
raw_headers | read-only mapping | All response headers. Values are tuples of strings. |
Header access helpers:
metadata.header_values("Header-Name") # all values as a tuple
metadata.first_header_value("Header-Name") # first value or None1. JSON Serialization
Use to_json() or to_pretty_json() to serialize SDK objects:
from ipgeolocation import JsonOutputMode, to_pretty_json
# Compact mode (default): omits None fields
print(to_pretty_json(response.data))
# Full mode: includes None fields as null
print(to_pretty_json(response.data, mode=JsonOutputMode.FULL))Errors
All exceptions inherit from IpGeolocationException . The SDK does not retry failed requests.
Before the request is sent:
-
ValidationExceptionfor bad config, invalid request parameters, or calling a closed client
Transport problems:
-
RequestTimeoutExceptionfor timeouts -
TransportExceptionfor connection or other HTTP-level failures
API errors (non-2xx responses):
| Exception | HTTP Status |
|---|---|
BadRequestException | 400 |
UnauthorizedException | 401 |
NotFoundException | 404 |
MethodNotAllowedException | 405 |
PayloadTooLargeException | 413 |
UnsupportedMediaTypeException | 415 |
LockedException | 423 |
RateLimitException | 429 |
ClientClosedRequestException | 499 |
ServerErrorException | 5xx |
ApiException | Any other non-2xx |
All API exceptions have .status_code and .api_message attributes.