├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .prettierrc.json ├── .tonic.example.js ├── .travis.yml ├── CHANGELOG.md ├── LICENSE-MIT ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── scripts └── create-data.js ├── test.js └── useragent-data.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | commonjs: true, 5 | es2020: true, 6 | node: true, 7 | }, 8 | extends: 'eslint:recommended', 9 | parserOptions: { 10 | ecmaVersion: 11, 11 | }, 12 | rules: { 13 | 'prefer-const': 'error', 14 | 'no-var': 'error', 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _ignore/ 2 | .nyc_output/ 3 | coverage/ 4 | node_modules/ 5 | .DS_Store 6 | .npm-debug.log 7 | .project 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | _ignore/ 3 | .DS_Store 4 | .gitignore 5 | .npm-debug.log 6 | .project 7 | .travis.yml 8 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.tonic.example.js: -------------------------------------------------------------------------------- 1 | const randomUseragent = require('random-useragent'); 2 | const ua = randomUseragent.getRandom(); // gets a random user agent string 3 | const data = randomUseragent.getRandomData(); // gets random user agent data 4 | console.log('Random useragent:', ua); 5 | console.log('Random useragent data:', data); 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'stable' 4 | - '14' 5 | - '12' 6 | - '10' 7 | script: 8 | - npm run cover 9 | - npm run coveralls 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased](https://github.com/skratchdot/random-useragent/tree/HEAD) 4 | 5 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.5.0...HEAD) 6 | 7 | **Merged pull requests:** 8 | 9 | - Update README.md: remove david-dm, update example link [\#25](https://github.com/skratchdot/random-useragent/pull/25) ([DavideViolante](https://github.com/DavideViolante)) 10 | - Add missing 0.5.0 to CHANGELOG.md [\#24](https://github.com/skratchdot/random-useragent/pull/24) ([DavideViolante](https://github.com/DavideViolante)) 11 | 12 | ## [0.5.0](https://github.com/skratchdot/random-useragent/tree/0.5.0) (2020-09-03) 13 | 14 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.4.0...0.5.0) 15 | 16 | **Closed issues:** 17 | 18 | - it's too old to use it :\( [\#8](https://github.com/skratchdot/random-useragent/issues/8) 19 | 20 | **Merged pull requests:** 21 | 22 | - Replace var with let or const [\#11](https://github.com/skratchdot/random-useragent/pull/11) ([DavideViolante](https://github.com/DavideViolante)) 23 | 24 | ## [0.4.0](https://github.com/skratchdot/random-useragent/tree/0.4.0) (2020-08-07) 25 | 26 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.3.1...0.4.0) 27 | 28 | ## [0.3.1](https://github.com/skratchdot/random-useragent/tree/0.3.1) (2016-10-15) 29 | 30 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.3.0...0.3.1) 31 | 32 | **Closed issues:** 33 | 34 | - UA mobile [\#4](https://github.com/skratchdot/random-useragent/issues/4) 35 | 36 | ## [0.3.0](https://github.com/skratchdot/random-useragent/tree/0.3.0) (2016-04-18) 37 | 38 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.2.1...0.3.0) 39 | 40 | **Merged pull requests:** 41 | 42 | - Better performance [\#2](https://github.com/skratchdot/random-useragent/pull/2) ([MrVoltz](https://github.com/MrVoltz)) 43 | 44 | ## [0.2.1](https://github.com/skratchdot/random-useragent/tree/0.2.1) (2015-11-30) 45 | 46 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.2.0...0.2.1) 47 | 48 | ## [0.2.0](https://github.com/skratchdot/random-useragent/tree/0.2.0) (2015-11-30) 49 | 50 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.1.2...0.2.0) 51 | 52 | ## [0.1.2](https://github.com/skratchdot/random-useragent/tree/0.1.2) (2015-04-24) 53 | 54 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.1.1...0.1.2) 55 | 56 | ## [0.1.1](https://github.com/skratchdot/random-useragent/tree/0.1.1) (2015-04-24) 57 | 58 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/0.1.0...0.1.1) 59 | 60 | **Merged pull requests:** 61 | 62 | - Update the useragent data file [\#1](https://github.com/skratchdot/random-useragent/pull/1) ([athieriot](https://github.com/athieriot)) 63 | 64 | ## [0.1.0](https://github.com/skratchdot/random-useragent/tree/0.1.0) (2014-06-04) 65 | 66 | [Full Changelog](https://github.com/skratchdot/random-useragent/compare/62d09593b662966c20acef0e32adaaee00dc1405...0.1.0) 67 | 68 | \* _This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)_ 69 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 skratchdot 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # random-useragent 2 | 3 | [![NPM version](https://badge.fury.io/js/random-useragent.svg)](http://badge.fury.io/js/random-useragent) 4 | [![Build Status](https://travis-ci.org/skratchdot/random-useragent.png?branch=master)](https://travis-ci.org/skratchdot/random-useragent) 5 | [![Code Climate](https://codeclimate.com/github/skratchdot/random-useragent.png)](https://codeclimate.com/github/skratchdot/random-useragent) 6 | [![Coverage Status](https://coveralls.io/repos/skratchdot/random-useragent/badge.svg?branch=master&service=github)](https://coveralls.io/github/skratchdot/random-useragent?branch=master) 7 | 8 | [![NPM](https://nodei.co/npm/random-useragent.png)](https://npmjs.org/package/random-useragent) 9 | 10 | ## Description 11 | 12 | Get a random user agent (with an optional filter to select from a specific set of user agents). 13 | 14 | ## Getting Started 15 | 16 | Install the module with: `npm install random-useragent` 17 | 18 | ```javascript 19 | const randomUseragent = require('random-useragent'); 20 | randomUseragent.getRandom(); // gets a random user agent string 21 | ``` 22 | 23 | - [Live example on NPM Runkit](https://npm.runkit.com/random-useragent) 24 | 25 | ## Documentation 26 | 27 | #### .getRandom(filter) 28 | 29 | Get a random user agent string (optionally using a filter). 30 | 31 | Example Result: 32 | 33 | ```javascript 34 | 'Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0'; 35 | ``` 36 | 37 | #### .getRandomData(filter) 38 | 39 | Get a random user agent's parsed data (optionally using a filter). 40 | 41 | Example Result: 42 | 43 | ```javascript 44 | { 45 | "folder": "/Browsers - Windows/Legacy Browsers", 46 | "description": "Firefox 20.0 (Win 8 32)", 47 | "userAgent": "Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0", 48 | "appCodename": "", 49 | "appName": "", 50 | "appVersion": "", 51 | "platform": "", 52 | "vendor": "", 53 | "vendorSub": "", 54 | "browserName": "Firefox", 55 | "browserMajor": "20", 56 | "browserVersion": "20.0", 57 | "deviceModel": "", 58 | "deviceType": "", 59 | "deviceVendor": "", 60 | "engineName": "Gecko", 61 | "engineVersion": "20.0", 62 | "osName": "Windows", 63 | "osVersion": "8", 64 | "cpuArchitecture": "" 65 | } 66 | ``` 67 | 68 | #### .getAll(filter) 69 | 70 | Get an array of all the user agent strings (optionally using a filter). 71 | 72 | #### .getAllData(filter) 73 | 74 | Get an array of all the parsed user agent data (optionally using a filter). 75 | 76 | ## Examples 77 | 78 | Get a random user agent string: 79 | 80 | ```javascript 81 | randomUseragent.getRandom(); 82 | ``` 83 | 84 | Get a random Firefox user agent string: 85 | 86 | ```javascript 87 | randomUseragent.getRandom(function (ua) { 88 | return ua.browserName === 'Firefox'; 89 | }); 90 | ``` 91 | 92 | Get a random user agent with a version >= 20: 93 | 94 | ```javascript 95 | randomUseragent.getRandom(function (ua) { 96 | return parseFloat(ua.browserVersion) >= 20; 97 | }); 98 | ``` 99 | 100 | ## Source Of User Agents 101 | 102 | The collection of user agents is pulled from the large, regularly updated xml file 103 | provided by the author of [User Agent Switcher](http://chrispederick.com/work/user-agent-switcher/), 104 | which is located here: 105 | 106 | - [Forum Post](http://techpatterns.com/forums/about304.html) 107 | - [Direct Link](http://techpatterns.com/downloads/firefox/useragentswitcher.xml) 108 | 109 | ## Links 110 | 111 | - [Source Code](https://github.com/skratchdot/random-useragent) 112 | - [Changelog](https://github.com/skratchdot/random-useragent/blob/master/CHANGELOG.md) 113 | - [Live example on Tonic](https://tonicdev.com/npm/random-useragent) 114 | 115 | ## License 116 | 117 | Copyright (c) 2014 skratchdot 118 | Licensed under the MIT license. 119 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * random-useragent 3 | * https://github.com/skratchdot/random-useragent 4 | * 5 | * Copyright (c) 2014 skratchdot 6 | * Licensed under the MIT license. 7 | */ 8 | 'use strict'; 9 | 10 | const useragents = require('./useragent-data.json'); 11 | const rand = require('random-seed').create(); 12 | 13 | // cloning is slow, but it's only done when returning parsed user agent 14 | // objects (so the data can't be changed by the end user). 15 | // this can be a performance hit when in a loop, so use with caution. 16 | const cloneData = function (data) { 17 | return JSON.parse(JSON.stringify(data)); 18 | }; 19 | 20 | const getData = function (filter) { 21 | return typeof filter === 'function' ? useragents.filter(filter) : useragents; 22 | }; 23 | 24 | exports.getRandom = function (filter) { 25 | const data = getData(filter); 26 | return data.length 27 | ? data[rand.intBetween(0, data.length - 1)].userAgent 28 | : null; 29 | }; 30 | 31 | exports.getRandomData = function (filter) { 32 | const data = getData(filter); 33 | return data.length 34 | ? cloneData(data[rand.intBetween(0, data.length - 1)]) 35 | : null; 36 | }; 37 | 38 | exports.getAll = function (filter) { 39 | return getData(filter).map(function (item) { 40 | return item.userAgent; 41 | }); 42 | }; 43 | 44 | exports.getAllData = function (filter) { 45 | return cloneData(getData(filter)); 46 | }; 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "random-useragent", 3 | "version": "0.5.0", 4 | "description": "Get a random useragent (with an optional filter)", 5 | "main": "index.js", 6 | "scripts": { 7 | "changelog": "github_changelog_generator --user skratchdot --project random-useragent && npm run format", 8 | "clean": "rimraf .nyc_output/ coverage/", 9 | "cover": "nyc npm test", 10 | "coveralls": "cat coverage/lcov.info | coveralls --verbose", 11 | "data": "./scripts/create-data.js && npm run format", 12 | "format": "prettier --check --write .", 13 | "lint": "eslint *.js scripts/*.js", 14 | "prepublish": "npm-run-all format lint test", 15 | "test": "mocha test.js", 16 | "watch": "npm-run-all clean --parallel watch:test watch:lint", 17 | "watch:lint": "sane 'npm run lint' .", 18 | "watch:test": "npm run test -- -w" 19 | }, 20 | "author": "skratchdot", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/skratchdot/random-useragent/issues" 24 | }, 25 | "homepage": "https://github.com/skratchdot/random-useragent", 26 | "repository": { 27 | "type": "git", 28 | "url": "git://github.com/skratchdot/random-useragent.git" 29 | }, 30 | "dependencies": { 31 | "random-seed": "^0.3.0" 32 | }, 33 | "devDependencies": { 34 | "chai": "^4.3.6", 35 | "coveralls": "^3.1.1", 36 | "eslint": "^8.25.0", 37 | "mocha": "^10.0.0", 38 | "npm-run-all": "^4.1.5", 39 | "nyc": "^15.1.0", 40 | "prettier": "^2.7.1", 41 | "request": "^2.88.2", 42 | "rimraf": "^3.0.2", 43 | "sane": "^5.0.1", 44 | "ua-parser-js": "^1.0.2", 45 | "xml2js": "^0.4.23" 46 | }, 47 | "tonicExampleFilename": ".tonic.example.js", 48 | "nyc": { 49 | "all": true, 50 | "include": [ 51 | "index.js" 52 | ], 53 | "reporter": [ 54 | "text", 55 | "html", 56 | "lcovonly" 57 | ] 58 | }, 59 | "keywords": [ 60 | "random", 61 | "useragent", 62 | "user-agent", 63 | "user", 64 | "agent", 65 | "data", 66 | "web", 67 | "developer" 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /scripts/create-data.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * random-useragent 4 | * https://github.com/skratchdot/random-useragent 5 | * 6 | * Copyright (c) 2014 skratchdot 7 | * Licensed under the MIT license. 8 | */ 9 | /*eslint prefer-template:0, no-console:0 */ 10 | 'use strict'; 11 | 12 | // config 13 | const xmlUrl = 14 | 'http://techpatterns.com/downloads/firefox/useragentswitcher.xml'; 15 | const file = __dirname + '/../useragent-data.json'; 16 | 17 | // requires 18 | const fs = require('fs'); 19 | const request = require('request'); 20 | const xml2js = require('xml2js'); 21 | const UAParser = require('ua-parser-js'); 22 | 23 | // instance 24 | const useragents = []; 25 | const xmlParser = new xml2js.Parser(); 26 | const uaParser = new UAParser(); 27 | 28 | // functions 29 | const parseUseragents = function (folderName, folderItem) { 30 | if (Object.prototype.hasOwnProperty.call(folderItem, 'useragent')) { 31 | folderItem.useragent.forEach(function (useragent) { 32 | useragent = useragent.$; 33 | uaParser.setUA(useragent.useragent); 34 | const parsed = uaParser.getResult(); 35 | if ( 36 | typeof useragent.useragent === 'string' && 37 | useragent.useragent.length > 0 38 | ) { 39 | useragents.push({ 40 | folder: folderName, 41 | description: useragent.description, 42 | userAgent: useragent.useragent, 43 | appCodename: useragent.appcodename, 44 | appName: useragent.appname, 45 | appVersion: useragent.appversion, 46 | platform: useragent.platform, 47 | vendor: useragent.vendor, 48 | vendorSub: useragent.vendorsub, 49 | browserName: parsed.browser.name || '', 50 | browserMajor: parsed.browser.major || '', 51 | browserVersion: parsed.browser.version || '', 52 | deviceModel: parsed.device.model || '', 53 | deviceType: parsed.device.type || '', 54 | deviceVendor: parsed.device.vendor || '', 55 | engineName: parsed.engine.name || '', 56 | engineVersion: parsed.engine.version || '', 57 | osName: parsed.os.name || '', 58 | osVersion: parsed.os.version || '', 59 | cpuArchitecture: parsed.cpu.architecture || '', 60 | }); 61 | } 62 | }); 63 | } 64 | }; 65 | 66 | const parseFolder = function (folderName, folder) { 67 | folder.forEach(function (folderItem) { 68 | const subFolderName = folderName + '/' + folderItem.$.description; 69 | // continue parsing folders 70 | if (Object.prototype.hasOwnProperty.call(folderItem, 'folder')) { 71 | parseFolder(subFolderName, folderItem.folder); 72 | } 73 | // parse any useragents 74 | parseUseragents(subFolderName, folderItem); 75 | }); 76 | }; 77 | 78 | // create file 79 | request(xmlUrl, function (error, response, body) { 80 | xmlParser.parseString(body, function (err, result) { 81 | parseFolder('', result.useragentswitcher.folder); 82 | fs.writeFile(file, JSON.stringify(useragents, null, '\t'), function () { 83 | console.log('Done Writing File.'); 84 | }); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* globals describe, it */ 3 | const expect = require('chai').expect; 4 | const lib = require('./index.js'); 5 | const iterations = 100; 6 | 7 | describe('random-useragent', function () { 8 | it("don't change data", function () { 9 | const key = 'someNewKey'; 10 | const d1 = lib.getAllData(); 11 | d1[0][key] = 'foo'; 12 | const d2 = lib.getAllData(); 13 | expect(Object.prototype.hasOwnProperty.call(d1[0], key)).to.equal(true); 14 | expect(Object.prototype.hasOwnProperty.call(d2[0], key)).to.equal(false); 15 | }); 16 | it('return values', function () { 17 | expect(lib.getRandom()).to.be.a('string'); 18 | expect(lib.getRandomData()).to.be.an('object'); 19 | expect(lib.getAll()).to.be.an('array'); 20 | expect(lib.getAllData()).to.be.an('array'); 21 | }); 22 | it('randomization works', function (done) { 23 | for (let i = 0; i < iterations; i++) { 24 | expect(lib.getRandom()).to.be.a('string'); 25 | expect(lib.getRandomData()).to.be.an('object'); 26 | } 27 | done(); 28 | }); 29 | it('valid filters work', function () { 30 | const filter = function (item) { 31 | return item.browserName === 'Chrome'; 32 | }; 33 | expect(lib.getRandom(filter)).to.be.a('string'); 34 | expect(lib.getRandomData(filter)).to.be.an('object'); 35 | expect(lib.getAll(filter)).to.be.an('array'); 36 | expect(lib.getAllData(filter)).to.be.an('array'); 37 | expect(lib.getAll(filter)).to.have.length.gt(0); 38 | expect(lib.getAllData(filter)).to.have.length.gt(0); 39 | }); 40 | it('invalid filters work', function () { 41 | const filter = function (item) { 42 | return item.browserName === 'Some Fake Browser'; 43 | }; 44 | expect(lib.getRandom(filter)).to.be.null; 45 | expect(lib.getRandomData(filter)).to.be.null; 46 | expect(lib.getAll(filter)).to.be.an('array'); 47 | expect(lib.getAllData(filter)).to.be.an('array'); 48 | expect(lib.getAll(filter)).to.have.length(0); 49 | expect(lib.getAllData(filter)).to.have.length(0); 50 | }); 51 | }); 52 | --------------------------------------------------------------------------------