The problem
Almost every backend hits the same geolocation question: where is this IP from, and what timezone is it in? Maybe you're logging a request, gating content by region, or trying to render a timestamp in the user's local time. The good news: there are great public APIs for this. The awkward news: most Python libraries for IP geolocation either pull in a heavy dependency, wrap a paid service, or both.
I wanted something I could pip install once and then forget about — small, stdlib-only by default, working offline if I needed it, and with a result object I could pass around without thinking.
So I built BabelBeacon.
What it is
- A single
GeoResultdataclass: country, region, city, lat/lon, IANA timezone, ASN/ISP - Two backends:
-
http— usesip-api.com(no key, ~45 req/min, free for non-commercial) -
mmdb— uses a localGeoLite2-City.mmdbfile (offline, no rate limits)
-
- Built-in lat/lon → IANA timezone resolution (no external service, no API key)
- Haversine distance helpers in km and mi
- In-memory cache (so you don't re-look up the same IP twice in a request)
- A CLI:
python3 -m babelbeacon 8.8.8.8
No required third-party deps. The optional MMDB path uses only Python's struct module to read the database.
Quickstart
from babelbeacon import lookup, distance_km, timezone_for
r = lookup("8.8.8.8")
print(r.country, r.city, r.timezone)
# United States, Mountain View, America/Los_Angeles
# Pure offline — no network call
tz = timezone_for(28.6, 77.2)
print(tz) # Asia/Kolkata
# Distance between two points
d = distance_km(28.6, 77.2, 19.0, 72.8)
print(f"{d:.0f} km") # ~1157 km
The CLI:
$ python3 -m babelbeacon 8.8.8.8 1.1.1.1
8.8.8.8: US Mountain View America/Los_Angeles AS15169 Google
1.1.1.1: US San Francisco America/Los_Angeles AS13335 Cloudflare
$ python3 -m babelbeacon --timezone-for 28.6,77.2
Asia/Kolkata
$ python3 -m babelbeacon --distance 28.6,77.2,19.0,72.8
1157.21 km
The two backends
HTTP (default)
lookup("8.8.8.8", backend="http")
Hits http://ip-api.com/json/<ip>?fields=... via urllib.request. No API key. Returns the full record (country, region, city, lat, lon, timezone, ISP, ASN, ZIP).
I picked ip-api.com because:
- Free for non-commercial use
- No signup, no key to manage
- Already returns a normalized JSON with timezone included (most APIs don't)
If you need production throughput, switch to MMDB.
MMDB (offline)
lookup("8.8.8.8", backend="mmdb", mmdb_path="./GeoLite2-City.mmdb")
Reads a local MaxMind GeoLite2 database. No network call. Works in air-gapped environments. The reader is ~200 lines of pure Python + struct — no maxminddb package needed.
This is the path you'd use for:
- Serverless / Lambda where latency matters
- Air-gapped networks
- Production with high QPS where a public API would rate-limit you
Timezone resolution (the part I'm most proud of)
Almost every IP geolocation API will return a country and city. Most don't return an IANA timezone — because the mapping from lat/lon → timezone is annoying and nobody wants to maintain a 200 MB polygon dataset.
The trick: there are only ~400 IANA timezones, and most of them cluster around recognizable country/region/city anchors. So BabelBeacon ships with a small built-in table of ~150 well-known anchors (Delhi, London, NYC, Tokyo, Sydney, etc.) plus a fallback: pick the closest anchor in the same country (or failing that, the closest continent-level zone) and return its timezone.
This isn't perfect — try it in the middle of the Pacific ocean and you'll get an arbitrary anchor. But for practical use cases (rendering timestamps for logged-in users, scheduling emails, picking a default locale), it works 95% of the time. And the cases where it doesn't work are exactly the cases where any approach short of a polygon database would also fail.
Honest limits
- The HTTP backend is free but rate-limited (~45 req/min from a single IP). For production at scale, use MMDB.
- The MMDB reader doesn't support all of MaxMind's optional data types yet (just the core city/country/location fields). PRs welcome.
- The timezone resolver uses anchor-based nearest-neighbor, not polygons. Good enough for most use cases, not for the middle of the ocean.
- IP-API.com's free tier is not for commercial use. If you're a business, get a paid plan or use MMDB.
Why I built it this way
I was writing a logging pipeline and didn't want to add geoip2 + maxminddb + pytz + python-dateutil for the one place I needed to print a user's local time. I just wanted one dataclass and one function. So I wrote the smallest thing that could do the job, and now it's a library.
The whole thing is ~400 lines of code, 21 unit tests, and a CLI. Easy to read, easy to vendor, easy to fork.
Try it
git clone https://github.com/AmSach/babelbeacon
cd babelbeacon
python3 -m unittest tests.test_babelbeacon
python3 -m babelbeacon 8.8.8.8
Repo: https://github.com/AmSach/babelbeacon
MIT licensed. Issues and PRs welcome — especially the MMDB polygon-type support and more timezone anchors.
Top comments (0)