# UAParser.js JavaScript library to detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client-Hints data that can be used either in browser (client-side) or node.js (server-side). * Author : Faisal Salman <> * Demo : https://uaparser.js.org * Source : https://github.com/faisalman/ua-parser-js * Documentation : * v1 : https://github.com/faisalman/ua-parser-js/tree/1.0.35#documentation * v2 : https://docs.uaparser.js.org/v2 *** ### From Our Sponsors:
↗ Become a sponsor
--- # Version 2.0 What's new & breaking, please read [CHANGELOG](CHANGELOG.md) before upgrading. # Documentation ### `UAParser([user-agent:string][,extensions:object][,headers:object(since@2.0)]):IData` In browser environment you don't need to pass the user-agent string to the function, as it should automatically get the string from the `window.navigator.userAgent`. Whereas in nodejs environment, the user-agent string must be passed in order for the function to work (usually you can find the user-agent in: `request.headers["user-agent"]`). ## Constructor #### * `new UAParser([user-agent:string][,extensions:object][,headers:object(since@2.0)]):UAParser` When you call `UAParser` with the `new` keyword, `UAParser` will return a new instance with an empty result object, you have to call one of the available methods to get the information from the user-agent string. Like so: ```js let parser = new UAParser("your user-agent here"); // you need to pass the user-agent for nodejs console.log(parser); // {} let parserResults = parser.getResult(); console.log(parserResults); /* { ua : "", browser : {}, engine : {}, os : {}, device : {}, cpu : {} } */ ``` #### * `UAParser([user-agent:string][,extensions:object][,headers:object(since@2.0)]):IData` When you call `UAParser` without the `new` keyword, it will automatically call `getResult()` function and return the parsed results. ```sh returns result object `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} }` ``` ## `UAParser`: #### Methods table The methods are self explanatory, here's a small overview on all the available methods: * `getResult()` - returns all function object calls, user-agent string, browser info, cpu, device, engine, os: `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} }`. * `getBrowser()` - returns the browser name and version. * `getDevice()` - returns the device model, type, vendor. * `getEngine()` - returns the current browser engine name and version. * `getOS()` - returns the running operating system name and version. * `getCPU()` - returns CPU architectural design name. * `getUA()` - returns the user-agent string. * `setUA(ua)` - set a custom user-agent to be parsed. --- #### * `getResult():IData` ```sh returns `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} }` ``` #### * `getBrowser():IData` ```sh returns `{ name: '', version: '' }` # Possible 'browser.name': 2345Explorer, 360 Browser, Amaya, Android Browser, Arora, Avant, Avast, AVG, BIDUBrowser, Baidu, Basilisk, Blazer, Bolt, Brave, Bowser, Camino, Chimera, [Mobile] Chrome [Headless/WebView], Chromium, Cobalt, Comodo Dragon, Dillo, Dolphin, Doris, DuckDuckGo, Edge, Electron, Epiphany, Facebook, Falkon, Fennec, Firebird, [Mobile] Firefox [Focus/Reality], Flock, Flow, GSA, GoBrowser, HeyTap, Huawei Browser, ICE Browser, IE, IEMobile, IceApe, IceCat, IceDragon, Iceweasel, Instagram, Iridium, Iron, Jasmine, Kakao[Story/Talk], K-Meleon, Kindle, Klar, Konqueror, LBBROWSER, Line, LinkedIn, Links, Lunascape, Lynx, MIUI Browser, Maemo Browser, Maemo, Maxthon, MetaSr Midori, Minimo, Mosaic, Mozilla, NetFront, NetSurf, Netfront, Netscape, NokiaBrowser, Obigo, Oculus Browser, OmniWeb, Opera Coast, Opera [Mini/Mobi/Tablet], PaleMoon, PhantomJS, Phoenix, Polaris, Puffin, QQ, QQBrowser, QQBrowserLite, Quark, QupZilla, RockMelt, [Mobile] Safari, Sailfish Browser, Samsung Browser, SeaMonkey, Silk, Skyfire, Sleipnir, Slim, SlimBrowser, Snapchat, Swiftfox, Tesla, TikTok, Tizen Browser, UCBrowser, UP.Browser, Viera, Vivaldi, Waterfox, WeChat, Weibo, Yandex, baidu, iCab, w3m, Whale Browser, ... # 'browser.version' determined dynamically ``` #### * `getDevice():IData` ```sh returns `{ model: '', type: '', vendor: '' }` # Possible 'device.type': console, mobile, tablet, smarttv, wearable, embedded ########## # NOTE: 'desktop' is not a possible device type. # UAParser only reports info directly available from the UA string, which is not the case for 'desktop' device type. # If you wish to detect desktop devices, you must handle the needed logic yourself. # You can read more about it in this issue: https://github.com/faisalman/ua-parser-js/issues/182 ########## # Possible 'device.vendor': Acer, Alcatel, Amazon, Apple, Archos, ASUS, AT&T, BenQ, BlackBerry, Dell, Essential, Facebook, Fairphone, GeeksPhone, Google, HP, HTC, Huawei, Infinix, Jolla, Kobo, Lenovo, LG, Meizu, Microsoft, Motorola, Nexian, Nintendo, Nokia, Nvidia, OnePlus, OPPO, Ouya, Palm, Panasonic, Pebble, Polytron, Realme, RIM, Roku, Samsung, Sharp, Siemens, Sony[Ericsson], Sprint, Tecno, Tesla, Vivo, Vodafone, Xbox, Xiaomi, Zebra, ZTE, ... # 'device.model' determined dynamically ``` #### * `getEngine():IData` ```sh returns `{ name: '', version: '' }` # Possible 'engine.name' Amaya, Blink, EdgeHTML, Flow, Gecko, Goanna, iCab, KHTML, LibWeb, Links, Lynx, NetFront, NetSurf, Presto, Tasman, Trident, w3m, WebKit # 'engine.version' determined dynamically ``` #### * `getOS():IData` ```sh returns `{ name: '', version: '' }` # Possible 'os.name' AIX, Amiga OS, Android[-x86], Arch, Bada, BeOS, BlackBerry, CentOS, Chromium OS, Contiki, Fedora, Firefox OS, FreeBSD, Debian, Deepin, DragonFly, elementary OS, Fuchsia, Gentoo, GhostBSD, GNU, Haiku, HarmonyOS, HP-UX, Hurd, iOS, Joli, KaiOS, Linpus, Linspire,Linux, Mac OS, Maemo, Mageia, Mandriva, Manjaro, MeeGo, Minix, Mint, Morph OS, NetBSD, NetRange, NetTV, Nintendo, OpenBSD, OpenVMS, OS/2, Palm, PC-BSD, PCLinuxOS, Plan9, PlayStation, QNX, Raspbian, RedHat, RIM Tablet OS, RISC OS, Sabayon, Sailfish, SerenityOS, Series40, Slackware, Solaris, SUSE, Symbian, Tizen, Ubuntu, Unix, VectorLinux, Viera, watchOS, WebOS, Windows [Phone/Mobile], Zenwalk, ... # 'os.version' determined dynamically ``` #### * `getCPU():IData` ```sh returns `{ architecture: '' }` # Possible 'cpu.architecture' 68k, amd64, arm[64/hf], avr, ia[32/64], irix[64], mips[64], pa-risc, ppc, sparc[64] ``` #### * `getUA():string` ```sh returns user-agent string of current instance ``` #### * `setUA(ua:string):UAParser` ```sh set user-agent string to be parsed returns current instance ``` --- ## `IData`: `since@2.0` #### Methods table The methods are self explanatory, here's a small overview on all the available methods: * `is(value)` - returns `true` if the passed value matches a value of current object, `false` otherwise * `toString()` - returns the full-name values of current object as a string * `withClientHints()` - returns an object with re-updated data from client hints * `withFeatureCheck()` - returns an object with re-updated data from feature detection --- #### * `is(value:string):boolean` ```js // Is just a shorthand comparison to check whether the value of specified item equals one of its properties (in a case-insensitive way) // so that instead of write it using `==` operator like this: let ua = UAParser(); let device = ua.device; let os = ua.os; if (device.type == "mobile" && os.name != "iOS") {} if (device.type == "smarttv" || device.vendor == "Samsung") {} // we can also write the comparison above into as follow: if (device.is("mobile") && !os.is("iOS")) {} if (device.is("SmartTV") || device.is("SaMsUnG")) {} /* For device, properties will be checked in this particular order: type, model, vendor */ // Another examples: let uap = new UAParser('Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 635) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537'); uap.getBrowser().name; // "IEMobile" uap.getBrowser().is("IEMobile"); // true uap.getCPU().is("ARM"); // true uap.getOS().name; // "Windows Phone" uap.getOS().is("Windows Phone"); // true uap.getDevice(); // { vendor: "Nokia", model: "Lumia 635", type: "mobile" } uap.getResult().device; // { vendor: "Nokia", model: "Lumia 635", type: "mobile" } let device = uap.getDevice(); device.is("mobile"); // true device.is("Lumia 635"); // true device.is("Nokia"); // true device.is("iPhone"); // false uap.getResult().device.is("Nokia"); // true uap.getResult().device.model; // "Lumia 635" uap.setUA("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"); let browser = uap.getBrowser(); browser.is("IEMobile"); // false browser.is("Chrome"); // true uap.getResult().browser.is("Edge"); // false uap.getResult().os.name // "Mac OS" uap.getResult().os.is("Mac OS"); // true uap.getResult().os.version; // "10.6.8" let engine = uap.getEngine(); engine.is("Blink"); // true ``` #### * `toString():string` ```js // Retrieve full-name values as a string /* Values will be concatenated following this pattern: * browser : name + version * cpu : architecture * device : vendor + model * engine : name + version * os : name + version */ // Usage examples let uap = new UAParser('Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 635) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537'); uap.getDevice(); // { // vendor: "Nokia", // model: "Lumia 635", // type: "mobile" // } uap.getDevice().toString(); // "Nokia Lumia 635" uap.getResult().os.name; // "Windows Phone" uap.getResult().os.version; // "8.1" uap.getResult().os.toString(); // "Windows Phone 8.1" uap.setUA("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"); uap.getBrowser().name; // "Chrome" uap.getBrowser().version; // "28.0.1500.95" uap.getBrowser().major; // "28" uap.getBrowser().toString(); // "Chrome 28.0.1500.95" let engine = uap.getEngine(); engine.name; // "Blink" engine.version; // "28.0.1500.95" engine.toString(); // "Blink 28.0.1500.95" ``` #### * `withClientHints():Promise|Thenable|IData` Recently, Chrome limits the information exposed through user-agent and introduces a new experimental set of data called "client-hints". In browser-environment, obtaining the client-hints data via JavaScript must be done in an asynchronous way. In `UAParser` you can chain the result object from `get*` method with `withClientHints()` to also read the client-hints data from the browser and return the updated data as a `Promise`. ```js // client-side example (async function () { let ua = new UAParser(); // get browser data from user-agent only : let browser = ua.getBrowser(); console.log('Using User-Agent: ', browser); // get browser data from client-hints (with user-agent as fallback) : browser = await ua.getBrowser().withClientHints(); console.log('Using Client-Hints: ', browser); // alternatively : ua.getBrowser().withClientHints().then(function (browser) { console.log('Using Client-Hints: ', browser); }); })(); ``` Along with `User-Agent` HTTP header, Chrome also sends this client-hints data by default under `Sec-CH-UA-*` HTTP headers in each request. In server-side development, you can capture this extra information by passing the `req.headers` to `UAParser()` (see examples below). When using `withClientHints()` in nodejs environment and browser without client-hints support (basically anything that's not Chromium-based), it will returns a new object with updated data. ```js // server-side example // Suppose we got a request having these HTTP headers: const request = { headers : { 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36', 'sec-ch-ua-mobile' : '?1', 'sec-ch-ua-model' : 'Galaxy S3 Marketing', 'sec-ch-ua-platform' : 'Android' } }; const result1 = UAParser(request.headers); // parse only "user-agent" header const result2 = UAParser(request.headers).withClientHints(); // update with "sec-ch-ua" headers console.log(result1.os.name); // "Linux" console.log(result1.device.type); // undefined console.log(result1.device.model); // undefined console.log(result2.os.name); // "Android" console.log(result2.device.type); // "mobile" console.log(result2.device.model); // "Galaxy S3 Marketing" new UAParser(request.headers) .getBrowser() .withClientHints() .then((browser) => { console.log(browser.toString()); // Chrome 110.0.0.0 }); ``` #### * `withFeatureCheck():IData` This method allows us to examine other features beyond `navigator.userAgent` to further improve detection of the following: - browser : Brave (check for `navigator.isBrave`) - device : iPad (check for `navigator.standalone` & `navigator.maxTouchPoints`) ```js // suppose this code runs on iPad const withoutFeatureCheck = UAParser(); const withFeatureCheck = UAParser().withFeatureCheck(); console.log(withoutFeatureCheck.device); // { vendor : "Apple", model : "Macintosh", type : undefined } console.log(withFeatureCheck.device); // { vendor : "Apple", model : "iPad", type : "tablet" } ``` ## Extending Regex If you want to detect something that's not currently provided by UAParser.js (eg: `bots`, specific apps, etc), you can pass a list of regexes to extend internal UAParser.js regexes with your own. * `UAParser([uastring,] extensions [,headers:object(since@2.0)])` ```js // Example: const myOwnListOfBrowsers = [ [/(mybrowser)\/([\w\.]+)/i], [UAParser.BROWSER.NAME, UAParser.BROWSER.VERSION, ['type', 'bot']] ]; const myUA = 'Mozilla/5.0 MyBrowser/1.3'; let myParser = new UAParser({ browser: myOwnListOfBrowsers }); console.log(myParser.setUA(myUA).getBrowser()); // {name: "MyBrowser", version: "1.3", major: "1", type : "bot"} console.log(myParser.getBrowser().is('bot')); // true // Another example: const myOwnListOfDevices = [ [/(mytab) ([\w ]+)/i], [UAParser.DEVICE.VENDOR, UAParser.DEVICE.MODEL, [UAParser.DEVICE.TYPE, UAParser.DEVICE.TABLET]], [/(myphone)/i], [UAParser.DEVICE.VENDOR, [UAParser.DEVICE.TYPE, UAParser.DEVICE.MOBILE]] ]; const myUA2 = 'Mozilla/5.0 MyTab 14 Pro Max'; let myParser2 = new UAParser({ browser: myOwnListOfBrowsers, device: myOwnListOfDevices }); console.log(myParser2.setUA(myUA2).getDevice()); // {vendor: "MyTab", model: "14 Pro Max", type: "tablet"} ``` Some basic extensions (although not very complete at the moment) can also be found under `ua-parser-js/extensions` submodule. ```js import { UAParser } from 'ua-parser-js'; import { Emails } from 'ua-parser-js/extensions'; const browser = new UAParser(Emails) .setUA('Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0') .getBrowser(); console.log(browser.name); // Thunderbird ``` # Usage ## Using HTML ```html ``` ## Using node.js Note: Device information is not available in the NodeJS environment. ```sh $ npm install ua-parser-js ``` ```js var http = require('http'); var uap = require('ua-parser-js'); http.createServer(function (req, res) { // get user-agent header var ua = uap(req.headers['user-agent']); /* // BEGIN since@2.0 - you can also pass client-hints data to UAParser // note: only works in secure context (https:// or localhost or file://) var getHighEntropyValues = 'Sec-CH-UA-Full-Version-List, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch, Sec-CH-UA-Bitness'; res.setHeader('Accept-CH', getHighEntropyValues); res.setHeader('Critical-CH', getHighEntropyValues); var ua = uap(req.headers).withClientHints(); // END since@2.0 */ // write the result as response res.end(JSON.stringify(ua, null, ' ')); }) .listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/'); ``` ## Using ES Modules ```js import { UAParser } from 'ua-parser-js'; const { browser, cpu, device } = UAParser('Mozilla/5.0 (X11; U; Linux armv7l; en-GB; rv:1.9.2a1pre) Gecko/20090928 Firefox/3.5 Maemo Browser 1.4.1.22 RX-51 N900'); console.log(browser.name); // Maemo Browser console.log(cpu.is('arm')); // true console.log(device.is('mobile')); // true console.log(device.model); // N900 ``` ## Using TypeScript ```sh $ npm install --save @types/ua-parser-js # Download TS type definition from DefinitelyTyped repository: # https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/ua-parser-js ``` ## Using jQuery/Zepto ($.ua) Although written in vanilla js, this library will automatically detect if jQuery/Zepto is present and create `$.ua` object (with values based on its User-Agent) along with `window.UAParser` constructor. To get/set user-agent you can use: `$.ua.get()` / `$.ua.set(uastring)`. ```js // Say we are in a browser with default user-agent: 'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Sprint APA7373KT Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0': // Get the details console.log($.ua.device); // {vendor: "HTC", model: "Evo Shift 4G", type: "mobile"} console.log($.ua.os); // {name: "Android", version: "2.3.4"} console.log($.ua.os.name); // "Android" console.log($.ua.get()); // "Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Sprint APA7373KT Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0" // Now lets try to reset to another custom user-agent $.ua.set('Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; Xoom Build/HWI69) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13'); // Test again console.log($.ua.browser.name); // "Safari" console.log($.ua.engine.name); // "Webkit" console.log($.ua.device); // {vendor: "Motorola", model: "Xoom", type: "tablet"} console.log(parseInt($.ua.browser.version.split('.')[0], 10)); // 4 // Add class to tag // $('body').addClass('ua-browser-' + $.ua.browser.name + ' ua-devicetype-' + $.ua.device.type); ``` # Development ## Backers & Sponsors ## Contributors Made with [contributors-img](https://contrib.rocks). ## How To Contribute * Fork and clone this repository * Make some changes as required * Write unit test to showcase its functionality * Run the test suites to make sure it's not breaking anything `$ npm test` * Submit a pull request under `develop` branch # License AGPL v3 License Copyright (c) 2012-2023 Faisal Salman <> This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.