MaxMind is great for tracking visitors – It gives you all kind of information based on the IP address.
Today when more and more users/visitors are using handheld devices with GPS for browsing the internet, I wanted to get the actual location for the visitor using HTML5 Geolocation API
Note: Since it can compromise user privacy, the position is not available unless the user approves it.
In order to get the location/coordinates, following javascript is used (window.coordinates is a global variable):
if (navigator) navigator.geolocation.getCurrentPosition(geoSuccess, geoError); function geoSuccess(p) { window.coordinates = p.coords; } function geoError(data) { //Do some error handling }
I added the geolocation to my previous post, Client side tracking with Sitecore DMS.
var Sandbox = Sandbox || {}; jQuery(document).ready(function () { Sandbox.Alert.DomReady(); }); Sandbox.Alert = { DomReady: function () { Sandbox.Alert.InitSandbox(); jQuery("#closeAlert").click(function () { Sandbox.Alert.TrackCloseEvent(); }); }, InitSandbox: function () { if (navigator) navigator.geolocation.getCurrentPosition(geoSuccess, geoError); function geoSuccess(p) { window.coordinates = p.coords; } function geoError(data) { //Some error handling } }, TrackCloseEvent: function () { var dataContainer = jQuery(".alert alert-info fade in"); var requestParamAndValues = {}; requestParamAndValues["PageEventId"] = dataContainer.data("goal"); requestParamAndValues["PageUrl"] = dataContainer.data("pageurl"); if (window.coordinates) requestParamAndValues["Coordinates"] = Sandbox.Alert.StringFormat("{0},{1}", window.coordinates.latitude, window.coordinates.longitude, '1'); var jsonObject = {}; jsonObject["requestParamAndValues"] = requestParamAndValues; var analyticsEvent = new AnalyticsPageEvent(jsonObject); analyticsEvent.trigger(); }, StringFormat : function () { var s = arguments[0]; for (var i = 0; i < arguments.length - 1; i++) { var reg = new RegExp("\\{" + i + "\\}", "gm"); s = s.replace(reg, arguments[i + 1]); } return s; } };
In the aspx page, ClientEventTracker, we need to add some lines of code (TrackerService):
namespace Sandbox.Tracking.Presentation { public partial class ClientEventTracker : System.Web.UI.Page { protected void Page_Init(object sender, EventArgs e) { Context.Response.ContentType = "application/javascript"; TriggerEvent(this.Context); } private static void TriggerEvent(HttpContext context) { string jsonData = context.Request["jsonData"]; InputData inputData = ConvertJsonToObjectService.Convert<InputData>(jsonData); if (!inputData.ContainsParamkey(InputDataKeys.PageUrl)) return; if (!inputData.ContainsParamkey(InputDataKeys.PageEventId)) return; Tracker.StartTracking(); Tracker.CurrentPage.Cancel(); TrackerService.SetCurrentVisitorCoordinates(inputData.GetValueByKey(InputDataKeys.Coordinates)); TrackerService.RegisterEventToAPage(inputData.GetValueByKey(InputDataKeys.PageEventId), inputData.GetValueByKey(InputDataKeys.PageUrl)); Tracker.Submit(); } } }
TrackerService is defined here:
namespace Sandbox.Tracking.Infrastructure { public class TrackerService { public static void RegisterEventToAPage(string eventId, string url) { if (string.IsNullOrWhiteSpace(eventId)) return; if (string.IsNullOrWhiteSpace(url)) return; if (!Tracker.IsActive) return; PageEventItem pageEvent = new PageEventItem(Sandbox.Framework.SitecoreEnhancements.SitecoreItemRepository.Get(eventId)); VisitorDataSet.PagesRow pagesRow = Tracker.CurrentVisit.GetPages().LastOrDefault(p => p.Url.Contains(url)); if (pagesRow == null) return; pagesRow.Register(pageEvent); } public static void SetCurrentVisitorCoordinates(string coordinates) { GeoCoordinate? geoCoordinate = GeoCoordinateRepository.Get(coordinates); if (!geoCoordinate.HasValue) return; if (!Tracker.IsActive) return; Tracker.CurrentVisit.Latitude = geoCoordinate.Value.Latitude; Tracker.CurrentVisit.Longitude = geoCoordinate.Value.Longitude; } } }
GeoCoordinate object:
namespace Sandbox.Tracking.Model { public struct GeoCoordinate { private readonly double _latitude; private readonly double _longitude; public double Latitude { get { return _latitude; } } public double Longitude { get { return _longitude; } } public GeoCoordinate(double latitude, double longitude) { _latitude = latitude; _longitude = longitude; } public override string ToString() { return string.Format("{0},{1}", Latitude, Longitude); } public override bool Equals(Object other) { return other is GeoCoordinate && Equals((GeoCoordinate)other); } public bool Equals(GeoCoordinate other) { return Math.Abs(Latitude - other.Latitude) < double.Epsilon && Math.Abs(Longitude - other.Longitude) < double.Epsilon; } public override int GetHashCode() { return Latitude.GetHashCode() ^ Longitude.GetHashCode(); } } }
GeoCoordinateRepository:
namespace Sandbox.Tracking.Model.Repositories { public class GeoCoordinateRepository { public static GeoCoordinate? Get(string latitude, string longitude) { if (string.IsNullOrWhiteSpace(latitude) || string.IsNullOrWhiteSpace(longitude)) return null; string coordinates = string.Concat(latitude, ",", longitude); return GeoCoordinateFactory.Create(coordinates); } public static GeoCoordinate? Get(string coordinates) { if (string.IsNullOrWhiteSpace(coordinates)) return null; return GeoCoordinateFactory.Create(coordinates); } public static IEnumerable<GeoCoordinate?> Get(IEnumerable<string> manyCoordinates) { return manyCoordinates.Select(Get); } } }
Finally the GeoCoordinateFactory:
namespace Sandbox.Tracking.Model.Factories { internal class GeoCoordinateFactory { internal static GeoCoordinate? Create(string coordinates) { string[] coordinateArray = coordinates.Split(','); if (coordinateArray.Length == 0) return null; if (string.IsNullOrWhiteSpace(coordinateArray[0]) || string.IsNullOrWhiteSpace(coordinateArray[1])) return null; return new GeoCoordinate(double.Parse(coordinateArray[0], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture), double.Parse(coordinateArray[1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture)); } } }
That’s all for now folks 🙂
Very cool!
LikeLike
Thanks I really appreciate it
LikeLike
Client Tracker is now released on Sitecore Marketplace 🙂 Check out blog post https://visionsincode.wordpress.com/2014/04/10/client-tracker-with-sitecore-dms
LikeLike
Nice Article. Do you think this could be moved into a Standard Sitecore package, and released on the Marketplace?
LikeLike
Thank you. I haven’t thought about it but yes it’s possible. It’s a really good idea. I will work with it and update you how it’s developing.
LikeLike
It is now released on Sitecore Marketplace 🙂 Check out blog post https://visionsincode.wordpress.com/2014/04/10/client-tracker-with-sitecore-dms
LikeLike
Thank you David(@angrymrt), for fixing my code 🙂
LikeLike