76

Most implementations i've seen are for browser detection on the client side. I was just wondering if it was possible to do browser detection before sending any resources to the client.

Thanks.

fancy
  • 48,619
  • 62
  • 153
  • 231
  • this is 2015. Is there a library for this now that's more comprehensive and stuff. I want to detect moz vs webkit vs ie. And i want to detect mobile vs desktop vs tablet. – Muhammad Umer Feb 12 '15 at 22:03
  • may be https://www.npmjs.com/package/mobile-detect or https://www.npmjs.com/package/express-device – Chaudhry Junaid Apr 27 '15 at 09:36
  • or this package as well? what do you think? https://www.npmjs.com/package/bowser – axel Jun 20 '16 at 11:49

17 Answers17

93
var ua = request.headers['user-agent'],
    $ = {};

if (/mobile/i.test(ua))
    $.Mobile = true;

if (/like Mac OS X/.test(ua)) {
    $.iOS = /CPU( iPhone)? OS ([0-9\._]+) like Mac OS X/.exec(ua)[2].replace(/_/g, '.');
    $.iPhone = /iPhone/.test(ua);
    $.iPad = /iPad/.test(ua);
}

if (/Android/.test(ua))
    $.Android = /Android ([0-9\.]+)[\);]/.exec(ua)[1];

if (/webOS\//.test(ua))
    $.webOS = /webOS\/([0-9\.]+)[\);]/.exec(ua)[1];

if (/(Intel|PPC) Mac OS X/.test(ua))
    $.Mac = /(Intel|PPC) Mac OS X ?([0-9\._]*)[\)\;]/.exec(ua)[2].replace(/_/g, '.') || true;

if (/Windows NT/.test(ua))
    $.Windows = /Windows NT ([0-9\._]+)[\);]/.exec(ua)[1];

That should work for you. Just put it in your response handler.

McKayla
  • 6,879
  • 5
  • 36
  • 48
  • 6
    @float using the UA to detect browsers is a bad habit and unstable. I would recommend you look at delegation as much of this to the CSS `@media` property so you can serve different CSS to mobile and non-mobile devices. – Raynos May 29 '11 at 12:45
  • 1
    @Raynos what if we are planning to serve a mobile web app that uses a different code base? Maybe we should merge the two code bases instead? – fancy May 29 '11 at 14:29
  • 1
    This script throws an exception if the user agent doesn't comply with expected strings. For example, the ZXing QRCode reader uses a User Agent string of "ZXing (Android)" and this results in a null pointer exception on /Android ([0-9\.]+)[\);]/.exec(ua)[1]. I've adjusted the code accordingly. – Philip Callender Apr 21 '14 at 04:36
  • for anyone looking for device detection, i have used something like this with success before: https://www.npmjs.com/package/express-device – newshorts Mar 16 '15 at 21:26
31

The ua-parser library for node (npm install ua-parser) exposes a big set of regexes for browser user-agent strings. I'd strongly recommend it for your needs.

franzlorenzon
  • 5,845
  • 6
  • 36
  • 58
S M
  • 8,155
  • 3
  • 35
  • 36
18

I threw this together using ua-parser-js. I'm sure it can be improved but it's functional.

Install the package:

sudo npm install ua-parser-js

In your routes file require UAParser:

var UAParser = require('ua-parser-js');

Do some stuff with it:

function ensureLatestBrowser(req, res, next) {
  var parser = new UAParser();
  var ua = req.headers['user-agent'];
  var browserName = parser.setUA(ua).getBrowser().name;
  var fullBrowserVersion = parser.setUA(ua).getBrowser().version;
  var browserVersion = fullBrowserVersion.split(".",1).toString();
  var browserVersionNumber = Number(browserVersion);

  if (browserName == 'IE' && browserVersion <= 9)
    res.redirect('/update/');
  else if (browserName == 'Firefox' && browserVersion <= 24)
    res.redirect('/update/');
  else if (browserName == 'Chrome' && browserVersion <= 29)
    res.redirect('/update/');
  else if (browserName == 'Canary' && browserVersion <= 32)
    res.redirect('/update/');
  else if (browserName == 'Safari' && browserVersion <= 5)
    res.redirect('/update/');
  else if (browserName == 'Opera' && browserVersion <= 16)
    res.redirect('/update/');
  else
    return next();
}

and then in your route just call:

app.all(/^(?!(\/update)).*$/, ensureLatestBrowser);

If you want to see what other information you can get with UAParser check out their demo page.

Donald
  • 3,901
  • 1
  • 20
  • 15
  • 1
    Sorry for my comment above. There's nothing wrong with the lib, instead IE send me the "fake IE 7 ua" if I don't set `X-UA-Compatible` meta tag. – iplus26 Nov 21 '17 at 13:08
5

I wanted to do a simple redirection to a mobile version of my site, so user-agent is reliable enough. I wanted to do it server-side so I didn't waste time loading unnecessary css and js on the client. http://detectmobilebrowsers.com/ had the most robust regex to match. So I threw together some express middleware that will let you do the redirection by just adding two lines of code to your app.

npm install detectmobilebrowsers to install

express = require 'express'
mobile  = require 'detectmobilebrowsers'

app = express()
app.configure () ->
  app.use mobile.redirect 'http://m.domain.com'
app.get '/', (req, res) ->
  res.send 'Not on Mobile'
app.listen 3000
eckes
  • 64,417
  • 29
  • 168
  • 201
Overflow289
  • 121
  • 3
  • 2
5

I released device-detector-js a couple months ago.

It's a TypeScript port of Matomo device-detector, a powerful device detection library originally written in PHP.

It can parse any user agent and detect the browser, operating system, device used (desktop, tablet, mobile, tv, cars, console, etc.), brand and model.

Installation

npm install device-detector-js

Example - simple user agent detection:

const DeviceDetector = require("device-detector-js");

const deviceDetector = new DeviceDetector();
const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36";
const device = deviceDetector.parse(userAgent);

console.log(device);

Take a look at the full API documentation.

Etienne Martin
  • 10,018
  • 3
  • 35
  • 47
4
ua = request.headers['user-agent'];
if( /firefox/i.test(ua) )
  browser = 'firefox';
else if( /chrome/i.test(ua) )
  browser = 'chrome';
else if( /safari/i.test(ua) )
  browser = 'safari';
else if( /msie/i.test(ua) )
  browser = 'msie';
else
  browser = 'unknown';
paolooo
  • 4,133
  • 2
  • 18
  • 33
2

if your using express you can easily check the ua with something like this:

app.get('/ua', function(req, res){
    res.send('user ' + req.headers['user-agent']);
});
bhurlow
  • 2,019
  • 2
  • 16
  • 14
2

Most browsers provide an HTTP request header called "User-Agent" This is the same as the navigator.userAgent property on the client side.

Maz
  • 3,375
  • 1
  • 22
  • 27
2

Try this code http://detectmobilebrowser.com/

tomislav
  • 339
  • 3
  • 6
1

I improved a bit @duck5auce's code to be actually useful and support IE 10-12 (Edge).

var getDevice = function(ua) {
    var $ = {active: false, subactive: false};

    if (/mobile/i.test(ua)) {
        $.active = 'mobile';
        $.Mobile = true;
    }

    if (/like Mac OS X/.test(ua)) {
        $.active = 'iOS';
        $.iOS = /CPU( iPhone)? OS ([0-9\._]+) like Mac OS X/.exec(ua)[2].replace(/_/g, '.');
        if (/like Mac OS X/.test(ua)) {
            $.subactive = 'iPhone';
            $.iPhone = /iPhone/.test(ua);
        }
        if (/like Mac OS X/.test(ua)) {
            $.subactive = 'iPad';
            $.iPad = /iPad/.test(ua);
        }
    }

    if (/Android/.test(ua)) {
        $.active = 'Android';
        $.Android = /Android ([0-9\.]+)[\);]/.exec(ua)[1];
    }

    if (/webOS\//.test(ua)) {
        $.active = 'webOS';
        $.webOS = /webOS\/([0-9\.]+)[\);]/.exec(ua)[1];
    }

    if (/(Intel|PPC) Mac OS X/.test(ua)) {
        $.active = 'Safari';
        $.Safari = /(Intel|PPC) Mac OS X ?([0-9\._]*)[\)\;]/.exec(ua)[2].replace(/_/g, '.') || true;
    }

    if (/Windows NT/.test(ua)) {
        $.active = 'IE';
        $.IE = /Windows NT ([0-9\._]+)[\);]/.exec(ua)[1];
    }
    if (/MSIE/.test(ua)) {
        $.active = 'IE';
        $.IE = /MSIE ([0-9]+[\.0-9]*)/.exec(ua)[1];
    }
    if (/Trident/.test(ua)) {
        $.active = 'IE';
        $.IE = /Trident\/.*rv:([0-9]+[\.0-9]*)/.exec(ua)[1];
    }
    if (/Edge\/\d+/.test(ua)) {
        $.active = 'IE Edge';
        $.IE = /Edge\/(\d+)/.exec(ua)[1];
    }

    return $.active + ' ' + $[$.active] + ($.subactive && ' ' + $.subactive + ' ' + $[$.subactive]);
};
EvgenyKolyakov
  • 3,310
  • 2
  • 21
  • 31
1

Powerfull npm useragent. Useragent allows you to parse user agent string with high accuracy by using hand tuned dedicated regular expressions for browser matching. This database is needed to ensure that every browser is correctly parsed as every browser vendor implements it's own user agent schema. This is why regular user agent parsers have major issues because they will most likely parse out the wrong browser name or confuse the render engine version with the actual version of the browser.

Jomy Joseph
  • 321
  • 1
  • 8
1

I had a similar requirement and I came across this node package called detect-browser.

const { detect } = require('detect-browser');
const browser = detect();

if (browser) {
  console.log(browser.name);
  console.log(browser.version);
  console.log(browser.os);
}

Or if you wanted to perform any action depending on a specific browser you could also use a switch case like below

const { detect } = require('detect-browser');
const browser = detect();

// handle the case where we don't detect the browser
switch (browser && browser.name) {
  case 'chrome':
  case 'firefox':
    console.log('supported');
    break;

  case 'edge':
    console.log('kinda ok');
    break;

  default:
    console.log('not supported');
}
darkHorse
  • 13
  • 8
1

Here's another one: https://github.com/koudelka/node-useragent_parser

0

If you want to control mobile in the templating layer, I just wrote a module for that. https://github.com/Fresheyeball/isMobile-node

Fresheyeball
  • 29,567
  • 20
  • 102
  • 164
0

You might want to have a look at Apache DeviceMap.

JavaScript libraries out of the box are more on the client side right now, but much will work on Node.JS or Angular in a similar way. Unlike simple pattern matching of UA strings DeviceMap comes with a vast range of devices and device families in its Device Description Repository (DDR) based on W3C standards.

Werner Keil
  • 592
  • 5
  • 12
0

[Here is another variation or assimilation for your consideration.]

It is more versatile and simplified further.

You can pass the Request or any object with a 'headers' property or it could be the headers property and you can pick any label to search for the parameter on the object or the headers or the actual user agent string itself.

It used the previously posted Mobile and Table Checking Regex, and simply returns that result, but by first sanctifying the input, one can plug various things in.

You can even override the default regex optionally passable as an argument. {I'll leave that further extension to the inspired.} Also one could have another way to default to the globally stored user-agent from the request if in scope etc.

mobTabCheck: function( ua, lbl, rgx ) {  /* mobile tablet check; UserAgent or request, or any object with optional search label  */
    if( ua === und ) return false;
    if( ua !== und && ua.constructor !== String ) {
        if( lbl === und ) lbl = 'user-agent';
        if( ua.headers !== und ) ua = ua.headers[ lbl ];
        else ua = ua[ lbl ];
    }
    if( rgx === und ) rgx = /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/;
    if( rgx.constructor === String ) rgx = new RegExp( rgx );
    return rgx.test( ua );
}

This Regex came from here... https://gist.github.com/dalethedeveloper/1503252/931cc8b613aaa930ef92a4027916e6687d07feac

The 98% Solution. I don't know if it checks tablets like my function title implies.

Really the title of this function (and some arguments) should be rename maybe?... serachObjectForLabelThatMatchesThisRegex

except all the defaults make it a single argument purposed thing.

Also I leave the function set as a key's value, which you can store however you prefer like... just promise me no var or const if you use it.

let mobTabCheck = function() {};
Master James
  • 1,691
  • 15
  • 19
0

for server detection of the device, browser, os. I recommend https://www.npmjs.com/package/node-device-detector

there is support for clienthints.