Geofencing with real-time Geodata in Sitecore DMS


More and more users/visitors are using handheld devices with GPS for browsing the internet. That means we can get the their actual location thanks to the HTML5 Geolocation API.

After my previous posts, Track a visitors coordinates in the Sitecore DMS, I began to see the possibilities with “real-time geodata”.

There are some more goodies in the HTML5 Geolocation API we can use – Automatic tracking, speed and heading.

1. Automatic tracking allows you to track a users location while the website/webpage is open in the browser.

2. The speed feature gives you the users current speed.
That means we know if a user is:
Standing/sitting still
Driving/sitting a in vehicle

3. The heading feature gives you the current direction the user is moving in.

I’m going to present these topics in a couple of posts.

Today I will talk about Geofencing and how it can be implemented.
So what is geofencing?

Geo-fence is a virtual perimeter for a real-world geographic area. That means when someone using a device with GPS and crosses a “geofence” we will know. This is nothing new, geofencing has been used for a while in native apps.

Why not use it in a website?
In this case it’s a banner which will change content when a user/visitor is crossing a “geofence”. I was thinking of Sitecore and their partners – A partner banner 🙂
When a user is visiting the website, a banner will show the nearest partner from the users current location.

By default the banner presents the Sitecore HQ, the banner is using google maps “Streetview”.

When “Streetview” is closed a map is presented with driving/walking directions.
The speed feature in the HTML5 Geolocation API will determine if the user is driving or walking.

The user passes Sigma(in Malmö).


The user is now close to Pentia(in Copenhagen).


The user is near Magnetix(in Copenhagen).


The user passes Codehouse(in Copenhagen)


So how is it done?

First we need to get the Geo real time data.
We are doing it with javascript. Here we are using “automatic tracking” which will retrace each time the user has a new position.
The track type is defined in a “Client tracker” module.


Init: function (trackType) {
  if (trackType == Sandbox.ClientTracker.TrackTypes.TrackPerRequest) {
    navigator.geolocation.getCurrentPosition(geoSuccess, geoError);
  if (trackType == Sandbox.ClientTracker.TrackTypes.TrackFrequent) {
    // see
    var watchID = navigator.geolocation.watchPosition(geoSuccess, geoError, Sandbox.ClientTracker.TrackFrequenzyOptions);
  function geoSuccess(p) {
    window.coordinates = p.coords;
TrackUserLocation: function () {
  var requestParamAndValues = {};
  requestParamAndValues["Coordinates"] = Sandbox.ClientTracker.StringFormat("{0},{1}", window.coordinates.latitude, window.coordinates.longitude, '1');

  if (window.coordinates.speed!=null)
    requestParamAndValues["GeoSpeed"] = window.coordinates.speed;

  if (window.coordinates.heading != null)
    requestParamAndValues["GeoHeading"] = window.coordinates.heading;

  var jsonObject = {};
  jsonObject["requestParamAndValues"] = requestParamAndValues;

  var analyticsEvent = new AnalyticsPageEvent(jsonObject, window.pathToHandler);
TrackTypes: {
   "NoTracking": 1,
   "TrackPerRequest": 2,
   "FrequentTracking": 3
TrackFrequenzyOptions: { //  see
   enableHighAccuracy: true,
   timeout: 10000, // Every 10 second 
   maximumAge: 0 //No caching

Next thing to do is to store the data. I’m very fond off the Visitor Tags in Sitecore DMS so that is where I will put it. I will use the TrackerHandler.ashx from previous post, Client Tracker with Sitecore DMS.

public class TrackerHandler : IHttpHandler, IRequiresSessionState

    public void ProcessRequest(HttpContext context)
        context.Response.ContentType = Constants.ResponseContentTypes.ApplicationJavascript;

    private static void Execute(HttpContext context)

        if (!AnalyticsSettings.Enabled)

        string jsonData = context.Request[Constants.QueryParameters.JsonData];

        InputData inputData = JsonConvert.DeserializeObject(jsonData);

        if (inputData == null)

        if (!Tracker.IsActive)


        if (inputData.ContainsParamkey(InputDataKeys.Coordinates))
            TrackerService.AddTagToCurrentVisitor(InputDataKeys.Coordinates.ToString(), inputData.GetValueByKey(InputDataKeys.Coordinates));
        if (inputData.ContainsParamkey(InputDataKeys.GeoSpeed))
            TrackerService.AddTagToCurrentVisitor(InputDataKeys.GeoSpeed.ToString(), inputData.GetValueByKey(InputDataKeys.GeoSpeed));

        if (inputData.ContainsParamkey(InputDataKeys.GeoHeading))
            TrackerService.AddTagToCurrentVisitor(InputDataKeys.GeoHeading.ToString(), inputData.GetValueByKey(InputDataKeys.GeoHeading));

        if (inputData.ContainsParamkey(InputDataKeys.PageUrl) && inputData.ContainsParamkey(InputDataKeys.PageEventId))
            TrackerService.RegisterEventToAPage(inputData.GetValueByKey(InputDataKeys.PageEventId), inputData.GetValueByKey(InputDataKeys.PageUrl));



    public bool IsReusable
            return false;

In order for the banners to present content per geolocation we need a rule that checks if a user is in range of a geo target

The geo targets are the Sitecore partners which is listed in the “Client tracker” module.


The rule will also need a radius range.

The rule defined in Sitecore

The actual code for the rule

public class VisitorCoordinatesWithinRadius<T> : WhenCondition<T> where T : RuleContext

        public string RadiusRangeId { get; set; }
        public string TargetLocationId { get; set; }

        protected override bool Execute(T ruleContext)

            Assert.ArgumentNotNull((object)ruleContext, "ruleContext");

            Visitor visitor = Tracker.Visitor;

            VisitorLoadOptions visitorLoadOptions = new VisitorLoadOptions()
                Options = VisitorOptions.VisitorTags


            GeoCoordinate? geoCoordinate = SetGeoCoordinates(Tracker.Visitor);

            if (!geoCoordinate.HasValue)
                return false;

            if (string.IsNullOrWhiteSpace(TargetLocationId))
                return false;

            if (string.IsNullOrWhiteSpace(RadiusRangeId))
                return false;

            return TargetLocationService.IsCoordinatesWithinRadiusRange(RadiusRangeId, TargetLocationId,
                geoCoordinate.Value.Latitude, geoCoordinate.Value.Longitude);


    private GeoCoordinate? SetGeoCoordinates(Visitor visitor)

        VisitorDataSet.VisitorTagsRow coordinatesTagsRow = visitor.Tags.Find(InputDataKeys.Coordinates.ToString());

        if (coordinatesTagsRow == null)
            return null;

        if (string.IsNullOrWhiteSpace(coordinatesTagsRow.TagValue))
            return null;

        return GeoCoordinateRepository.Get(coordinatesTagsRow.TagValue);

TargetLocationService who checks if a user is within range

public class TargetLocationService
       public static bool IsCoordinatesWithinRadiusRange(string radiusRangeId, string targetLocationId, double latitudeToCompare, double longitudeToCompare)
            GeoCoordinate? geoCoordinatesValueToCompare = GeoCoordinateRepository.Get(latitudeToCompare, longitudeToCompare);

            if (!geoCoordinatesValueToCompare.HasValue)
                return false;

            TargetLocation targetLocation = TargetLocationRepository.Get(Sitecore.Context.Database.GetItem(new ID(targetLocationId)));

            if (targetLocation == null)
                return false;

            if (!targetLocation.Coordinates.HasValue)
                return false;

            LocationRange radiusRange = LocationRangeRepository.Get(Sitecore.Context.Database.GetItem(new ID(radiusRangeId)));

            if (!radiusRange.Range.HasValue)
                return false;

            GeoCoordinateService geoLocationService = new GeoCoordinateService();

            double distanceInMeterToTarget = geoLocationService.DistanceToCoordinates(geoCoordinatesValueToCompare.Value,
                targetLocation.Coordinates.Value.Latitude, targetLocation.Coordinates.Value.Longitude,

            return (distanceInMeterToTarget <= decimal.ToDouble(radiusRange.Range.Value));


The GeoCoordinateService that calculates the distance

public class GeoCoordinateService
    public double DistanceToCoordinates(GeoCoordinate coordinateToCheck, double endPointLatitude, double endPointLongitude, DistanceType distanceType)
        double r = Sandbox.SharedSource.ClientTracker.Constants.GeoData.EarthRadiusInMeters;

        if (distanceType == DistanceType.Kilometers)
        r = Sandbox.SharedSource.ClientTracker.Constants.GeoData.EarthRadiusInKilometers;

        if (distanceType == DistanceType.Miles)
        r = Sandbox.SharedSource.ClientTracker.Constants.GeoData.EarthRadiusInMiles;

        double dLat = DegreeToRadian(endPointLatitude) - DegreeToRadian(coordinateToCheck.Latitude);
        double dLon = DegreeToRadian(endPointLongitude) - DegreeToRadian(coordinateToCheck.Longitude);

        double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(DegreeToRadian(coordinateToCheck.Latitude)) * Math.Cos(DegreeToRadian(endPointLatitude)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
        double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        double distance = c * r;

        return Math.Round(distance, 2);

Finally the google map javascript for presenting streetview, map and directions.
For directions we are using the users current “geo speed” in order to give walking or driving directions.


CreateMap: function () {
        var directionsService = new google.maps.DirectionsService();
        var directionsDisplay = new google.maps.DirectionsRenderer();
            var createMap = function (start) {

                var coordinatesArray = jQuery('#map').data('coordinates').split(',');

                var speedType = jQuery('#map').data('speedtype');

                if (speedType == null)
                    speedType = google.maps.DirectionsTravelMode.DRIVING;

                var targetDestination = new google.maps.LatLng(coordinatesArray[0], coordinatesArray[1]);
                var travel = {
                        origin : (start.coords)? new google.maps.LatLng(, start.lng) : start.address,
                        destination: targetDestination,
                        travelMode: speedType
                    mapOptions = {
                        zoom: 10,
                        // Default view: Malmö
                        center: new google.maps.LatLng(55.615056, 12.990449),
                        mapTypeId: google.maps.MapTypeId.ROADMAP

                map = new google.maps.Map(document.getElementById("map"), mapOptions);
                directionsService.route(travel, function(result, status) {
                    if (status === google.maps.DirectionsStatus.OK) {
                var panoOptions = {
                    position: targetDestination,
                    addressControl: false,
                    addressControlOptions: {
                        position: google.maps.ControlPosition.TOP_LEFT
                    pov: {
                        heading: 100,
                        pitch: 5
                    linksControl: false,
                    panControl: false,
                    zoomControlOptions: {
                        style: google.maps.ZoomControlStyle.SMALL
                    enableCloseButton: true,
                    zoom: 0.4

                var myPano = new google.maps.StreetViewPanorama(


        // Check for geolocation support	
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (position) {
                // Success!
                    coords : true,
                    lat : position.coords.latitude,
                    lng : position.coords.longitude
                function () {
                    // Gelocation fallback: Defaults to Malmö, Sweden
                        coords : false,
                        address: "Malmö, Sweden"
        else {
            // No geolocation fallback: Defaults to Malmö, Sweden
                coords : false,
                address : "Malmö, Sweden"

That’s it!

I think Geofencing is pretty cool. In this case I’m presenting a map and the directions to a location. But you can do so much more…
For instance if a visitor is passing a cafe, restaurant, or a shop – the website can push real time content. We have the users location and we will know if the user is walking or driving. We also know the date and the time. We can even find out what kind of weather it is…

You are only limited by your own imagination. Let it fly.

That’s all for now folks 🙂

7 thoughts on “Geofencing with real-time Geodata in Sitecore DMS

  1. Awesome, simply put.

    I think it would be fantastic if your API could request a child of a node automatically by using the geo fencing features. Something like Item GetNearestItem(CurrentposX, CurrentposY, Distance, ParentItem) or the like.

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.