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 many free geoIP web services available these days; a first implementation can simply rely on one, perhaps adding a fallback as necessary, though eventually a more robust solution may become necessary.
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('//geoip.nekudo.com/api/?callback=?', function(data) { self.ipAddress = data.ip + ''; self.city = data.city + ''; self.country = data.country.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)}}