Combine approaches for easy, lightweight JavaScript user information detection

Basic browser/user detection can be important for providing an enhanced user experience. For example, making a best-guess detection of the user’s IP address (subject to the usual caveats about VPN use) can help in pre-selecting a user’s country of origin, enabling faster form fill-outs. The user’s preferred language, especially on first access of a site, is obviously of huge importance; detecting it early with a non-intrusive script can help avoid clunkier approaches such as passing out language-differentiated URLs to globalized versions of your site, which may be passed between users with unintended consequences.

Especially for a site which already makes use of JavaScript, an unobtrusive script can make a difference. And while there are fairly robust libraries such as platform.js, they often do not address all concerns of detecting language, geoIP, and browser. Adding extra dependencies to a site, in terms of maintenance burden and JS payload, is desirable to avoid when possible.

It’s easy enough to create a tiny script which merges freely available geoIP with basic browser/language detection, as shown below. There are so many free geoIP web services available these days, a first implementation can simply rely on one, perhaps adding a fallback as necessary. The excellent freegeoip.net, shown in the sample below, at time of this writing has shown high reliability, allows for up to 15,000 requests per hour from the same end-user IP address, and can also be installed for free in any Linux environment.

The simple demo code, with browser and OS versions not yet filled in, appears below, and may be run at JSFiddle . This could, for example, be passed as a JSON bundle in a call to a web service, or submitted with a page. While the code may be reused freely, as it essentially cobbles together multiple simple well-known methods into an easy-to-use package, the emphasis is on the approach: a lightweight script that avoids heavy dependencies and still captures useful information about a user. As always, use such information responsibly, especially keeping in mind GDPR regulations which will have taken full effect by May 2018.

function UserInfo() {
  var self = this;
  this.language = ((navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage)) + '').substring(0, 2);
  this.browserName = '';
  this.browserVersion = '';
  this.osName = '';
  this.osVersion = '';
  this.country = '';
  this.ipAddress = '';
  this.city = '';
  this.region = '';
  this.postalCode = '';
  
  if (navigator && navigator.userAgent) {
    var ua = (navigator.userAgent + '').toLowerCase();
    var platform = ua;
    
    var i = platform.indexOf('(');
    if (i > -1)
      platform = platform.substring(i + 1);

    i = platform.indexOf(')');
    if (i > -1)
      platform = platform.substring(0, i);
      
    if (platform.indexOf('windows') > -1)
      this.osName = 'Windows';
    else if (platform.indexOf('android') > -1)
      this.osName = 'Android';
    else if (platform.indexOf('macintosh') > -1 || platform.indexOf('macos') > -1)
      this.osName = 'macOS';
    else if (platform.indexOf('iphone') > -1 || platform.indexOf('ipad') > -1)
      this.osName = 'iOS';
  }

  if (!!window.chrome && !!window.chrome.webstore)
    this.browserName = 'Chrome';
  else if (typeof InstallTrigger !== 'undefined')
    this.browserName = 'Firefox';
  else if (/*@cc_on!@*/false || !!document.documentMode)
    this.browserName = 'IE';
  else if (/constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || safari.pushNotification))
    this.browserName = 'Safari';
  else if ((!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0)
    this.browserName = 'Opera';
  else if (!!window.StyleMedia)
    this.browserName = 'Edge';
  
try {
    $.getJSON('//freegeoip.net/json/?callback=?', function(data) {
      self.ipAddress = data.ip + '';
      self.city = data.city + '';
      self.region = data.region_code + '';
      self.country = data.country_code + '';      
      self.postalCode = data.zip_code + '';
    });
} catch (err) {}

  this.ids = []; 
  
  this.addID = function(sn, st, idt, i) {
    var newID = {};
    newID.systemName = sn + '';
    newID.systemType = st + '';
    newID.idType = idt + '';
    newID.id = i + '';      
    this.ids.push(newID);
  };  
}

The minified version is relatively compact, at 1560 characters:

function UserInfo(){var i=this;if(this.language=((navigator.languages?navigator.languages[0]:navigator.language||navigator.userLanguage)+"").substring(0,2),this.browserName="",this.browserVersion="",this.osName="",this.osVersion="",this.country="",this.ipAddress="",this.city="",this.region="",this.postalCode="",navigator&&navigator.userAgent){var e=(navigator.userAgent+"").toLowerCase(),o=e.indexOf("(");o>-1&&(e=e.substring(o+1)),(o=e.indexOf(")"))>-1&&(e=e.substring(0,o)),e.indexOf("windows")>-1?this.osName="Windows":e.indexOf("anddroid")>-1?this.osName="Android":e.indexOf("macintosh")>-1||e.indexOf("macos")>-1?this.osName="macOS":(e.indexOf("iphone")>-1||e.indexOf("ipad")>-1)&&(this.osName="iOS")}window.chrome&&window.chrome.webstore?this.browserName="Chrome":"undefined"!=typeof InstallTrigger?this.browserName="Firefox":document.documentMode?this.browserName="IE":/constructor/i.test(window.HTMLElement)||"[object SafariRemoteNotification]"===(!window.safari||safari.pushNotification).toString()?this.browserName="Safari":window.opr&&opr.addons||window.opera||navigator.userAgent.indexOf(" OPR/")>=0?this.browserName="Opera":window.StyleMedia?this.browserName="Edge":(isChrome||isOpera)&&window.CSS&&(this.browserName="Blink");try{$.getJSON("//freegeoip.net/json/?callback=?",function(e){i.ipAddress=e.ip+"",i.city=e.city+"",i.region=e.region_code+"",i.country=e.country_code+"",i.postalCode=e.zip_code+""})}catch(i){}this.ids=[],this.addID=function(i,e,o,s){var t={};t.systemName=i+"",t.systemType=e+"",t.idType=o+"",t.id=s+"",this.ids.push(t)}}

Advertisements

Leave a Reply

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

WordPress.com Logo

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

Google+ photo

You are commenting using your Google+ 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 )

w

Connecting to %s