Lot of times we come across the requirement to apply personalization based on visitor’s GeoCoordinates (latitude & longitude) & if visitor location is within specified distance to a ‘centre point location’. For example, showing personalized content for visitors accessing website from certain part of city/town or show content if website visitor is walking distance to nearest store or a festival etc.
Note: This example will only work if visitor’s device (PC or Mobile) has location sharing turned on.
I’m using Episerver guide to create a very simple personalisation criterion and added following input fields.
- Centralize location latitude
- Centralize location longitude
- Radius (meters )
Create Personalization criteria
GeoCoordinateRadiusCriterionSettings Class
public class GeoCoordinateRadiusCriterionSettings : CriterionModelBase
{
[Required]
public double CentralizeLocationLatitude { get; set; }
[Required]
public double CentralizeLocationLongitude { get; set; }
[Required]
public double Radius { get; set; }
public override ICriterionModel Copy()
{
return ShallowCopy();
}
}
Get Visitor’s location & Criterion
GeoCoordinateRadiusCriterion Class
[VisitorGroupCriterion(
Category = "Geolocation",
DisplayName = "GeoCoordinate & Radius",
Description = "Checks visitor's location falls in specified radius")]
public class GeoCoordinateRadiusCriterion : CriterionBase<GeoCoordinateRadiusCriterionSettings>
{
public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext)
{
//user location
var visitorlocation = GetVisitorLatLong();
double sLatitude = visitorlocation.Latitude;
double sLongitude = visitorlocation.Longitude;
// center point location
double eLatitude = Model.CentralizeLocationLatitude;
double eLongitude = Model.CentralizeLocationLongitude;
var sCoord = new GeoCoordinate(sLatitude, sLongitude);
var eCoord = new GeoCoordinate(eLatitude, eLongitude);
var distance = sCoord.GetDistanceTo(eCoord);
if (distance <= Model.Radius)
{
return true;
}
else
{
return false;
}
}
private GeoLocation GetVisitorLatLong()
{
GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
var userLocation = new GeoLocation();
watcher.Start();
System.Device.Location.GeoCoordinate coord = watcher.Position.Location;
if (!watcher.Position.Location.IsUnknown)
{
userLocation.Latitude = coord.Latitude;
userLocation.Longitude = coord.Longitude;
}
return userLocation;
}
}
Radius is calculated based on center point of a circle. However, lot of time we have requirement to find visitor in a polygon area of Geo Coordinates. This custom criterion can be extended to calculate personalization criteria based on polygon area.
Source Code: The source code of this Episerver personalization criteria can be downloaded from this link.
Nice blog Post. I did similar type of work for region and zipcode.
Hi Naveed,
It’s great to see you sharing your Episerver knowledge and it’s always good to see an example of creating a custom personalisation criterion but there are a couple of things to point out.
For the benefit of anyone looking to implement geolocation-based personalisation like this, it’s worth noting that this is inbuilt functionality in Episerver (“Geographic co-ordinate” under “Time and place criteria”) though, in newer versions it’s not enabled by default and requires you to add it as a separate nuget package. There’s a bit of discussion about it including some links to the docs and the announcement in this forum post:
https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2019/6/geographic-coordinate-and-location-visitor-group-criteria-missing/#204707
The other thing to note is that, while GeoCoordinateWatcher is a handy class for getting location in client applications, the criterion code will run on the server, not the client, so you’ll always return the location of the server hosting the site rather than the site visitor. There are various ways you could get the location of the client but the inbuilt location criteria use the maxmind geolite2 database to lookup the client IP address.