IP-based visitor country detection for Umbraco multi-language sites. Resolves visitor country via
CDN headers (Cloudflare, AWS CloudFront, Azure Front Door) with an offline MMDB fallback —
then maps the country code to a .NET CultureInfo so your site can switch language automatically.
Works with Umbraco 16, 17 and 18 (multi-targeted net9.0 / net10.0).
- Multi-source detection chain (first hit wins):
- Cloudflare —
CF-IPCountryheader - Akamai —
X-Akamai-Edgescapeheader (parsescountry_code=XX) - Fastly —
X-Geo-CountryorFastly-Client-Countryheader - Vercel —
X-Vercel-IP-Countryheader - Netlify —
X-Countryheader - AWS CloudFront —
CloudFront-Viewer-Countryheader - Azure Front Door —
X-Azure-ClientIP-Country/X-Azure-Geo-Countryheader - Forwarded IP resolution — handles
X-Forwarded-For,X-Real-IP,CF-Connecting-IP,True-Client-IP - Offline MMDB — local iplocate.io database (no external API calls)
- Cloudflare —
- Two output modes:
GetCountryCode()— raw ISO 3166-1 alpha-2 code (e.g. "VN", "US")Detect()→ fullGeoLocationResultwith mappedCultureInfo
- Culture mapping:
- Custom map via
appsettings.json(country → specific culture) - Automatic fallback using .NET
RegionInfo(ISO standard derivation)
- Custom map via
- Cookie persistence — skip detection on subsequent requests
- Optional auto-culture — middleware sets
CurrentCulture/CurrentUICulturefor the entire Umbraco pipeline (SurfaceControllers, ViewComponents, Views, API controllers) - Pluggable — add custom
IGeoLocationProviderimplementations via DI - Zero-config install — self-wires via Umbraco composers, no
Program.cschanges - Offline DB update — replace the
.mmdbfile manually or upgrade the NuGet package
dotnet add package uTPro.Feature.GeoLocationThat's it. The middleware runs automatically. Access the result from any controller or view:
// In a SurfaceController, RenderController, or ViewComponent:
var geo = HttpContext.GetGeoLocation();
// geo.CountryCode → "VN"
// geo.Culture → CultureInfo("vi-VN")
// geo.Provider → "Cloudflare"// Or inject IGeoLocationService for raw detection:
var countryCode = _geoService.GetCountryCode(HttpContext); // "US"
var culture = _geoService.MapToCulture("US"); // CultureInfo("en-US")| Umbraco | .NET | Target |
|---|---|---|
| 16 | .NET 9 | net9.0 |
| 17 & 18 | .NET 10 | net10.0 |
All settings are optional — the package works out of the box. Configure under
uTPro:Feature:GeoLocation in appsettings.json:
{
"uTPro": {
"Feature": {
"GeoLocation": {
"EnableProviders": {
"Cloudflare": true
},
"CultureMap": {
"VN": "vi-VN",
"US": "en-US",
"JP": "ja-JP"
}
}
}
}
}| Key | Default | Description |
|---|---|---|
EnableProviders |
all false |
Toggle CDN providers: Cloudflare, Akamai, Fastly, Vercel, Netlify, AwsCloudFront, AzureFrontDoor. Only enable what you use. |
CustomCountryHeader |
"" |
Custom header with 2-letter country code (highest priority, only active when set). |
CustomIpHeader |
"" |
Custom header with client IP (only active when set). |
AutoSetCulture |
false |
When true, middleware sets Thread.CurrentThread.CurrentCulture for the Umbraco pipeline. |
DatabasePath |
App_Data/GeoLocation/iplocate-country.mmdb |
Path to the offline MMDB file (relative to ContentRoot or absolute). |
UseCookie |
true |
Persist detected country in a cookie to skip detection on subsequent requests. |
CookieName |
utpro_geo_country |
Cookie name. |
CookieMaxAgeDays |
30 |
Cookie lifetime in days. |
FallbackCulture |
en |
Culture used when no country is detected. |
CultureMap |
{} |
Custom country→culture overrides. Keys: ISO 3166-1 alpha-2. Values: .NET culture names. |
Note: By default only Forwarded (IP resolution) and Offline (MMDB) providers are active. CDN providers must be explicitly enabled via
EnableProviders.
The package provides two levels of country-to-culture resolution:
- Custom map (
CultureMapin config): highest priority. You define exact country→culture pairs. - ISO standard (automatic): uses .NET
RegionInfoto derive the default culture for a country. For example,"DE"→de-DE,"BR"→pt-BR.
This means you only need to configure CultureMap for exceptions or preferences — the ISO standard
handles the rest.
The offline .mmdb ships with the NuGet package. You can update it manually at any time:
- Download the latest
ip-to-country.mmdbfrom iplocate.io - Rename to
iplocate-country.mmdb - Replace
App_Data/GeoLocation/iplocate-country.mmdbin your deployed site - Restart the application
NuGet package upgrades will not overwrite your manually updated file — your custom DB is safe.
Implement IGeoLocationProvider and register it in your own composer:
public sealed class MyCustomGeoProvider : IGeoLocationProvider
{
public string Name => "MyCustom";
public int Priority => 5; // Runs before Cloudflare (10)
public string? Detect(HttpContext httpContext)
{
// Your custom detection logic.
return httpContext.Request.Headers["X-My-Country"].ToString();
}
}
// In your composer:
builder.Services.AddSingleton<IGeoLocationProvider, MyCustomGeoProvider>();Full documentation is available at the uTPro Docs site:
| Guide | Description |
|---|---|
| Getting Started | Install, first boot, access the result |
| Configuration | All appsettings keys and their effects |
| Culture Mapping | Custom map vs ISO standard derivation |
| Offline Database | MMDB source, update strategies |
| Extensibility | Custom providers, advanced usage |
- No external API calls — all detection uses request headers or the local MMDB file.
- The cookie is functional (not tracking) and marked
Secure,SameSite=Lax,IsEssential=true. - IP addresses are not persisted — they're used only during the request lifetime.
By T4VN. Free to use — including in commercial projects — under a proprietary End User License Agreement. Issues welcome on the GitHub repository.
