├── README.md ├── bot-detector.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # Javascript BotDetector 2 | An easy way to check if users visiting your websites are bots or not. 3 | 4 | If you are selling products online or you just want to check if your visitors are real persons, you can act many strategies to do that. 5 | User-Agent can be used most of time to detect bot engine but what you can do to detect real users interacting with your pages? 6 | 7 | This project aims to be a tool that can help you doing that checking many scenarios actually allowed over internet: 8 | - scroll and mouse movement (for desktop) 9 | - gesture and device sensors recognizement (for mobile) 10 | 11 | ## How to 12 | Download and put `bot-detector.js` into your project js folder. 13 | After you have to include it in your page: 14 | ```html 15 | 16 | ```` 17 | 18 | 19 | Now you can instantiate new `BotDetector` class and wait for the result event. 20 | ```javascript 21 | 35 | ``` 36 | Your `callback` method will be called when detection process is completed and will returns a property, `isBot` containing response 37 | to your question: is, my visitor, a bot? 38 | -------------------------------------------------------------------------------- /bot-detector.js: -------------------------------------------------------------------------------- 1 | function BotDetector(args) { 2 | var self = this; 3 | self.isBot = false; 4 | self.tests = {}; 5 | 6 | var selectedTests = args.tests || []; 7 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SCROLL) != -1) { 8 | self.tests[BotDetector.Tests.SCROLL] = function() { 9 | var e = function() { 10 | self.tests[BotDetector.Tests.SCROLL] = true; 11 | self.update() 12 | self.unbindEvent(window, BotDetector.Tests.SCROLL, e) 13 | self.unbindEvent(document, BotDetector.Tests.SCROLL, e) 14 | }; 15 | self.bindEvent(window, BotDetector.Tests.SCROLL, e); 16 | self.bindEvent(document, BotDetector.Tests.SCROLL, e); 17 | }; 18 | } 19 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.MOUSE) != -1) { 20 | self.tests[BotDetector.Tests.MOUSE] = function() { 21 | var e = function() { 22 | self.tests[BotDetector.Tests.MOUSE] = true; 23 | self.update(); 24 | self.unbindEvent(window, BotDetector.Tests.MOUSE, e); 25 | } 26 | self.bindEvent(window, BotDetector.Tests.MOUSE, e); 27 | }; 28 | } 29 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.KEYUP) != -1) { 30 | self.tests[BotDetector.Tests.KEYUP] = function() { 31 | var e = function() { 32 | self.tests[BotDetector.Tests.KEYUP] = true; 33 | self.update(); 34 | self.unbindEvent(window, BotDetector.Tests.KEYUP, e); 35 | } 36 | self.bindEvent(window, BotDetector.Tests.KEYUP, e); 37 | }; 38 | } 39 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SWIPE) != -1) { 40 | self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = function() { 41 | var e = function() { 42 | self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = true; 43 | self.update(); 44 | self.unbindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); 45 | } 46 | self.bindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); 47 | } 48 | } 49 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_MOTION) != -1) { 50 | self.tests[BotDetector.Tests.DEVICE_MOTION] = function() { 51 | var e = function(event) { 52 | if(event.rotationRate.alpha || event.rotationRate.beta || event.rotationRate.gamma) { 53 | var userAgent = navigator.userAgent.toLowerCase(); 54 | var isAndroid = userAgent.indexOf('android') != -1; 55 | var beta = isAndroid ? event.rotationRate.beta : Math.round(event.rotationRate.beta / 10) * 10; 56 | var gamma = isAndroid ? event.rotationRate.gamma : Math.round(event.rotationRate.gamma / 10) * 10; 57 | if (!self.lastRotationData) { 58 | self.lastRotationData = { 59 | beta: beta, 60 | gamma: gamma 61 | }; 62 | } 63 | else { 64 | var movement = beta != self.lastRotationData.beta || gamma != self.lastRotationData.gamma; 65 | if (isAndroid) { 66 | movement = movement && (beta > 0.2 || gamma > 0.2); 67 | } 68 | var args = { beta: beta, gamma: gamma } 69 | self.tests[BotDetector.Tests.DEVICE_MOTION] = movement; 70 | self.update(); 71 | if (movement) { 72 | self.unbindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); 73 | } 74 | } 75 | } 76 | else { 77 | self.tests[BotDetector.Tests.DEVICE_MOTION] = false; 78 | } 79 | 80 | } 81 | self.bindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); 82 | } 83 | } 84 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION) != -1) { 85 | self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = function() { 86 | var e = function() { 87 | self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = true; 88 | self.update(); 89 | self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION, e); 90 | } 91 | self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION); 92 | } 93 | } 94 | if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION_MOZ) != -1) { 95 | self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = function() { 96 | var e = function() { 97 | self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = true; 98 | self.update(); 99 | self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); 100 | } 101 | self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); 102 | } 103 | } 104 | 105 | 106 | self.cases = {}; 107 | self.timeout = args.timeout || 1000; 108 | self.callback = args.callback || null; 109 | self.detected = false; 110 | } 111 | 112 | BotDetector.Tests = { 113 | KEYUP: 'keyup', 114 | MOUSE: 'mousemove', 115 | SWIPE: 'swipe', 116 | SWIPE_TOUCHSTART: 'touchstart', 117 | SWIPE_TOUCHMOVE: 'touchmove', 118 | SWIPE_TOUCHEND: 'touchend', 119 | SCROLL: 'scroll', 120 | GESTURE: 'gesture', 121 | GYROSCOPE: 'gyroscope', 122 | DEVICE_MOTION: 'devicemotion', 123 | DEVICE_ORIENTATION: 'deviceorientation', 124 | DEVICE_ORIENTATION_MOZ: 'MozOrientation' 125 | }; 126 | BotDetector.prototype.update = function(notify) { 127 | var self = this; 128 | var count = 0; 129 | var tests = 0; 130 | for(var i in self.tests) { 131 | if (self.tests.hasOwnProperty(i)) { 132 | self.cases[i] = self.tests[i] === true; 133 | if (self.cases[i] === true) { 134 | count++; 135 | } 136 | } 137 | tests++; 138 | } 139 | self.isBot = count == 0; 140 | self.allMatched = count == tests; 141 | if (notify !== false) { 142 | self.callback(self); 143 | } 144 | } 145 | 146 | BotDetector.prototype.bindEvent = function(e, type, handler) { 147 | if (e.addEventListener) { 148 | e.addEventListener(type, handler, false); 149 | } 150 | else if(e.attachEvent) { 151 | e.attachEvent("on" + type, handler); 152 | } 153 | }; 154 | 155 | BotDetector.prototype.unbindEvent = function(e, type, handle) { 156 | if (e.removeEventListener) { 157 | e.removeEventListener(type, handle, false); 158 | } 159 | else { 160 | var evtName = "on" + type; 161 | if (e.detachEvent) { 162 | if (typeof e[evtName] === 'undefined') { 163 | e[type] = null 164 | } 165 | e.detachEvent(evtName) 166 | } 167 | } 168 | }; 169 | BotDetector.prototype.monitor = function() { 170 | var self = this; 171 | for(var i in this.tests) { 172 | if (this.tests.hasOwnProperty(i)) { 173 | this.tests[i].call(); 174 | } 175 | } 176 | this.update(false); 177 | setTimeout(function() { 178 | self.update(true); 179 | }, self.timeout); 180 | }; 181 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | JS Bot Detector 4 | 5 | 6 | 7 | 8 | 25 | 26 | 27 |
28 |

JS Bot Detector

29 |
30 |
31 |

Are you a bot?

32 |

I'm checking...

33 |
    34 |
35 |
36 |
37 |
38 | 39 | --------------------------------------------------------------------------------