Get your site visitors Geolocation using Maxmind Database

Posted by

I came across a scenario where my client wanted to personalize the content based on country of visitor.

Sitecore has its own IP Geolocation Service which provides information about the location and owner of an IP address, beyond that provided by a reverse DNS lookup. IP Geolocation information includes the country, state, city, and the registered company name of every visitor.

But it’s a paid service and my client wanted to explorer if we can use any free version for getting the country.

I already knew about MAXMIND which operates both ways – Paid as well as free version.

There are few limitations with the free version:

  • There are no automatic updates for the database, but you can write your own script to do so.
  • Free database updates are available a week or so later then the paid once.

Our client agreed upon the limitations and we started the development.

After the download is complete, unzip the files and copy “GeoLite2-Country.mmdb” file into your project.

Below is code sample to get the country from maxmind database from visitor IP address:

    public class GetLocation
    {
        private ILog log = LogManager.GetLogger("Geo-IP");
        private static GetLocation _user;
        public static System.Net.IPAddress ip;
        public static GetLocation User => _user ?? (_user = new GetLocation());
        private static IPAddress GetIpAddressFromTracker()
        {
            //True-Client-IP -> if you have AKAMAI in-place.
            string remoteAddr = HttpContext.Current.Request.Headers["True-Client-IP"];
            if (string.IsNullOrEmpty(remoteAddr))
            {
                string forwardedFor = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                if (!string.IsNullOrEmpty(forwardedFor))
                { remoteAddr = forwardedFor.Split(',').Select(s => s.Trim()).First(); }
                else
                { return new IPAddress(Tracker.Current.Interaction.Ip); }
            }
            try
            {
                IPAddress Address;
                if (!string.IsNullOrEmpty(remoteAddr) && IPAddress.TryParse(remoteAddr, out Address))
                { return Address; }
                return null;
            }
            catch
            { return new IPAddress(Tracker.Current.Interaction.Ip); }
        }

        private static string GetCountryFromMaxMind(IPAddress ipAddress)
        {
            var db = new DatabaseReader(HttpContext.Current.Server.MapPath("/App_data/GeoLite2-Country.mmdb"), FileAccessMode.Memory);
            MaxMind.GeoIP2.Responses.CountryResponse response;
            return db.TryCountry(ipAddress, out response) ? response.Country.Name : string.Empty;
        }

        private static string GetCountryCode(string country)
        {
            var regions = CultureInfo.GetCultures(CultureTypes.SpecificCultures).Select(x => new RegionInfo(x.LCID));
            return (regions.FirstOrDefault(region => region.EnglishName.ToLower().Contains((country.ToLower())))).TwoLetterISORegionName;
        }

        public Ip GetIpSettings()
        {
            var ipsettings = new Ip();
            IPAddress ipAddress;

            ipAddress = GetIpAddressFromTracker();
            ipsettings.IpAddress = Lookup.Address.Tracker;

            if (ipAddress != null && string.IsNullOrEmpty(ipsettings.Country))
            {
                ipsettings.LookupService = Lookup.Service.MaxMindGeoIp2;
                ipsettings.Country = GetCountryFromMaxMind(ipAddress);
            }

            if (ipAddress != null && !string.IsNullOrEmpty(ipsettings.Country))
            {
                ipsettings.CountryCode = GetCountryCode(ipsettings.Country).ToUpper();
            }
            return ipsettings;
        }
    }

    public class Ip
    {
        public string CountryCode { get; set; }
        public string Country { get; set; }
        public Lookup.Address IpAddress { get; set; }
        public Lookup.Service LookupService { get; set; }
        
    }

    public class Lookup
    {
        public enum Service
        {
            SitecoreGeoIp,MaxMindGeoIp2
        }
        public enum Address
        {
            Tracker,QueryString,Empty
        }
    }

Once this is done, you can use above functions to get the country name or country code as per your need, for e.g:

var countryobj = GetLocation.User.GetIpSettings();
string country_code = countryobj.CountryCode;

There are couple of ways provided by MAXMIND for retrieving the geolocation:

  • https://maxmind.github.io/GeoIP2-dotnet/
  • You can also use the maxmindNuGet API for the same.
  • If you find yourself in a similar situation and need to use MAXMIND for getting the information, now you know how to make it work.

    Until next time, cheers

    Leave a Reply