The Geographic Location audience criterion matches visitors by country, optionally narrowed to regions. For example: "is in the United States (California and Oregon only) or Canada", or "is not in France". It works by looking up the visitor's IP address in a free MaxMind GeoLite2 database kept on your own server.
Setting it up takes about ten minutes: a MaxMind account, two secrets, and one scheduled job. Until then the criterion appears in the audience builder greyed out, with a note saying what's missing.
1. Create a MaxMind account and sign up for GeoLite
- Go to maxmind.com and create an account.
- Sign in to the account portal and sign up for GeoLite, accepting the GeoLite licence when asked. Creating an account on its own doesn't give you GeoLite access; this second step does.
2. Generate a licence key
- In the account portal, open the Account menu and choose Manage License Keys.
- Click Generate new license key, give it a name you'll recognise (for example the site's name), and click Confirm.
- Copy the key straight away. MaxMind shows it only once. If you lose it, generate a new one and deactivate the old one.
Treat the licence key like a password.
3. Find your Account ID
Your Account ID is shown in the MaxMind account portal. It's also filled in for you in the
GeoIP.conf file the portal offers for download, on the line starting AccountID.
4. Store both as secrets
The Account ID and licence key must never go in appsettings.json or anything else you commit.
On your own machine, use user-secrets. Run these from your site's project folder, the one with
the .csproj. The first command is only needed once per project; the Starter template doesn't
enable user-secrets for you.
dotnet user-secrets init
dotnet user-secrets set "Cendia:GeoLocation:AccountId" "<your account id>"
dotnet user-secrets set "Cendia:GeoLocation:LicenseKey" "<your licence key>"
When hosted, set environment variables (or use your vault) with double underscores in place of
the colons: Cendia__GeoLocation__AccountId and Cendia__GeoLocation__LicenseKey.
5. Download the database
- Restart the site. It checks for credentials when it starts, and the criterion only becomes available after that check.
- In the CMS, go to Settings › Scheduled Jobs, find GeoIP Database Update, and press Start.
- After a few seconds the history should show a Succeeded run reading something like
Downloaded GeoLite2-City (65,921,355 bytes). The file is saved to
App_Data/GeoLite2-City.mmdb.
The job then repeats weekly, which matches how often MaxMind publishes updates. The new file is only swapped in once it opens successfully, and the site picks it up within a minute without a restart.
Keep the database out of source control. Make sure App_Data/ is in your .gitignore.
6. Try it on your own machine
A browser on the same machine arrives as ::1 (localhost), which has no location. So in the
Development environment, TestIp stands in for a localhost address. Add it to
appsettings.Development.json:
{
"Cendia": {
"GeoLocation": {
"TestIp": "81.2.69.142"
}
}
}
81.2.69.142 is in the United Kingdom. TestIp is ignored in every other environment, and for any
address that isn't localhost.
Then check the whole path:
- Create an audience with Geographic Location › Is in › United Kingdom.
- Personalise a block on a page with that audience.
- Load the page. You should see the UK version.
7. Before you go live
- Attribution. MaxMind's GeoLite licence requires it. The usual wording is "This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com". Check MaxMind's current licence for the exact wording and where it must appear.
- Proxies, CDNs and load balancers. Behind one, every visitor arrives with the proxy's address. Turn on forwarded headers (below) or every visitor will appear to be wherever your proxy is.
- Firewalls. The download goes to
download.maxmind.com, which redirects to a Cloudflare R2 storage host (MaxMind lists the exact hostname in its database update documentation). Your server needs outbound HTTPS to both. - Don't press Start repeatedly. MaxMind limits downloads per day. The weekly schedule stays well inside that limit.
Troubleshooting
| What you see | Why, and what to do |
|---|---|
| Geographic Location is greyed out in the builder | No credentials or database were found when the site started. Check the secrets are set for this project or environment, then restart. |
| The job succeeds with "Skipped: set Cendia:GeoLocation…" | The job can't see the Account ID or licence key. Same fix as above. |
| The job fails with "MaxMind refused the account id or licence key" | The ID or key is wrong, or the key was deactivated. Generate a new key and update the secret. |
| Nothing matches on your own machine | TestIp is missing, or the site isn't running in the Development environment. |
| Visitors all land in the same country when hosted | The site is behind a proxy. Configure ForwardedHeaders below. |
| Countries match but regions never do | The edition is GeoLite2-Country, which has no regions. Use the default, GeoLite2-City. |
Configuration reference
{
"Cendia": {
"GeoLocation": {
"DatabasePath": "App_Data/GeoLite2-City.mmdb",
"Edition": "GeoLite2-City"
}
}
}
DatabasePath is relative to the site's content root unless it's a full path. A database file you
place there yourself works too; with no credentials set, the job then skips instead of downloading.
Privacy
The lookup happens entirely on your server. No visitor address is sent to MaxMind, and nothing about the lookup is stored: a location is worked out when a page is requested, then discarded. It sets no cookie.
Behind a proxy, CDN or load balancer
The proxy passes the visitor's real address in X-Forwarded-For. Any visitor can send that header
too, so Cendia only believes it from proxies you name:
{
"Cendia": {
"ForwardedHeaders": {
"Enabled": true,
"KnownProxies": [ "10.0.0.4" ],
"KnownNetworks": [ "10.0.0.0/8" ],
"ForwardLimit": 1
}
}
}
When enabled, forwarded headers are handled first in the request pipeline, before anything that
reads the address, so you don't need to add any middleware yourself. This also corrects IP Range
and Number of Visits counted by IP address. With no KnownProxies or KnownNetworks, only a
proxy on the same machine is trusted, and a warning is logged at startup.