---
title: "IP Geolocation in Python: Free API Tutorial + Code"
slug: "/tutorials/ip-geolocation-in-python"
description: "Fetch IP geolocation in Python: location, timezone, currency, ASN, and VPN/proxy detection. Free tier, official library, code examples."
---

# How to Get IP Geolocation in Python (API Tutorial)

By Mudassar Tariq Software Engineer at IP Geolocation

Posted on June 19, 2026 | 9 min read

![How to Get IP Geolocation in Python (API Tutorial)](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/ipgeolocation-in-python-1.png)

IP geolocation in Python turns any IP address into real-world context: country, city, timezone, currency, and the network that owns it. Developers use it for fraud checks, localization, analytics, and access control.

This tutorial shows you how to get IP geolocation in Python with the [IPGeolocation API](https://ipgeolocation.io/ip-location-api.html) and its official Python library: install it, make your first lookup, read the response, and geolocate the real visitor hitting your app in Flask and FastAPI. An async client is shown too, with bulk and VPN/proxy detection as optional paid add-ons.

The core lookups run on a free API key: 1,000 lookups a day, no credit card. Security and bulk are paid add-ons, signposted where they appear. For the background on how IP geolocation works, see the [what is IP geolocation guide](https://ipgeolocation.io/guides/what-is-ip-geolocation-how-it-works). Here, we write code.

* * *

## TL;DR

*   **Get IP geolocation in Python:** install `ipgeolocationio`, create a client with your API key, call `lookup_ip_geolocation()` with an IPv4 or IPv6 address (or omit it for the caller's own IP), and read the `location`, `time_zone`, `currency`, and `asn` objects from the response.
*   **Sync, async, or no SDK:** the official library ships sync and async clients with typed responses; or call `https://api.ipgeolocation.io/v3/ipgeo` directly with `requests`.
*   **Visitor IP:** behind a proxy or CDN, geolocate the real client IP through your framework's trusted-proxy handling, not your server's address.
*   **Optional paid add-ons:** `include=["security"]` for VPN, proxy, and Tor detection, and the bulk endpoint for up to 50,000 IPs per request.
*   **Free vs paid:** the free plan gives 1,000 lookups per day with no credit card; [paid plans](https://ipgeolocation.io/pricing.html) add the optional modules.

* * *

## What you need

Python 3.8 or newer and a free API key. Follow along with the official library (recommended) or call the REST API directly with the `requests` module if you'd rather skip the SDK. Both call the same API and return the same data.

* * *

## Get your free API key

Create a free [IPGeolocation.io account](https://app.ipgeolocation.io/signup) and copy your API key from the dashboard. No card required. The [getting started guide](https://ipgeolocation.io/tutorials/getting-started-with-ip-geolocation-api) covers signup step by step.

The free tier covers core geolocation: location, country metadata, currency, ASN, and timezone. Security and bulk lookups are paid; see [pricing](https://ipgeolocation.io/pricing.html) for the current plans. Keep the key in an environment variable so it never ends up in your source or git history:

```bash
export IPGEOLOCATION_API_KEY="your_api_key_here"
```

* * *

## Your first lookup with the official library

The [official IPGeolocation.io Python library](https://ipgeolocation.io/documentation/ip-geolocation-api-python-sdk.html) gives you typed requests and responses, so your editor autocompletes fields instead of guessing at dictionary keys. Install it:

```bash
pip install ipgeolocationio
```

The package installs as `ipgeolocationio` and imports as `ipgeolocation`. Here's a complete lookup, key read from the environment, the call wrapped so a hiccup never takes down your request:

```python
import os
from ipgeolocation import (
    IpGeolocationClient,
    IpGeolocationClientConfig,
    LookupIpGeolocationRequest,
    IpGeolocationException,
)

config = IpGeolocationClientConfig(api_key=os.environ["IPGEOLOCATION_API_KEY"])

try:
    with IpGeolocationClient(config) as client:
        response = client.lookup_ip_geolocation(
            LookupIpGeolocationRequest(ip="8.8.8.8")
        )

    location = response.data.location
    if location is not None:
        print(location.country_name, location.city)   # United States Mountain View
    if response.data.time_zone is not None:
        print(response.data.time_zone.name)            # America/Los_Angeles
except IpGeolocationException as exc:
    print(f"IP geolocation lookup failed: {exc}")
```

`LookupIpGeolocationRequest` takes any IPv4 or IPv6 address, the response comes back typed, and optional sections are `None` until you request them, which is why each access is guarded.

The shorter SDK snippets below reuse the same `config`, client pattern, and imports where relevant; the `requests`, Flask, and FastAPI examples set up their own.

To geolocate the machine making the request, its own public IP, leave the `ip` out entirely:

```python
with IpGeolocationClient(config) as client:
    response = client.lookup_ip_geolocation(LookupIpGeolocationRequest())

print(response.data.ip)  # your public IP
```

Building on FastAPI, aiohttp, or another async stack? The library ships an `AsyncIpGeolocationClient` with the same methods as coroutines:

```python
import asyncio
import os
from ipgeolocation import (
    AsyncIpGeolocationClient,
    IpGeolocationClientConfig,
    LookupIpGeolocationRequest,
    IpGeolocationException,
)


async def geolocate(ip: str):
    config = IpGeolocationClientConfig(api_key=os.environ["IPGEOLOCATION_API_KEY"])
    try:
        async with AsyncIpGeolocationClient(config) as client:
            response = await client.lookup_ip_geolocation(
                LookupIpGeolocationRequest(ip=ip)
            )
        return response.data
    except IpGeolocationException as exc:
        print(f"Lookup failed: {exc}")
        return None


result = asyncio.run(geolocate("1.1.1.1"))
```

* * *

## Prefer no SDK? Use requests

If you'd rather not add the library, call the REST endpoint directly. You get plain dictionaries back, so reach into them with `.get()` and give the request a timeout:

```python
import os
from typing import Optional

import requests

API_KEY = os.environ["IPGEOLOCATION_API_KEY"]
ENDPOINT = "https://api.ipgeolocation.io/v3/ipgeo"


def geolocate(ip: str) -> Optional[dict]:
    try:
        resp = requests.get(
            ENDPOINT, params={"apiKey": API_KEY, "ip": ip}, timeout=5
        )
        resp.raise_for_status()
    except requests.exceptions.RequestException as exc:
        print(f"IP geolocation request failed: {exc}")
        return None
    return resp.json()


data = geolocate("8.8.8.8")
if data:
    location = data.get("location", {})
    print(location.get("country_name"), location.get("city"))
```

The `timeout` keeps a slow call from hanging your worker, and `raise_for_status()` turns a 401 or 429 into a real exception instead of letting you parse an error body as if it were location data.

* * *

## What IP geolocation in Python returns

A default response includes more fields than shown here. This trimmed example shows the sections most apps read first:

```json
{
  "ip": "8.8.8.8",
  "location": {
    "country_name": "United States",
    "state_prov": "California",
    "city": "Mountain View",
    "zipcode": "94043-1351",
    "latitude": "37.42240",
    "longitude": "-122.08421"
  },
  "country_metadata": { "calling_code": "+1", "tld": ".us", "languages": ["en-US", "es-US", "haw", "fr"] },
  "currency": { "code": "USD", "name": "US Dollar", "symbol": "$" },
  "asn": { "as_number": "AS15169", "organization": "Google LLC" },
  "time_zone": { "name": "America/Los_Angeles" }
}
```

![Annotated IPGeolocation.io JSON response showing location, ASN, currency, and time zone objects](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/sample-api-response-returned-for-a-single-ip-address-on-free-plan-1.svg)

On the free plan you get `location`, `country_metadata`, `currency`, basic `asn`, and `time_zone`. Paid plans add `network`, `company`, full `asn` detail, and the optional modules below. For the exact split by plan, see [plan capabilities](https://ipgeolocation.io/documentation/ip-geolocation-api-python-sdk.html#capabilities) and [default response sections](https://ipgeolocation.io/documentation/ip-geolocation-api-python-sdk.html#default-response-sections) in the SDK docs. Both IPv4 and IPv6 work.

If you only need a field or two, ask for them with `fields=["location.country_name"]` and the response stays small. That is one of several [request options](https://ipgeolocation.io/documentation/ip-geolocation-api-python-sdk.html#request-options) the SDK supports for advanced usage, alongside `lang`, `excludes`, custom headers, and output format:

```python
with IpGeolocationClient(config) as client:
    response = client.lookup_ip_geolocation(
        LookupIpGeolocationRequest(
            ip="8.8.8.8",
            fields=["location.country_name", "location.city", "time_zone.name"],
        )
    )

print(response.data.location.country_name)
```

* * *

## Geolocate your real visitors

Looking up `8.8.8.8` is the easy part. The real job is geolocating the person hitting your app, and behind a load balancer, Nginx, or a CDN, their IP is usually carried in `X-Forwarded-For`. Use trusted-proxy handling to resolve the client IP from that header, then look it up.

There's a security catch: a client can spoof `X-Forwarded-For`, so never read it blindly. In Python the clean fix is to let your framework resolve the client IP from the proxies you trust, rather than parsing the header by hand.

The address you can trust is the first one from the right that is not one of your proxies, never the leftmost value a client can fake. For which entry to trust and how to set this up behind Nginx, Cloudflare, and other proxies, see our guide to [getting the real client IP behind a proxy](https://ipgeolocation.io/guides/get-real-client-ip-address).

* * *

### 1. Flask

```python
import os
import requests
from flask import Flask, request
from werkzeug.middleware.proxy_fix import ProxyFix

app = Flask(__name__)
# Trust exactly the proxies in front of your app (here, one load balancer or CDN)
# so request.remote_addr is the real client IP, not a spoofable header.
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1)

API_KEY = os.environ["IPGEOLOCATION_API_KEY"]
ENDPOINT = "https://api.ipgeolocation.io/v3/ipgeo"


@app.route("/")
def home():
    ip = request.remote_addr or ""
    try:
        resp = requests.get(
            ENDPOINT, params={"apiKey": API_KEY, "ip": ip}, timeout=5
        )
        resp.raise_for_status()
        loc = resp.json().get("location", {})
        return {"ip": ip, "country": loc.get("country_name"), "city": loc.get("city")}
    except requests.exceptions.RequestException as exc:
        app.logger.warning("Geolocation failed for %s: %s", ip, exc)
        return {"ip": ip, "country": None, "city": None}
```

* * *

### 2. FastAPI

```python
import os
import requests
from fastapi import FastAPI, Request

app = FastAPI()
API_KEY = os.environ["IPGEOLOCATION_API_KEY"]
ENDPOINT = "https://api.ipgeolocation.io/v3/ipgeo"


# Run uvicorn with --forwarded-allow-ips set to your proxy IPs so request.client.host
# reflects the real client from X-Forwarded-For, only for proxies you trust.
@app.get("/")
def home(request: Request):
    ip = request.client.host if request.client else ""
    try:
        resp = requests.get(
            ENDPOINT, params={"apiKey": API_KEY, "ip": ip}, timeout=5
        )
        resp.raise_for_status()
        loc = resp.json().get("location", {})
        return {"ip": ip, "country": loc.get("country_name"), "city": loc.get("city")}
    except requests.exceptions.RequestException as exc:
        return {"ip": ip, "country": None, "city": None, "error": str(exc)}
```

![How a web app reads the real visitor IP from X-Forwarded-For behind a proxy](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/how-a-device-becomes-a-proxy-node.svg)

On Django, configure trusted proxies and read the resolved client IP rather than parsing the header yourself, then pass that IP to the same lookup. For CDN ranges (Cloudflare, AWS), trust the published CIDR ranges, not a single hard-coded IP. And skip the temptation to call the API with no `ip` to "get the user's location," because that geolocates your server, not your visitor.

* * *

## Handle errors in production

The library does not retry for you. Timeouts, rate limits, and server errors raise exceptions and stop, which is the right default and means you decide what to retry. Back off on the transient ones (429, 5xx, timeouts) and give up on the permanent ones (a bad key, an invalid IP):

```python
import os
import time
from ipgeolocation import (
    IpGeolocationClient,
    IpGeolocationClientConfig,
    LookupIpGeolocationRequest,
    RateLimitException,
    ServerErrorException,
    RequestTimeoutException,
    IpGeolocationException,
)

config = IpGeolocationClientConfig(
    api_key=os.environ["IPGEOLOCATION_API_KEY"],
    connect_timeout=5,
    read_timeout=5,
)


def lookup_with_retry(ip: str, attempts: int = 3):
    delay = 1.0
    for attempt in range(1, attempts + 1):
        try:
            with IpGeolocationClient(config) as client:
                return client.lookup_ip_geolocation(
                    LookupIpGeolocationRequest(ip=ip)
                )
        except (RateLimitException, ServerErrorException, RequestTimeoutException):
            if attempt == attempts:
                raise  # out of retries, let the caller handle it
            time.sleep(delay)
            delay *= 2  # 1s, 2s, 4s
        except IpGeolocationException as exc:
            print(f"Lookup failed permanently: {exc}")  # retrying will not help
            return None
```

Before you ship anything that exposes the key in a browser or serverless function, read [how to secure your API key before production](https://ipgeolocation.io/tutorials/secure-api-key-before-production).

* * *

## Quick reference

| Task | How |
| --- | --- |
| Look up one IP | `lookup_ip_geolocation(LookupIpGeolocationRequest(ip="8.8.8.8"))` |
| Look up the caller's own IP | omit the `ip` parameter |
| Look up a real visitor | use trusted-proxy handling to resolve the client IP, then look it up |
| Look up many IPs (paid) | `bulk_lookup_ip_geolocation(...)` |
| Flag VPN, proxy, or Tor (paid) | add `include=["security"]` |
| Skip the SDK | call `GET /v3/ipgeo` with `requests` |

Common mistakes to avoid:

*   Never expose your API key in browser JavaScript. Keep it server-side in an environment variable.
*   Do not omit `ip` when you want a visitor's location; an empty `ip` geolocates your server.
*   Do not trust `X-Forwarded-For` unless your own proxy sets it; let your framework resolve it from trusted proxies.
*   Cache results per IP to save credits, and request only the `fields` you need to reduce payload and latency.
*   Treat IP geolocation as approximate; do not make it your only fraud or access-control signal.

Examples tested with `ipgeolocationio` 2.0.0 on Python 3.8+.

* * *

## Optional paid modules: security, abuse, bulk

The same client reaches the rest of the API when you need it. These are paid features, so each one links to its full reference:

*   **VPN, proxy, and Tor detection:** add `include=["security"]` for a `security` object with `threat_score`, `is_vpn`, `is_proxy`, and `is_tor`. See the [IP Security API](https://ipgeolocation.io/ip-security-api.html).
*   **Network abuse contact:** add `include=["abuse"]` for the reporting contact behind an IP range. See the [Abuse Contact API](https://ipgeolocation.io/ip-abuse-contact-api.html).
*   **Bulk lookups:** `bulk_lookup_ip_geolocation()` against `/v3/ipgeo-bulk` handles up to 50,000 IPs in one request, returning a success or error per IP. For log enrichment, see the [IP enrichment guide](https://ipgeolocation.io/guides/what-is-ip-enrichment-and-why-logs-need-it).

## Frequently asked questions

### How do I get IP geolocation in Python?

**Answer:** Install the official library with `pip install ipgeolocationio`, or call `https://api.ipgeolocation.io/v3/ipgeo` with `requests`. Pass your API key and the target IP, then read the `location` object for the country, city, and coordinates of that IP. The free tier allows 1,000 lookups per day.

### How do I get the visitor's location from their IP in Flask or Django?

**Answer:** When your app runs behind a proxy or CDN, use trusted-proxy handling to resolve the visitor's IP from `X-Forwarded-For`, and fall back to the remote address otherwise. Pass that IP to the API. Do not omit the IP, because an empty value geolocates your server instead of the visitor.

### Is there a free IP geolocation API for Python?

**Answer:** Yes. The free tier gives 1,000 lookups per day with no credit card and returns location, timezone, currency, and basic ASN data. VPN and proxy detection, company data, and bulk lookup require a paid plan.

### How do I look up many IP addresses at once in Python?

**Answer:** Use the bulk endpoint `https://api.ipgeolocation.io/v3/ipgeo-bulk`, a single POST that accepts up to 50,000 IPs. The library's `bulk_lookup_ip_geolocation` returns a success or error result per IP, in input order, so one bad address never fails the whole batch. Bulk lookup is a paid feature.

### Does the IPGeolocation.io Python SDK support async?

**Answer:** Yes. Alongside the sync `IpGeolocationClient` (built on requests), the SDK ships `AsyncIpGeolocationClient` (built on httpx) with the same methods as coroutines. Use it with `async with` in FastAPI, aiohttp, or any async app, and share the same config object across both clients.

### Does the API support IPv6 addresses?

**Answer:** Yes. Every lookup accepts both IPv4 and IPv6 addresses, on the free and paid plans. Pass the address as the `ip` value exactly as you would an IPv4 address, and the response shape is identical.

* * *

## Where to go next

Grab a [free API key](https://app.ipgeolocation.io/signup), drop the first snippet into your project, and swap `8.8.8.8` for your visitor's IP once it runs. Add the retry wrapper before you ship, and turn on `include=["security"]` when you need to screen traffic.

For every method, option, and response field, see the full [Python SDK reference](https://ipgeolocation.io/documentation/ip-geolocation-api-python-sdk.html).

### Related Tutorials

[![How to Add Geolocation to Your Shopify Store](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/07/How-to-Add-Geolocation-to-Your-Shopify-Store.svg)](https://ipgeolocation.io/tutorials/add-geolocation-to-shopify)

[How to Add Geolocation to Your Shopify Store](https://ipgeolocation.io/tutorials/add-geolocation-to-shopify)

How to route Shopify visitors to the right market by country, and how to decide whether you need a geolocation app or Shopify's built-in redirect.

Posted on July 14, 2026

By [Anwar Ahmed](https://www.linkedin.com/in/anwar-ce/)

[Read More](https://ipgeolocation.io/tutorials/add-geolocation-to-shopify)

[![How to Get IP Geolocation in JavaScript (Node + Browser)](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/ip-geolocation-in-javascript.png)](https://ipgeolocation.io/tutorials/ip-geolocation-in-javascript)

[How to Get IP Geolocation in JavaScript (Node + Browser)](https://ipgeolocation.io/tutorials/ip-geolocation-in-javascript)

Get IP geolocation in JavaScript the right way: the official SDK in Node.js, the correct browser pattern without exposing your key, the visitor's real IP via Express and Next.js, and the location, timezone, currency, ASN, VPN, proxy and threat data the API returns.

Posted on June 24, 2026

By Mudassar Tariq

[Read More](https://ipgeolocation.io/tutorials/ip-geolocation-in-javascript)

[![How to Get IP Geolocation in PHP (API Tutorial)](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/ip-geolocation-in-php-1.png)](https://ipgeolocation.io/tutorials/ip-geolocation-in-php)

[How to Get IP Geolocation in PHP (API Tutorial)](https://ipgeolocation.io/tutorials/ip-geolocation-in-php)

Get IP geolocation in PHP with the official IPGeolocation.io library: install with Composer, run your first lookup, and read the real visitor IP in vanilla PHP and Laravel. Links to optional VPN/proxy, abuse contact, and bulk lookups on paid plans.

Posted on June 22, 2026

By Mudassar Tariq

[Read More](https://ipgeolocation.io/tutorials/ip-geolocation-in-php)

[![WooCommerce Fraud Prevention: Setup Guide for FraudShield](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/ghos-2.png)](https://ipgeolocation.io/tutorials/woocommerce-fraud-prevention-setup-guide-for-fraudshield)

[WooCommerce Fraud Prevention: Setup Guide for FraudShield](https://ipgeolocation.io/tutorials/woocommerce-fraud-prevention-setup-guide-for-fraudshield)

A full setup walkthrough for FraudShield, the WooCommerce fraud detection plugin built on the ipgeolocation.io API. Install to first protected order in under 20 minutes.

Posted on June 16, 2026

By [Anwar Ahmed](https://www.linkedin.com/in/anwar-ce/)

[Read More](https://ipgeolocation.io/tutorials/woocommerce-fraud-prevention-setup-guide-for-fraudshield)

[![How to Secure Your API Key Before Production](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/06/How-to-secure-your-ipgeolocation-api-key-before-production-1.jpg)](https://ipgeolocation.io/tutorials/secure-api-key-before-production)

[How to Secure Your API Key Before Production](https://ipgeolocation.io/tutorials/secure-api-key-before-production)

Your API key works in development, but shipping it as-is to production is a security risk. This tutorial covers environment variables, backend proxies, CORS-based auth, and usage monitoring for the IPGeolocation.io API.

Posted on May 14, 2026

By [Daud Ahmad](https://www.linkedin.com/in/daudahmad0303)

[Read More](https://ipgeolocation.io/tutorials/secure-api-key-before-production)

[![IP Geolocation in Google Tag Manager](https://blogs.ipgeolocation.io/blogs-site/content/images/2026/05/Frame-2147224987-3.svg)](https://ipgeolocation.io/tutorials/ip-geolocation-in-google-tag-manager)

[IP Geolocation in Google Tag Manager](https://ipgeolocation.io/tutorials/ip-geolocation-in-google-tag-manager)

Learn how to set up IP geolocation tracking in Google Tag Manager using the official IPGeolocation.io custom template. Covers API key setup, tag configuration, data layer variables, and practical use cases.

Posted on May 7, 2026

By [Anwar Ahmed](https://www.linkedin.com/in/anwar-ce/)

[Read More](https://ipgeolocation.io/tutorials/ip-geolocation-in-google-tag-manager)
