Skip to main content

Flask-IP2Location

A small Flask extension that looks up each visitor's IP address with the IP2Location Python library and stores the result in the Flask session — so any other view or template in the app can reuse it without repeating the lookup.

Installing

From PyPI, once published:

pip install flask-ip2location

From this source tree (editable install, for development):

pip install -e ".[dev]"

IP2Location and Flask are declared as dependencies in pyproject.toml and install automatically either way.

How it works

  • On the first request in a session, a before_request hook resolves the visitor's IP against your local IP2Location .BIN database and stores the result under session["ip2location"].
  • On later requests, if the visitor's IP hasn't changed, the cached value is reused — no repeat database queries.
  • Any view or Jinja template can read session["ip2location"] directly, or import the current_location proxy for convenience.

Quick start

  1. Get a database file. This extension requires a IP2Location database BIN file to work. You may obtain a free LITE database or purchase a commercial database as below:

    Save the .BIN file somewhere your app can read it.

  2. Wire it up

    from flask import Flask
    from flask_ip2location import IP2LocationFlask, current_location
    
    app = Flask(__name__)
    app.config["SECRET_KEY"] = "change-me"
    app.config["IP2LOCATION_DB_PATH"] = "/path/to/IP2LOCATION-LITE-DB11.BIN"
    
    ip2loc = IP2LocationFlask(app)
    
    @app.route("/")
    def index():
        return current_location["country_long"]
    
    @app.route("/other-page")
    def other_page():
        # Same session, same data, no extra lookup:
        return current_location["city"]
    

    Or with the application-factory pattern:

    ip2loc = IP2LocationFlask()
    
    def create_app():
        app = Flask(__name__)
        app.config["IP2LOCATION_DB_PATH"] = "..."
        ip2loc.init_app(app)
        return app
    
  3. Try the full demo:

    pip install -e .
    # edit examples/example_app.py to point at your .BIN file
    python examples/example_app.py
    

Reading the data elsewhere

Three equivalent ways to get the visitor's location in any view/template:

from flask import session
session["ip2location"]              # plain dict, or None
from flask_ip2location import current_location
current_location["country_long"]     # LocalProxy, behaves like the dict
{# register current_location as a Jinja global once, e.g.
   app.jinja_env.globals["current_location"] = current_location #}
{{ current_location.country_long }}

The stored value is a plain dict (or None if the lookup failed or was skipped), so it's JSON-serializable for AJAX endpoints too.

Configuration reference

Config key Default Description
IP2LOCATION_DB_PATH required Path to the .BIN database file.
IP2LOCATION_MODE None Passed to the underlying IP2Location.IP2Location() constructor, e.g. "SHARED_MEMORY" to load the whole file into memory for faster lookups.
IP2LOCATION_SESSION_KEY "ip2location" Session dict key the result is stored under.
IP2LOCATION_FIELDS None (auto) Optional allow-list restricting which auto-detected fields are kept, e.g. ["country_long", "city"]. By default every column your .BIN edition actually supports is kept automatically — see below.
IP2LOCATION_AUTO_LOOKUP True Automatically look up on every request via before_request. Set False and call ip2loc.refresh() yourself if you'd rather trigger it manually (e.g. only after login).
IP2LOCATION_SKIP_PRIVATE_IPS True Skip the database query entirely for loopback/private/reserved IPs (e.g. 127.0.0.1 during local dev), storing None instead of erroring.
IP2LOCATION_TRUST_PROXY_HEADER False Trust the client-supplied X-Forwarded-For header for the visitor IP. See the caveat below before turning this on.

Automatic column detection

You don't need to know which .BIN edition you're using or list its fields by hand — the extension detects them from the query result itself. Every possible IP2Location field (country, region, city, isp, asn, ...) is only ever populated by the library when your specific database edition supports it; unsupported fields never even get set on the result object. The extension keeps exactly the fields that came back populated, so:

  • A free DB1 (country-only) LITE database gives you a session dict with just ip, country_short, country_long.
  • A DB11 LITE database additionally gives you region, city, latitude, longitude, zipcode, timezone.
  • A commercial edition with ISP/ASN data gives you those too, automatically — nothing to configure, and nothing to update if you later upgrade your database edition.

If you want to keep only a subset regardless of what's available (e.g. to keep the session cookie small, or for privacy), set IP2LOCATION_FIELDS to an explicit list and it's applied as a filter on top of auto-detection.

Notes and caveats

  • Proxies/load balancers. If your app runs behind one, request.remote_addr will be the proxy's IP, not the visitor's. The correct fix is werkzeug.middleware.proxy_fix.ProxyFix configured for exactly as many trusted hops as you have, shown commented-out in examples/example_app.py. IP2LOCATION_TRUST_PROXY_HEADER is a blunter alternative that trusts whatever X-Forwarded-For value shows up, which a visitor can forge if nothing upstream is sanitizing it — only use it if you understand your deployment's proxy setup.
  • Session storage. Flask's default session is a signed-but-not-encrypted cookie: don't store anything sensitive in it. City/country/ISP data is usually fine, but if you widen IP2LOCATION_FIELDS or have privacy requirements, consider pairing this with a server-side session backend like Flask-Session.
  • LITE database fields. Free LITE editions only populate the fields their tier covers (e.g. DB1 is country-only). As described above, this is detected automatically per lookup rather than assumed from config.

Running the tests

pip install -e ".[dev]"
pytest

Tests monkeypatch IP2Location.IP2Location with a fake in tests/conftest.py, so no real .BIN database file is needed to run the suite.

License

See the LICENSE file.

Metadata

Release files for flask-ip2location 1.0.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 flask-ip2location 1.0.0
File Size Uploaded
flask_ip2location-1.0.0.tar.gz 14.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flask-ip2location 1.0.0
File Interpreter ABI Platform
flask_ip2location-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.7 kB

Release files / flask_ip2location-1.0.0.tar.gz

Download URL flask_ip2location-1.0.0.tar.gz
Size 14.3 kB
Tags Source
SHA-256 checksum
How to use checksums
114a141bcedfbfe6ff901cf2307007092087bed2d410cf96611630b0a04d6b89
BLAKE2b-256 checksum
How to use checksums
9c28b5199899bfda2a2397c7a197b4218ede2d31685ee187c01efe60afd134e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release files / flask_ip2location-1.0.0-py3-none-any.whl

Download URL flask_ip2location-1.0.0-py3-none-any.whl
Size 9.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fe2c40303171307671304d4835051a9fa3321e3012192b988300c2a181764b68
BLAKE2b-256 checksum
How to use checksums
5d38bb41b05e1e6e8471a4117e277dada1ed18da62a0bef077501768673bf623
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release history Release notifications | RSS feed

This release

1.0.0 This release

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