Why Odoo Does Not Display Visitor Country and How to Fix It
An incorrectly formatted installed GeoIP package can completely halt country statistics. Learn how the error occurs, how to pinpoint it in four steps, and where the database originates.
A package that looks installed but does nothing
There was a GeoIP database on the server, and the path was in the configuration. Yet, every visitor was recorded as being from the country 'Unknown' for months, without a single line in the error log.
Odoo reads GeoIP data exclusively in the MaxMind DB format with the extension .mmdb. The Linux package geoip-database provides GeoIP.data different and long-deprecated format. The server reports GeoIP as installed but determines no country at all.
This is the most unpleasant kind of error. It doesn't crash, it writes nothing to the log, and its result looks plausible. A statistic showing 'Unknown' for every visitor reads like a website that simply has no international guests. Only cross-referencing with the server logs reveals that nothing is being determined at all. In our case, this took months.
The information in this post refers to Odoo 19 on Debian Trixie, verified on August 12, 2026.
Why Odoo cannot read the file
Odoo accesses the database via the library geoip2. It understands exactly one format. The older GeoIP.dat comes from the same house but belongs to the discontinued legacy series, for which MaxMind has not been providing data for years.
The Debian package contains exactly two files in Trixie:
/usr/share/GeoIP/GeoIP.dat
/usr/share/GeoIP/GeoIPv6.dat
Whoever apt install geoip-databaseexecutes and then checks the directory, finds files, and concludes that the matter is settled. The package name perpetuates this misconception.
A second detail costs time if you are not aware of it. Odoo opens the database once at the start of a job process and keeps the connection in memory. If you replace the file while the system is running, nothing changes. We tested this by deleting the file while it was in use. The queries continued to run and responded using the already deleted file. For practical purposes, this means that an update only takes effect after a restart, and a cron job that renews the file weekly runs in vain as long as no one restarts the service.
The second condition is called proxy_mode
Even with the correct file, the country remains empty if Odoo runs behind a Reverse Proxy and proxy_mode is missing from the configuration. Odoo then sees the proxy's address, usually 127.0.0.1. For a private address, every geolocation database returns an empty result, which is entirely correct.
Both causes look identical in the dashboard.
Therefore, it is worthwhile to check them separately rather than guessing at one location.
Two free sources, both requiring attribution
None of the useful databases are homemade, and both are free:
| Source | Account required | Update frequency | Edition |
|---|---|---|---|
| DB-IP Lite | no | monthly | Attribution (CC BY 4.0) |
| MaxMind GeoLite2 | yes, free | weekly | Attribution (CC BY-SA 4.0) |
We tested DB-IP Lite against the internal call Odoo makes. The file reports itself as DBIP-Country-Lite and resolves 8.8.8.8 to US, a German IPv4 address and a German IPv6 address each to DE. This is sufficient for a country statistic.
Attribution is a licensing requirement. For DB-IP the notice is "This product includes IP2Country data from DB-IP.com", for MaxMind "This product includes GeoLite2 data created by MaxMind". It must be placed where the evaluation is published, usually in the legal notice or privacy policy.
Both providers also sell more precise variants. Those needing cities, time zones, or ISPs can find the terms on their pricing pages. For the question of which country a visitor came from, the free versions are sufficient.
Four steps to narrow down the error
-
Is there actually a
.mmdbfile in the directory?bash ls -la /usr/share/GeoIP/ -
Does the configuration point to this file, and is
proxy_modeset?bash grep -E "^(geoip_country_db|proxy_mode)" /etc/odoo/odoo.conf -
Does the file respond to the internal call Odoo makes?
bash python3 -c "import geoip2.database as d; r=d.Reader('/usr/share/GeoIP/GeoLite2-Country.mmdb'); print(r.metadata().database_type, r.country('8.8.8.8').country.iso_code)"The database type and
US. -
Do new visits record a country? Only this check rules out
proxy_modeas the cause.
Step 3 is critical because it accesses the same library on the same path as the server. If it responds cleanly but the statistics remain empty, the visitor address will not be recorded.
Check the file first, then the network path. Changing both simultaneously makes it impossible to determine what actually helped later.
When the installation silently does the wrong thing
The format issue was not the only silent error that day. Two additional patterns emerged, and both affect any type of server installation, whether in a container or on a classic machine.
The tool geoipupdate is available in Debian as part of the contrib component. Those running a minimal base often have only main enabled. The installation then fails with "Package 'geoipupdate' has no installation candidate", even though the package is listed on the Debian website. This message is misleading because the package name is known, but no installable version is available. Check the package page for the component and verify whether the source is enabled.
Since then, we have obtained the tool directly from the manufacturer with a fixed version and verified checksum. This works consistently on any Debian system, regardless of whether the lines are in a Dockerfile or an Ansible playbook:
curl -fsSLo geoipupdate.deb \
"https://github.com/maxmind/geoipupdate/releases/download/v8.0.0/geoipupdate_8.0.0_linux_amd64.deb"
echo "6616449c83038b5a92908d0d6eee01595e594995248872ec5183c8488201f0fb geoipupdate.deb" | sha256sum -c -
dpkg -i geoipupdate.deb
The second pattern concerns pinned versions. We had a pinned Python version that long ago had two successors. The build still ran because old patch states remain in the registries. A pin that breaks reports itself. A pin that simply continues ages silently, and eventually the application runs on a foundation no one consciously chose anymore. We now automatically compare the pinned state against the current one of the same series and have the pipeline warn as soon as they diverge.
By the way, the geodatabase itself is not baked into any installation. Its distribution is not covered by licensing law, and because IP ranges are reassigned continuously, a bundled copy becomes obsolete anyway. It is loaded at runtime before the server process starts and resides on a persistent storage medium instead of in the image.
Since the overhaul, our settings page clearly states whether country detection is active and names the data source used. Anyone who wants to replicate this does not need an account or a contract: a file from DB-IP, an entry in the configuration, and a restart.