diff --git a/CHANGELOG.md b/CHANGELOG.md index e56ee43..84bcaf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,33 +2,19 @@ # Version 2.0 - What's breaking: - - Dual-licensed under AGPL v3 or Commercial License + - Dual-licensed under AGPLv3 or PRO License - Browser detection on mobile device: `"Chrome" => "Mobile Chrome"`, `"Firefox" => "Mobile Firefox"` - OS detection: `"Mac OS" => "macOS"`, `"Chromium OS" => "Chrome OS"` - What's new: - - Add some new methods in result object: - - Add support for client hints: `withClientHints()` - - Add support for feature detection: `withFeatureCheck()` + - Some new methods in result object: + - Support for client hints: `withClientHints()` + - Support for feature detection: `withFeatureCheck()` - Utility for easy comparison: `is()` - Utility to print full-name: `toString()` - - Add support for ES module `import { UAParser } from 'ua-parser-js'` - - Provide Enums `'ua-parser-js/enums'` - - Provide Extensions `'ua-parser-js/extensions'` - - Provide Helpers `'ua-parser-js/helpers'` - -## Version 2.0.0-alpha.3 -- Add `withFeatureCheck()` method -- Add `isFrozenUA()` method in `helpers` submodule -- Add `MediaPlayers` & `Modules` in `extensions` submodule -- Fix issue with ESM import - -## Version 2.0.0-alpha.2 -- Fix browser result always returning Chromium when using `withClientHints()` -- Fix infinite-loop when await-ing `withClientHints()` in non-client-hints browser - -## Version 2.0.0-alpha.1 -- Initial work on new major version - + - Support for ES module `import { UAParser } from 'ua-parser-js'` + - Provided Enums submodule `'ua-parser-js/enums'` + - Provided Extensions submodule `'ua-parser-js/extensions'` + - Provided Helpers submodule `'ua-parser-js/helpers'` # Version 0.7 / 1.0 diff --git a/README.md b/README.md index d24cb53..039902b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

@@ -15,622 +15,40 @@ # 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 -
- ---- +The most comprehensive, compact, & up-to-date JavaScript library to detect +user's Browser, Engine, OS, CPU, and Device type/model. Runs either in browser +(client-side) or node.js (server-side). # Version 2.0 -What's new & breaking, please read [CHANGELOG](CHANGELOG.md) before upgrading. +Before upgrading from `v0.7` / `v1.0`, please read [CHANGELOG](CHANGELOG.md) to +see what's new & breaking. # 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); -``` + * v1.0: https://github.com/faisalman/ua-parser-js/tree/1.0.35#documentation + * v2.0: https://docs.uaparser.js.org/v2 # Development -## Backers & Sponsors - - - - - - ## Contributors +Large or small, your contribution is valuable here. Please read [CONTRIBUTING](CONTRIBUTING.md) +guide first for the instruction details. + Made with [contributors-img](https://contrib.rocks). -## How To Contribute +## Backers & Sponsors -* 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 +AGPLv3 License Copyright (c) 2012-2023 Faisal Salman <>